!/===========================================================================/
! Copyright (c) 2007, The University of Massachusetts Dartmouth 
! Produced at the School of Marine Science & Technology 
! Marine Ecosystem Dynamics Modeling group
! All rights reserved.
!
! FVCOM has been developed by the joint UMASSD-WHOI research team. For 
! details of authorship and attribution of credit please see the FVCOM
! technical manual or contact the MEDM group.
!
! 
! This file is part of FVCOM. For details, see http://fvcom.smast.umassd.edu 
! The full copyright notice is contained in the file COPYRIGHT located in the 
! root directory of the FVCOM code. This original header must be maintained
! in all distributed versions.
!
! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
! AND ANY EXPRESS OR  IMPLIED WARRANTIES, INCLUDING,  BUT NOT  LIMITED TO,
! THE IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS FOR A PARTICULAR
! PURPOSE ARE DISCLAIMED.  
!
!/---------------------------------------------------------------------------/
! CVS VERSION INFORMATION
! $Id$
! $Name$
! $Revision$
!/===========================================================================/
!
MODULE MOD_ASSIM
# if defined (DATA_ASSIM)

  USE MOD_PREC
  USE CONTROL
  USE ALL_VARS
  USE MOD_NCTOOLS
  USE MOD_UTILS
  USE MOD_WD
# if defined (DYE_RELEASE)
  USE MOD_DYE
# endif 
  USE MOD_STARTUP
  USE MOD_INPUT
#  if defined (ENKF)
      USE ENKFVAL,  ONLY : ENKF_NENS
      USE MOD_ENKF,   ONLY : ENKF_memberCONTR
#  endif
#  if defined (SEDIMENT)
      USE MOD_SED
#  endif

  IMPLICIT NONE
  SAVE

   TYPE(NCFILE), POINTER ::NC_RST_ASSIM
   TYPE(NCFILE), POINTER ::NC_TSAVG_ASSIM
   Integer :: Pyear,Pmonth,Pmdays
   !Pmonth : present month
   !Pmdays : total days in present month

  !
  !--Data Assimilation Parameters for SST Assimilation
  !
  LOGICAL  :: SST_ASSIM                    !!TRUE IF SST ASSIMILATION ACTIVE
  CHARACTER(LEN=80) SST_ASSIM_FILE         !!FILE NAME FOR SST DATA
  REAL(SP) :: SST_RADIUS                   !!SEARCH RADIUS FOR INTERPOLATION POINTS
  REAL(SP) :: SST_WEIGHT_MAX                    
  REAL(SP) :: SST_TIMESCALE
  REAL(SP) :: SST_TIME_WINDOW              !!TIME WINDOW FOR OBSERVATION ASSIMILATION (in hours)
  INTEGER  :: SST_N_PER_INTERVAL           !! ASSUMING DAILY DATA:
  !! AVERAGE OVER

  NAMELIST /NML_SST_ASSIMILATION/      &
       & SST_ASSIM,                    &
       & SST_ASSIM_FILE,               &
       & SST_RADIUS,                   &
       & SST_WEIGHT_MAX,               &
       & SST_TIMESCALE,                &
       & SST_TIME_WINDOW,              &
       & SST_N_PER_INTERVAL

  !
  !--Data Assimilation Parameters for SST GRID Assimilation
  !
  LOGICAL  :: SSTGRD_ASSIM                    !!TRUE IF SST ASSIMILATION ACTIVE
! lwang added for SST mld assimilation
  LOGICAL  :: SSTGRD_MLD
! lwang
  CHARACTER(LEN=80) SSTGRD_ASSIM_FILE         !!FILE NAME FOR SST DATA
  REAL(SP) :: SSTGRD_WEIGHT_MAX                    
  REAL(SP) :: SSTGRD_TIMESCALE
  REAL(SP) :: SSTGRD_TIME_WINDOW              !!TIME WINDOW FOR OBSERVATION ASSIMILATION (in hours)
  INTEGER  :: SSTGRD_N_PER_INTERVAL           !! ASSUMING DAILY DATA:
  !! AVERAGE OVER

  NAMELIST /NML_SSTGRD_ASSIMILATION/      &
       & SSTGRD_ASSIM,                    &
! lwang added for SST mld assimilation
       & SSTGRD_MLD,                      &
! lwang
       & SSTGRD_ASSIM_FILE,               &
       & SSTGRD_WEIGHT_MAX,               &
       & SSTGRD_TIMESCALE,                &
       & SSTGRD_TIME_WINDOW,              &
       & SSTGRD_N_PER_INTERVAL

  ! SST ASSIM IS EITHER GRID OR NOT - CAN NOT DO BOTH AT ONCE!


  !
  !--Data Assimilation Parameters for SSS GRID Assimilation
  !
  LOGICAL  :: SSSGRD_ASSIM                    !!TRUE IF SSS ASSIMILATION ACTIVE
! lwang added for SSS mld assimilation
  LOGICAL  :: SSSGRD_MLD
! lwang
  CHARACTER(LEN=80) SSSGRD_ASSIM_FILE         !!FILE NAME FOR SSS DATA
  REAL(SP) :: SSSGRD_WEIGHT_MAX                    
  REAL(SP) :: SSSGRD_TIMESCALE
  REAL(SP) :: SSSGRD_TIME_WINDOW              !!TIME WINDOW FOR OBSERVATION ASSIMILATION (in hours)
  INTEGER  :: SSSGRD_N_PER_INTERVAL           !! ASSUMING DAILY DATA:
  !! AVERAGE OVER

  NAMELIST /NML_SSSGRD_ASSIMILATION/      &
       & SSSGRD_ASSIM,                    &
! lwang added for SSS mld assimilation
!       & SSSGRD_MLD,                      &
! lwang
       & SSSGRD_ASSIM_FILE,               &
       & SSSGRD_WEIGHT_MAX,               &
       & SSSGRD_TIMESCALE,                &
       & SSSGRD_TIME_WINDOW,              &
       & SSSGRD_N_PER_INTERVAL


  !--Data Assimilation Parameters for SSH GRID Assimilation
  !
  LOGICAL  :: SSHGRD_ASSIM                    !!TRUE IF SSH ASSIMILATION ACTIVE
  CHARACTER(LEN=80) SSHGRD_ASSIM_FILE         !!FILE NAME FOR SSH DATA
  REAL(SP) :: SSHGRD_WEIGHT_MAX                    
  REAL(SP) :: SSHGRD_TIMESCALE
  REAL(SP) :: SSHGRD_TIME_WINDOW            !!TIME WINDOW FOR OBSERVATION ASSIMILATION (in hours)
  INTEGER  :: SSHGRD_N_PER_INTERVAL           !! ASSUMING DAILY DATA:
  !! AVERAGE OVER

  NAMELIST /NML_SSHGRD_ASSIMILATION/      &
       & SSHGRD_ASSIM,                    &
       & SSHGRD_ASSIM_FILE,               &
       & SSHGRD_WEIGHT_MAX,               &
       & SSHGRD_TIMESCALE,                &
       & SSHGRD_TIME_WINDOW,              &
       & SSHGRD_N_PER_INTERVAL

  !
  !--Data Assimilation Parameters for Climatological TS GRID Assimilation
  !
  LOGICAL  :: TSGRD_ASSIM                    !!TRUE IF SST ASSIMILATION ACTIVE
  CHARACTER(LEN=80) TSGRD_ASSIM_FILE         !!FILE NAME FOR TS DATA
  REAL(SP) :: TSGRD_WEIGHT_MAX                    
  REAL(SP) :: TSGRD_TIMESCALE
  REAL(SP) :: TSGRD_TIME_WINDOW              !!TIME WINDOW FOR OBSERVATION ASSIMILATION (in hours)
  INTEGER  :: TSGRD_N_PER_INTERVAL           !! ASSUMING DAILY DATA:
  !! AVERAGE OVER
  CHARACTER(LEN=80) TSGRD_ASSIM_SAVE_FILE    !!FILE NAME FOR TS ASSIMILATION RESULT

  NAMELIST /NML_TSGRD_ASSIMILATION/      &
       & TSGRD_ASSIM,                    &
       & TSGRD_ASSIM_FILE,               &
       & TSGRD_WEIGHT_MAX,               &
       & TSGRD_TIMESCALE,                &
       & TSGRD_TIME_WINDOW,              &
       & TSGRD_N_PER_INTERVAL

  REAL(SP),ALLOCATABLE :: AW0G(:,:),AWXG(:,:),AWYG(:,:)

!--Data Assimilation Parameters for Current Nudging  Assimilation
!
  LOGICAL  :: CUR_NGASSIM            !!TRUE IF CURRENT ASSIMILATION ACTIVE(nudging)
  CHARACTER(LEN=80) CUR_NGASSIM_FILE   !!FILE NAME FOR CURRENT DATA
  REAL(SP) :: CUR_NG_RADIUS          !!SEARCH RADIUS FOR INTERPOLATION POINTS 
  REAL(SP) :: CUR_GAMA
  REAL(SP) :: CUR_GALPHA
  REAL(SP) :: CUR_NG_ASTIME_WINDOW       !(in hours)

  INTEGER  :: CUR_MAX_LAYER          !!MAXIMUM NUMBER OF VERTICAL DATA FROM ANY OBS POINT

  NAMELIST /NML_CUR_NGASSIMILATION/     &
       & CUR_NGASSIM,                   &
       & CUR_NGASSIM_FILE,              &
       & CUR_NG_RADIUS,                 &
       & CUR_GAMA,                      &
       & CUR_GALPHA,                    &
       & CUR_NG_ASTIME_WINDOW

!
!--Data Assimilation Parameters for Current OI Assimilation
!
  LOGICAL  :: CUR_OIASSIM            !!TRUE IF CURRENT OI ASSIMILATION ACTIVE
  CHARACTER(LEN=80) CUR_OIASSIM_FILE !!FILE NAME FOR CURRENT DATA
  REAL(SP) :: CUR_OI_RADIUS             !!SEARCH RADIUS FOR INTERPOLATION POINTS 
  REAL(SP) :: CUR_OIGALPHA
  REAL(SP) :: CUR_OI_ASTIME_WINDOW    !(in hours)
  INTEGER  :: CUR_N_INFLU            !!NUMBER OF INFLUENTIAL OBSERVATIONS
  REAL(SP),ALLOCATABLE,DIMENSION(:,:)  :: CUR_PARAM
  INTEGER(ITIME)  :: CUR_NSTEP_OI

  NAMELIST /NML_CUR_OIASSIMILATION/    &
       & CUR_OIASSIM,                  &
       & CUR_OIASSIM_FILE,             &
       & CUR_OI_RADIUS,                &
       & CUR_OIGALPHA,                    &
       & CUR_OI_ASTIME_WINDOW,         &
!       & CUR_MAX_LAYER,                &
       & CUR_N_INFLU,                  &
       & CUR_NSTEP_OI

  !
  !--Data Assimilation Parameters for Temp/Salinity Data Nudging Assimilation
  !
  LOGICAL  :: TS_NGASSIM                  !!TRUE IF TEMP/SAL ASSIMILATION ACTIVE
  CHARACTER(LEN=80) TS_NGASSIM_FILE         !!FILE NAME FOR TEMP/SAL DATA
  REAL(SP) :: TS_NG_RADIUS                !!SEARCH RADIUS FOR INTERPOLATION POINTS
  REAL(SP) :: TS_GAMA
  REAL(SP) :: TS_GALPHA
!  REAL(SP) :: TS_WEIGHT_MAX  
!  REAL(SP) :: TS_TIMESCALE  
  REAL(SP) :: TS_NG_ASTIME_WINDOW   !(in hours)

  NAMELIST /NML_TS_NGASSIMILATION/     &
       & TS_NGASSIM,                   &
       & TS_NGASSIM_FILE,              &
       & TS_NG_RADIUS,                 &
!       & TS_WEIGHT_MAX,                &
       & TS_GAMA,                      &
       & TS_GALPHA,                    &
!       & TS_TIMESCALE,                 &
       & TS_NG_ASTIME_WINDOW

!
!--Data Assimilation Parameters for Temp/Salinity Data OI Assimilation
!
  LOGICAL  :: TS_OIASSIM              !!TRUE IF TEMP/SAL OI ASSIMILATION ACTIVE
  CHARACTER(LEN=80):: TS_OIASSIM_FILE !!FILE NAME FOR TEMP/SAL DATA
  REAL(SP) :: TS_OI_RADIUS            !!SEARCH RADIUS FOR INTERPOLATION POINTS
  REAL(SP) :: TS_OIGALPHA  
  REAL(SP) :: TS_OI_ASTIME_WINDOW    !(in hours)
  INTEGER  :: TS_MAX_LAYER         !!MAXIMUM NUMBER OF VERTICAL DATA FROM ANY OBS POINT
  INTEGER  :: TS_N_INFLU           !!NUMBER OF INFLUENTIAL OBSERVATIONS
  REAL(SP),ALLOCATABLE :: TS_PARAM(:,:)

  INTEGER(ITIME)  :: TS_NSTEP_OI
  NAMELIST /NML_TS_OIASSIMILATION/    &
       & TS_OIASSIM,                &
       & TS_OIASSIM_FILE,           &
       & TS_OI_RADIUS,              &
       & TS_OIGALPHA,               &
       & TS_OI_ASTIME_WINDOW,          &
       & TS_MAX_LAYER,              &
       & TS_N_INFLU,                &
       & TS_NSTEP_OI

!qxu{
!
!--Current Assimilation Object Type
!
  TYPE ASSIM_OBJ_CUR
   INTEGER  :: N_TIMES                     !!NUMBER OF DATA TIMES
   INTEGER  :: N_INTPTS                    !!NUMBER OF INTERPOLATION POINTS 
   INTEGER  :: N_T_WEIGHT                  !!DATA TIME FOR CURRENT OBSERVATION WEIGHTING
   INTEGER  :: N_LAYERS                    !!NUMBER OF OBSERVATIONS IN THE VERTICAL
   INTEGER  :: N_CELL                      !!CELL NUMBER OF OBSERVATION
   REAL(SP) :: X,Y                         !!X AND Y COORDINATES OF OBSERVATION
   REAL(SP) :: T_WEIGHT                    !!TIME WEIGHT
   REAL(SP) :: DEPTH                       !!DEPTH AT OBSERVATION STATION (MOORING)
   REAL(SP) :: SITA                        !!LOCAL ISOBATH ANGLE AT OBSERVATION
   REAL(SP),ALLOCATABLE,DIMENSION(:)  :: ODEPTH      !!OBSERVATION DEPTHS
!   REAL(SP),ALLOCATABLE,DIMENSION(:)  :: TIMES       !!DATA TIMES
   TYPE(TIME),ALLOCATABLE,DIMENSION(:)  :: TIMES       !!DATA TIMES
   REAL(SP),ALLOCATABLE,DIMENSION(:,:):: UO,VO       !!OBSERVATION DATA FOR X,Y VELOCITY COMPONENTS
   INTEGER,ALLOCATABLE,DIMENSION(:)   :: INTPTS      !!POINTS USED TO INTERPOLATE TO OBSERVATION LOC 
   INTEGER,ALLOCATABLE,DIMENSION(:,:) :: S_INT       !!SIGMA INTERVALS SURROUNDING CURRENT MEASUREMENT
   REAL(SP),ALLOCATABLE,DIMENSION(:,:):: S_WEIGHT    !!SIGMA WEIGHTING                               
   REAL(SP),ALLOCATABLE,DIMENSION(:)  :: X_WEIGHT    !!SPATIAL WEIGHTING FOR INTERPOLATION POINTS
  END TYPE ASSIM_OBJ_CUR

!
!--Temperature/Salinity Assimilation Object Type
!
   TYPE ASSIM_OBJ_TS  
     INTEGER  :: N_TIMES                                  !!NUMBER OF DATA TIMES
     INTEGER  :: N_INTPTS                                 !!NUMBER OF INTERPOLATION POINTS
     INTEGER  :: N_T_WEIGHT                               !!DATA TIME FOR CURRENT OBSERVATION WEIGHTING
     INTEGER  :: N_LAYERS                                 !!NUMBER OF OBSERVATIONS IN THE VERTICAL
     INTEGER  :: N_CELL                                   !!CELL NUMBER OF OBSERVATION
     REAL(SP) :: X,Y                                      !!X AND Y COORDINATES OF OBSERVATION
     REAL(SP) :: T_WEIGHT                                 !!TIME WEIGHT
     REAL(SP) :: DEPTH                                    !!DEPTH AT OBSERVATION STATION (MOORING)
     REAL(SP) :: SITA                                     !!LOCAL ISOBATH ANGLE AT OBSERVATION
     REAL(SP), ALLOCATABLE, DIMENSION(:)   :: ODEPTH      !!OBSERVATION DEPTHS
!     REAL(SP), ALLOCATABLE, DIMENSION(:)   :: TIMES       !!DATA TIMES
     TYPE(TIME),ALLOCATABLE,DIMENSION(:)  :: TIMES        !!DATA TIMES
     REAL(SP), ALLOCATABLE, DIMENSION(:,:) :: TEMP        !!OBSERVATION DATA FOR TEMPERATURE 
     REAL(SP), ALLOCATABLE, DIMENSION(:,:) :: SAL         !!OBSERVATION DATA FOR SALINITY 
     INTEGER,  ALLOCATABLE, DIMENSION(:)   :: INTPTS      !!POINTS USED TO INTERPOLATE TO OBSERVATION LOC
     INTEGER,  ALLOCATABLE, DIMENSION(:,:) :: S_INT       !!SIGMA INTERVALS SURROUNDING CURRENT MEASUREMENT
     REAL(SP), ALLOCATABLE, DIMENSION(:,:) :: S_WEIGHT    !!SIGMA WEIGHTING
     REAL(SP), ALLOCATABLE, DIMENSION(:)   :: X_WEIGHT    !!SPATIAL WEIGHTING FOR INTERPOLATION POINTS
   END TYPE ASSIM_OBJ_TS    

!
!--Current Data Assimilation Variables
!
   INTEGER                          :: N_ASSIM_CUR !!NUMBER OF CURRENT OBSERVATIONS 
   TYPE(ASSIM_OBJ_CUR), ALLOCATABLE :: CUR_OBS(:)  !!CURRENT ASSIMILATION DATA OBJECTS
   INTEGER, ALLOCATABLE             :: DA_CUR(:)   !!FLAG IF ELEMENT IS USED FOR CURRENT DA INTERP 

!
!--Salinity/Temperature Data Assimilation Variables
!
   INTEGER                                N_ASSIM_TS   !!NUMBER OF TEMPERATURE OBSERVATIONS
   TYPE(ASSIM_OBJ_TS), ALLOCATABLE     :: TS_OBS(:)    !!TEMP ASSIMILATION DATA OBJECTS
   INTEGER, ALLOCATABLE                :: DA_TS(:)     !!FLAG IF NODE IS USED FOR CURRENT DA INTERP

!qxu}
   INTEGER                                N_ASSIM_TS_W   !!NUMBER OF TEMPERATURE O BSERVATIONS
   INTEGER, ALLOCATABLE, DIMENSION(:)   :: ID_STATION


  TYPE ASSIM_OBS_LOC
     INTEGER  :: N_TIMES
     TYPE(TIME), ALLOCATABLE, DIMENSION(:) :: OBSTIME(:)
     INTEGER  :: N_LOCS
     REAL(SP), ALLOCATABLE, DIMENSION(:,:) :: X ! (N_LOCS,N_TIMES)
     REAL(SP), ALLOCATABLE, DIMENSION(:,:) :: Y ! (N_LOCS,N_TIMES)
     REAL(SP), ALLOCATABLE, DIMENSION(:,:) :: Z ! (N_LOCS,N_TIMES)
     REAL(SP), ALLOCATABLE, DIMENSION(:)   :: H
     REAL(SP), ALLOCATABLE, DIMENSION(:)   :: SITA

  END TYPE ASSIM_OBS_LOC

  TYPE ASSIM_OBS_DATA
     REAL(SP), ALLOCATABLE, DIMENSION(:,:) :: DATA
     INTEGER, ALLOCATABLE, DIMENSION(:,:) :: MASK
  END TYPE ASSIM_OBS_DATA


  TYPE ASSIM_OBJ
     CHARACTER(LEN=80) :: VARNAME
     REAL(SP), POINTER, DIMENSION(:,:) :: DATA
     REAL(SP), POINTER, DIMENSION(:) :: X,Y,EL,H
     REAL(SP), POINTER, DIMENSION(:,:) :: SIGMA
     REAL(SP):: RADIUS
     REAL(SP):: WEIGHT_MAX
     REAL(SP):: TIMESCALE  
     REAL(SP):: TIME_WINDOW
     TYPE(NCFILE), POINTER :: FILE
     INTEGER :: N_OBS
     TYPE(ASSIM_OBS_LOC), POINTER :: OBS_LOC
     TYPE(ASSIM_OBS_DATA), POINTER :: OBS_DAT
  END TYPE ASSIM_OBJ

  !
  !--Current Data Assimilation Variables
  !
  TYPE(ASSIM_OBJ), POINTER :: ASSIM_U  !!CURRENT ASSIMILATION DATA OBJECTS
  TYPE(ASSIM_OBJ), POINTER :: ASSIM_V  !!CURRENT ASSIMILATION DATA OBJECTS

  !
  !--Salinity/Temperature Data Assimilation Variables
  !
  TYPE(ASSIM_OBJ), POINTER     :: ASSIM_T    !!TEMP ASSIMILATION DATA OBJECTS
  TYPE(ASSIM_OBJ), POINTER     :: ASSIM_S    !!TEMP ASSIMILATION DATA OBJECTS

  !
  !--SST Data Assimilation Variables
  !
  TYPE(ASSIM_OBJ), POINTER     :: ASSIM_SST   !!SST ASSIMILATION DATA OBJECTS

  !
  !-- GRID SST Data Assimilation Variables
  !

  TYPE(NCFILE), POINTER :: SST_FILE

  INTEGER                             N_TIMES_SST !!NUMBER OF SST OBSERVATIONS TIMES

  INTEGER    :: SST_SAVE_INDEX
  TYPE(TIME) :: SST_SAVE_TIME
  TYPE(TIME)  :: SST_SAVE_INTERVAL
  TYPE(NCVAR), POINTER :: VAR_SST
  TYPE(TIME)  :: ASSIM_RESTART_TIME 

  INTEGER                             ASSIM_FLAG  !!TRUE IF ON ASSIMILATION SWEEP   

  REAL(SP), ALLOCATABLE, TARGET, DIMENSION(:)  :: SST_OBS   !!SST OBS ON GRID
  REAL(SP), ALLOCATABLE, DIMENSION(:,:)  :: SST_SAVED  !!SST ON EACH HOUR DURING SIM 
  REAL(SP), ALLOCATABLE, DIMENSION(:)    :: SST_AVG   !!SIM SST AVERAGED OVER OBSERVATION PERIOD 
! lwang added for SST mld assimilation
  REAL(SP), ALLOCATABLE, DIMENSION(:,:,:)  :: T_SAVED, S_SAVED !!TEMP AND SALT ON EACH HOUR DURING SIM
  REAL(SP), ALLOCATABLE, DIMENSION(:,:)    :: TT_AVG, SS_AVG  !! SIM TEMP AND SALT AVERAGED OVER OBSERVATION PERIOD
  REAL(SP), ALLOCATABLE, DIMENSION(:,:)    :: RHO_AVG       !! AVERAGE DENSITY CALCULATED BY TT_AVG AND SS_AVG
  REAL(SP), ALLOCATABLE, DIMENSION(:)      :: MLD_RHO       !! MIXED LAYER DEPTH
! lwang  
!# if defined (ENKF)
  REAL(SP), ALLOCATABLE, DIMENSION(:,:)    :: SST_AVG_ENKF   !!SIM SST AVERAGED OVER OBSERVATION PERIOD FOR EACH ENSEMBLE MEMBER
  REAL(SP), ALLOCATABLE, DIMENSION(:,:,:)  :: SST_SAVED_ENKF  !!SST ON EACH HOUR DURING SIM FOR EACH ENSEMBLE MEMBER
  REAL(SP), ALLOCATABLE, DIMENSION(:,:)    :: SSS_AVG_ENKF   !!SIM SST AVERAGED OVER OBSERVATION PERIOD FOR EACH ENSEMBLE MEMBER
  REAL(SP), ALLOCATABLE, DIMENSION(:,:,:)  :: SSS_SAVED_ENKF  !!SST ON EACH HOUR DURING SIM FOR EACH ENSEMBLE MEMBER
  REAL(SP), ALLOCATABLE, DIMENSION(:,:,:)  :: SSH_SAVED_ENKF  !!SSH ON EACH HOUR DURING SIM FOR EACH MEMEBER
  REAL(SP), ALLOCATABLE, DIMENSION(:,:)    :: SSH_AVG_ENKF   !!SIM SSH AVERAGED OVER OBSERVATION PERIOD FOR EACH MEMBER
!# endif

  !
  !-- GRID SSS Data Assimilation Variables
  !

  TYPE(NCFILE), POINTER :: SSS_FILE

  INTEGER                             N_TIMES_SSS !!NUMBER OF SSS OBSERVATIONS TIMES

  INTEGER    :: SSS_SAVE_INDEX
  TYPE(TIME) :: SSS_SAVE_TIME
  TYPE(TIME)  :: SSS_SAVE_INTERVAL
  TYPE(NCVAR), POINTER :: VAR_SSS
!  TYPE(TIME)  :: ASSIM_RESTART_TIME 

!  INTEGER                             ASSIM_FLAG  !!TRUE IF ON ASSIMILATION SWEEP   

  REAL(SP), ALLOCATABLE, TARGET, DIMENSION(:)  :: SSS_OBS   !!SSS OBS ON GRID
  REAL(SP), ALLOCATABLE, DIMENSION(:,:)  :: SSS_SAVED  !!SSS ON EACH HOUR DURING SIM 
  REAL(SP), ALLOCATABLE, DIMENSION(:)    :: SSS_AVG   !!SIM SSS AVERAGED OVER OBSERVATION PERIOD
  REAL(SP), ALLOCATABLE, DIMENSION(:)    :: SSS_WEIGHT !!SSS WEIGHT ON GRID 
! lwang added for SSS mld assimilation
!  REAL(SP), ALLOCATABLE, DIMENSION(:,:,:)  :: T_SAVED, S_SAVED !!TEMP AND SALT ON EACH HOUR DURING SIM
!  REAL(SP), ALLOCATABLE, DIMENSION(:,:)    :: TT_AVG, SS_AVG  !! SIM TEMP AND SALT AVERAGED OVER OBSERVATION PERIOD
!  REAL(SP), ALLOCATABLE, DIMENSION(:,:)    :: RHO_AVG       !! AVERAGE DENSITY CALCULATED BY TT_AVG AND SS_AVG
!  REAL(SP), ALLOCATABLE, DIMENSION(:)      :: MLD_RHO       !! MIXED LAYER DEPTH
! lwang  

!qxu{
  TYPE(NCFILE), POINTER :: SSH_FILE

  INTEGER                             N_TIMES_SSH !!NUMBER OF SST OBSERVATIONS TIMES

  INTEGER    :: SSH_SAVE_INDEX
!qxu{for SSH assimilation by 04/01/2022
 !TYPE(TIME) :: SSH_SAVE_TIME
  TYPE(TIME) :: SSH_SAVE_TIME,SSH_SAVE_TIME0
!qxu}

  TYPE(TIME)  :: SSH_SAVE_INTERVAL
  TYPE(NCVAR), POINTER :: VAR_SSH

  REAL(SP), ALLOCATABLE, TARGET, DIMENSION(:)  :: SSH_OBS   !!SST OBS ON GRID
  REAL(SP), ALLOCATABLE, DIMENSION(:,:)  :: SSH_SAVED  !!SST ON EACH HOUR DURING SIM 
  REAL(SP), ALLOCATABLE, DIMENSION(:)    :: SSH_AVG   !!SIM SST AVERAGED OVER OBSERVATION PERIOD 

  TYPE(NCFILE), POINTER :: TS_FILE

  INTEGER  ::                          N_TIMES_TSC !!NUMBER OF TSC OBSERVATIONS TIMES

  INTEGER    :: TSC_SAVE_INDEX, TSC_SAVE_INDEX2
  TYPE(TIME) :: TSC_SAVE_TIME, TSC_SAVE_TIME2
  TYPE(TIME)  :: TSC_SAVE_INTERVAL
!  TYPE(NCVAR), POINTER :: VAR_TC
!  TYPE(NCVAR), POINTER :: VAR_SC
  !TYPE(TIME)  :: ASSIM_RESTART_TIME 

  !INTEGER                             ASSIM_FLAG  !!TRUE IF ON ASSIMILATION SWEEP   

  REAL(SP), ALLOCATABLE, TARGET, DIMENSION(:,:)  :: TC_OBS   !!Temp OBS ON GRID
  REAL(SP), ALLOCATABLE, TARGET, DIMENSION(:,:)  :: SC_OBS   !!Salinity OBS ON GRID

  TYPE(NCVAR), POINTER :: TSC_T1_N, TSC_T1_P
  TYPE(NCVAR), POINTER :: TSC_S1_N, TSC_S1_P

  REAL(SP), ALLOCATABLE, DIMENSION(:,:,:)  :: TC_SAVED  !!SST ON EACH HOUR DURING SIM 
  REAL(SP), ALLOCATABLE, DIMENSION(:,:,:)  :: SC_SAVED  !!SST ON EACH HOUR DURING SIM 
  REAL(SP), ALLOCATABLE, DIMENSION(:,:)    :: TC_AVG    !!SIM TEMP AVERAGED OVER OBSERVATION PERIOD 
  REAL(SP), ALLOCATABLE, DIMENSION(:,:)    :: SC_AVG    !!SIM SAlinity AVERAGED OVER OBSERVATION PERIOD 

  REAL(SP), ALLOCATABLE, DIMENSION(:,:)    :: TC0_AVG   !!SIM TEMP AVERAGED OVER MONTHLY PERIOD
  REAL(SP), ALLOCATABLE, DIMENSION(:,:)    :: SC0_AVG   !!SIM SALINITY AVERAGED OVER MONTHLY PERIOD

  ! Some IINT VARIABLES TO KEEP TRACK OF PROGRESS
  INTEGER(ITIME) :: INT_COUNT, INT_START, INT_END


  !--save all_var to the *_BUF 

  TYPE(TIME)                              ::IntTime_BUF 
  TYPE(TIME)                              ::ExtTime_BUF 
  INTEGER(ITIME)                          ::IINT_BUF
  REAL(SP), ALLOCATABLE, DIMENSION(:,:)   ::U_BUF
  REAL(SP), ALLOCATABLE, DIMENSION(:,:)   ::V_BUF
  REAL(SP), ALLOCATABLE, DIMENSION(:,:)   ::WTS_BUF
  REAL(SP), ALLOCATABLE, DIMENSION(:,:)   ::S1_BUF
  REAL(SP), ALLOCATABLE, DIMENSION(:,:)   ::T1_BUF
!  REAL(SP), ALLOCATABLE, DIMENSION(:,:)   ::RHO_BUF

  REAL(SP), ALLOCATABLE, DIMENSION(:,:)   ::KM_BUF
  REAL(SP), ALLOCATABLE, DIMENSION(:,:)   ::KH_BUF
  REAL(SP), ALLOCATABLE, DIMENSION(:,:)   ::KQ_BUF

# if defined (EQUI_TIDE)
  REAL(SP), ALLOCATABLE, DIMENSION(:)   :: EL_EQI_BUF
# endif

# if defined (ATMO_TIDE)
  REAL(SP), ALLOCATABLE, DIMENSION(:)   :: EL_ATMO_BUF
# endif

# if defined (GOTM)
  REAL(SP), ALLOCATABLE, DIMENSION(:,:)   :: TKE_BUF
  REAL(SP), ALLOCATABLE, DIMENSION(:,:)   :: TEPS_BUF
# else
  REAL(SP), ALLOCATABLE, DIMENSION(:,:)   ::Q2_BUF
  REAL(SP), ALLOCATABLE, DIMENSION(:,:)   ::Q2L_BUF  
  REAL(SP), ALLOCATABLE, DIMENSION(:,:)   ::L_BUF
# endif

  REAL(SP), ALLOCATABLE, DIMENSION(:)     ::UA_BUF
  REAL(SP), ALLOCATABLE, DIMENSION(:)     ::VA_BUF

  REAL(SP), ALLOCATABLE, DIMENSION(:)     ::EL_BUF
  REAL(SP), ALLOCATABLE, DIMENSION(:)     ::ET_BUF
  REAL(SP), ALLOCATABLE, DIMENSION(:)     ::H_BUF

# if defined (SEDIMENT)
  REAL(SP), ALLOCATABLE, DIMENSION(:,:,:)   ::CONC_BUF
# endif
 

# if defined (DYE_RELEASE)  
  REAL(SP), ALLOCATABLE, DIMENSION(:,:)   ::DYE_BUF
  REAL(SP), ALLOCATABLE, DIMENSION(:,:)   ::DYEF_BUF
!  REAL(SP), ALLOCATABLE, DIMENSION(:,:)   ::DYEMEAN_BUF
# endif 


#   if defined(ICE)
    REAL(SP), ALLOCATABLE, DIMENSION(:,:,:) ::aicen_buf 
    REAL(SP), ALLOCATABLE, DIMENSION(:,:,:) ::vicen_buf
    REAL(SP), ALLOCATABLE, DIMENSION(:,:,:) ::vsnon_buf
    REAL(SP), ALLOCATABLE, DIMENSION(:,:,:) ::tsfcn_buf
    REAL(SP), ALLOCATABLE, DIMENSION(:,:,:) ::esnon_buf
    REAL(SP), ALLOCATABLE, DIMENSION(:,:,:) ::eicen_buf
    REAL(SP), ALLOCATABLE, DIMENSION(:)     ::uice2_buf
    REAL(SP), ALLOCATABLE, DIMENSION(:)     ::vice2_buf
    REAL(SP), ALLOCATABLE, DIMENSION(:,:)   ::fresh_buf
    REAL(SP), ALLOCATABLE, DIMENSION(:,:)   ::fsalt_buf
    REAL(SP), ALLOCATABLE, DIMENSION(:,:)   ::fhnet_buf
    REAL(SP), ALLOCATABLE, DIMENSION(:,:)   ::strength_buf
    INTEGER , ALLOCATABLE, DIMENSION(:)     ::isicec_buf
    REAL(SP), ALLOCATABLE, DIMENSION(:)   ::sig1_buf
    REAL(SP), ALLOCATABLE, DIMENSION(:)   ::sig2_buf
    REAL(SP), ALLOCATABLE, DIMENSION(:)   ::sig12_buf
# endif




CONTAINS !------------------------------------------------------------------!
  ! NAME_LIST_INITIALIZE_ASSIM : INITIALIZE NAMELIST VARIABLES VALUE !
  ! SET_ASSIM_PARAM     :   READ ASSIMILATION PARAMETERS FROM INPUT  !
  ! SETUP_DATA_ASSIMILATION                                          !
  ! OPEN_SST_ASSIM      :                                            !
  ! OPEN_SSTGRD_ASSIM   :                                            !
  ! OPEN_SSSGRD_ASSIM   :                                            !
  ! OPEN_SSHGRD_ASSIM   :                                            !
  ! OPEN_TSGRD_ASSIM    :                                            !
  ! LOAD_SST_ASSIM      :                                            !
  ! SET_SSTGRD_ASSIM    :                                            !
  ! SET_SSSGRD_ASSIM    :                                            !
  ! SET_SSHGRD_ASSIM    :                                            !
  ! SET_TSGRD_ASSIM     :                                            !
  ! SET_CUR_ASSIM_DATA  :   READ AND SET CURRENT ASSIMILATION DATA   ! 
  ! SET_TS_ASSIM_DATA   :   READ AND SET TEMP/SAL ASSIMILATION DATA  ! 
  ! CURRENT_ASSIMILATION:   NUDGE CURRENT USING ASSIMILATION         !
  ! TEMP ASSIMILATION   :   NUDGE TEMP USING ASSIMILATION            !
  ! SALT_ASSIMILATION   :   NUDGE SALT USING ASSIMILATION            !
  ! CUR_OPTIMINTERP     :                                            !
  ! TS_OPTIMINTERP      :                                            !
  ! SSTGRD_OBSERVATION_UPDATE                                        !
  ! SSSGRD_OBSERVATION_UPDATE                                        !
  ! SSHGRD_OBSERVATION_UPDATE                                        !
  ! SSTGRD_NUDGE        :                                            !
  ! SSSGRD_NUDGE        :                                            !
  ! SSHGRD_NUDGE        :                                            !
  ! TSGRD_NUDGE         :                                            !
  ! TSGRD_OBSERVATION_UPDATE                                         !
  ! SST_SAVE            :                                            !
  ! SSS_SAVE            :                                            !
  ! SSH_SAVE            :                                            !
  ! TSGRD_SAVE          :                                            !
  ! RESTORE_STATE       :                                            !
  ! EXCHANGE_ALL        :                                            !
  ! SAVE_STATE          :                                            !
  ! ALLOC_BUFFER        :                                            !
  ! SETUP_RSTFILE_ASSIM :                                            !
  ! DUMP_DATA_ASSIM     :                                            !
  ! SET_MONTHLY_TS_MEAN :                                            ! 
  ! DUMP_TSAVG_ASSIM    :                                            !
  ! -----------------------------------------------------------------!


  !==============================================================================|
  !==============================================================================|

  SUBROUTINE NAME_LIST_INITIALIZE_ASSIM 
    IMPLICIT NONE

    !    NML_SST_ASSIMILIATION
    SST_ASSIM          = .FALSE.
    SST_ASSIM_FILE     = trim(CASENAME)//"_sst.nc"
    SST_RADIUS         = 0.0_SP
    SST_WEIGHT_MAX     = 0.0_SP
    SST_TIMESCALE      = 0.0_SP
    SST_TIME_WINDOW    = 0.0_SP
    SST_N_PER_INTERVAL = 0

    !    NML_SSTGRD_ASSIMILATION
    SSTGRD_ASSIM          = .FALSE.
! lwang added for SST mld assimilation
    SSTGRD_MLD            = .FALSE.
! lwang
    SSTGRD_ASSIM_FILE     = trim(CASENAME)//"_sstgrd.nc"
    SSTGRD_WEIGHT_MAX     = 0.0_SP
    SSTGRD_TIMESCALE      = 0.0_SP
    SSTGRD_TIME_WINDOW    = 0.0_SP
    SSTGRD_N_PER_INTERVAL = 0

    !    NML_SSSGRD_ASSIMILIATION
    SSSGRD_ASSIM          = .FALSE.
! lwang added for SSS mld assimilation
!    SSSGRD_MLD            = .FALSE.
! lwang
    SSSGRD_ASSIM_FILE     = trim(CASENAME)//"_sssgrd.nc"
    SSSGRD_WEIGHT_MAX     = 0.0_SP
    SSSGRD_TIMESCALE      = 0.0_SP
    SSSGRD_TIME_WINDOW    = 0.0_SP
    SSSGRD_N_PER_INTERVAL = 0

    !    NML_SSHGRD_ASSIMILIATION
    SSHGRD_ASSIM          = .FALSE.
    SSHGRD_ASSIM_FILE     = trim(CASENAME)//"_sshgrd.nc"
    SSHGRD_WEIGHT_MAX     = 0.0_SP
    SSHGRD_TIMESCALE      = 0.0_SP
    SSHGRD_TIME_WINDOW    = 0.0_SP
    SSHGRD_N_PER_INTERVAL = 0

    !    NML_TSGRD_ASSIMILIATION
    TSGRD_ASSIM          = .FALSE.
    TSGRD_ASSIM_FILE     = trim(CASENAME)//"_tsgrd.nc"
    TSGRD_WEIGHT_MAX     = 0.0_SP
    TSGRD_TIMESCALE      = 0.0_SP
    TSGRD_TIME_WINDOW    = 0.0_SP
    TSGRD_N_PER_INTERVAL = 0

!    !    NML_CUR_ASSIMILIATION
!    CUR_ASSIM       = .FALSE.
!    CUR_ASSIM_FILE  = trim(CASENAME)//"_cur.nc"
!    CUR_RADIUS      = 0.0_SP
!    CUR_WEIGHT_MAX  = 0.0_SP
!    CUR_TIMESCALE   = 0.0_SP
!    CUR_TIME_WINDOW = 0.0_SP

    !    NML_CUR_NGASSIMILIATION
    CUR_NGASSIM            = .FALSE.
    CUR_NGASSIM_FILE       = trim(CASENAME)//"_cur"
    CUR_GAMA               = 0.0_SP
    CUR_NG_RADIUS          = 0.0_SP
    CUR_GALPHA             = 0.0_SP
    CUR_NG_ASTIME_WINDOW   = 0.0_SP

    !    NML_CUR_OIASSIMILIATION
    CUR_OIASSIM            = .FALSE.
    CUR_OIASSIM_FILE       = trim(CASENAME)//"_cur"
    CUR_OI_RADIUS          = 0.0_SP 
    CUR_OI_ASTIME_WINDOW   = 0.0_SP
    CUR_MAX_LAYER          = 0.0_SP
    CUR_N_INFLU            = 0.0_SP

    !    NML_TS_NGASSIMILIATION
    TS_NGASSIM             = .FALSE.
    TS_NGASSIM_FILE        = trim(CASENAME)//"_ts"
    TS_NG_RADIUS           = 0.0_SP
    TS_GAMA                = 0.0_SP
    TS_GALPHA              = 0.0_SP
    TS_NG_ASTIME_WINDOW    = 0.0_SP

    !    NML_TS_OIASSIMILIATION
    TS_OIASSIM             = .FALSE.
    TS_OIASSIM_FILE        = trim(CASENAME)//"_ts"
    TS_OI_RADIUS           = 0.0_SP
    TS_OIGALPHA            = 0.0_SP
    TS_OI_ASTIME_WINDOW    = 0.0_SP
    TS_MAX_LAYER           = 0.0_SP
    TS_N_INFLU             = 0.0_SP
    TS_NSTEP_OI            = 0

  END SUBROUTINE NAME_LIST_INITIALIZE_ASSIM 

  SUBROUTINE SET_ASSIM_PARAM 

    !------------------------------------------------------------------------------|
    !  READ IN PARAMETERS CONTROLLING ASSIMILATION                                 |
    !------------------------------------------------------------------------------|

    IMPLICIT NONE
    CHARACTER(LEN=120) :: FNAME, pathnfile
    INTEGER :: IOS, charnum
    LOGICAL FEXIST


    IF (DBG_SET(DBG_SBR)) WRITE(IPT,*) "START: SET_ASSIM_PARAM"

    charnum = index (DATA_ASSIMILATION_FILE,".nml")
    if (charnum /= len_trim(DATA_ASSIMILATION_FILE)-3)&
         & CALL WARNING("DATA ASSIMILATION FILE does not end in .nml", &
         & trim(DATA_ASSIMILATION_FILE))
    ! OPEN FILE - try both with appending input dir and without!
    pathnfile = trim(INPUT_DIR)//trim(DATA_ASSIMILATION_FILE)
    INQUIRE(FILE=PATHNFILE,EXIST=FEXIST)
    IF(FEXIST) THEN
       Call FOPEN(ASSIMUNIT,trim(pathnfile),'cfr')
    ELSE
       pathnfile = trim(DATA_ASSIMILATION_FILE)
       Call FOPEN(ASSIMUNIT,trim(pathnfile),'cfr')
    END IF


    CALL NAME_LIST_INITIALIZE_ASSIM

    ! SAVE FILE NAME USED TO FNAME FOR ERROR CHECKING
    FNAME =  pathnfile

    ! Read SST ASSIMILATION Settings
    READ(UNIT=ASSIMUNIT, NML=NML_SST_ASSIMILATION,IOSTAT=ios)
    if(ios .NE. 0 ) then
       if(DBG_SET(dbg_log)) write(UNIT=IPT,NML=NML_SST_ASSIMILATION)
       CALL FATAL_ERROR("Can Not Read NameList NML_SST_ASSIMILATION from file: "//trim(FNAME))
    end if
    SST_TIME_WINDOW = SST_TIME_WINDOW*3600.0   ! convert hours -> seconds
    REWIND(ASSIMUNIT)

    if(DBG_SET(dbg_scl)) &
         & write(IPT,*) "Read_Name_List:"

    if(DBG_SET(dbg_scl)) &
         & write(UNIT=IPT,NML=NML_SST_ASSIMILATION)


    ! Read SST GRID ASSIMILATION Settings
    READ(UNIT=ASSIMUNIT, NML=NML_SSTGRD_ASSIMILATION,IOSTAT=ios)
    if(ios .NE. 0 ) then
       if(DBG_SET(dbg_log)) write(UNIT=IPT,NML=NML_SSTGRD_ASSIMILATION)
       CALL FATAL_ERROR("Can Not Read NameList NML_SSTGRD_ASSIMILATION from file: "//trim(FNAME))
    end if
   SSTGRD_TIME_WINDOW = SSTGRD_TIME_WINDOW*3600.0   ! convert hours -> seconds
    REWIND(ASSIMUNIT)


    if(DBG_SET(dbg_scl)) &
         & write(IPT,*) "Read_Name_List:"

    if(DBG_SET(dbg_scl)) &
         & write(UNIT=IPT,NML=NML_SSTGRD_ASSIMILATION)

    ! Read SSS GRID ASSIMILATION Settings
    READ(UNIT=ASSIMUNIT, NML=NML_SSSGRD_ASSIMILATION,IOSTAT=ios)
    if(ios .NE. 0 ) then
       if(DBG_SET(dbg_log)) write(UNIT=IPT,NML=NML_SSSGRD_ASSIMILATION)
       CALL FATAL_ERROR("Can Not Read NameList NML_SSSGRD_ASSIMILATION from file: "//trim(FNAME))
    end if
   SSSGRD_TIME_WINDOW = SSSGRD_TIME_WINDOW*3600.0   ! convert hours -> seconds
    REWIND(ASSIMUNIT)

!----> Siqi Li, SSS@20230928
!    IF(SSSGRD_ASSIM /= SSTGRD_ASSIM) CALL FATAL_ERROR("SSTGRD and SSSGRD must turn on or turn off at the same time")
    IF (SSSGRD_ASSIM .AND. (.NOT.SSTGRD_ASSIM)) CALL FATAL_ERROR("SSSGRD cannot be turned on without SSTGRD")
!<----

    if(DBG_SET(dbg_scl)) &
         & write(IPT,*) "Read_Name_List:"

    if(DBG_SET(dbg_scl)) &
         & write(UNIT=IPT,NML=NML_SSSGRD_ASSIMILATION)

    ! Read SSH GRID ASSIMILATION Settings
    READ(UNIT=ASSIMUNIT, NML=NML_SSHGRD_ASSIMILATION,IOSTAT=ios)
    if(ios .NE. 0 ) then
       if(DBG_SET(dbg_log)) write(UNIT=IPT,NML=NML_SSHGRD_ASSIMILATION)
       CALL FATAL_ERROR("Can Not Read NameList NML_SSHGRD_ASSIMILATION from file: "//trim(FNAME))
    end if
   SSHGRD_TIME_WINDOW = SSHGRD_TIME_WINDOW*3600.0   ! convert hours -> seconds
    REWIND(ASSIMUNIT)


    if(DBG_SET(dbg_scl)) &
         & write(IPT,*) "Read_Name_List:"

    if(DBG_SET(dbg_scl)) &
         & write(UNIT=IPT,NML=NML_SSHGRD_ASSIMILATION)

    ! Read TS GRID ASSIMILATION Settings
    READ(UNIT=ASSIMUNIT, NML=NML_TSGRD_ASSIMILATION,IOSTAT=ios)
    if(ios .NE. 0 ) then
       if(DBG_SET(dbg_log)) write(UNIT=IPT,NML=NML_TSGRD_ASSIMILATION)
       CALL FATAL_ERROR("Can Not Read NameList NML_TSGRD_ASSIMILATION from file: "//trim(FNAME))
    end if
    TSGRD_TIME_WINDOW = TSGRD_TIME_WINDOW*3600.0   ! convert hours -> seconds
    REWIND(ASSIMUNIT)
    
    if(DBG_SET(dbg_scl)) &
         & write(IPT,*) "Read_Name_List:"

    if(DBG_SET(dbg_scl)) &
         & write(UNIT=IPT,NML=NML_TSGRD_ASSIMILATION)

    ! Read CUR NUDGING ASSIMILATION Settings
    rewind(ASSIMUNIT)
    READ(UNIT=ASSIMUNIT, NML=NML_CUR_NGASSIMILATION,IOSTAT=ios)
    if(ios .NE. 0 ) then
       if(DBG_SET(dbg_log)) write(UNIT=IPT,NML=NML_CUR_NGASSIMILATION)
       CALL FATAL_ERROR("Can Not Read NameList NML_CUR_NGASSIMILATION from file: "//trim(FNAME))
    end if
    CUR_NG_ASTIME_WINDOW = CUR_NG_ASTIME_WINDOW*3600.0      !convert hours -> seconds
    REWIND(ASSIMUNIT)

    if(DBG_SET(dbg_scl)) &
         & write(IPT,*) "Read_Name_List:"

    if(DBG_SET(dbg_scl)) &
         & write(UNIT=IPT,NML=NML_CUR_NGASSIMILATION)

    ! Read CUR OI ASSIMILATION Settings
    READ(UNIT=ASSIMUNIT, NML=NML_CUR_OIASSIMILATION,IOSTAT=ios)
    if(ios .NE. 0 ) then
       if(DBG_SET(dbg_log)) write(UNIT=IPT,NML=NML_CUR_OIASSIMILATION)
       CALL FATAL_ERROR("Can Not Read NameList NML_CUR_OIASSIMILATION from file: "//trim(FNAME))
    end if
    CUR_OI_ASTIME_WINDOW = CUR_OI_ASTIME_WINDOW*3600.0      !convert hours -> seconds
    REWIND(ASSIMUNIT)

    if(DBG_SET(dbg_scl)) &
         & write(IPT,*) "Read_Name_List:"

    if(DBG_SET(dbg_scl)) &
         & write(UNIT=IPT,NML=NML_CUR_OIASSIMILATION)

    ! Read TS NUDGING ASSIMILATION Settings
    READ(UNIT=ASSIMUNIT, NML=NML_TS_NGASSIMILATION,IOSTAT=ios)
    if(ios .NE. 0 ) then
       if(DBG_SET(dbg_log)) write(UNIT=IPT,NML=NML_TS_NGASSIMILATION)
       CALL FATAL_ERROR("Can Not Read NameList NML_TS_NGASSIMILATION from file: "//trim(FNAME))
    end if
    TS_NG_ASTIME_WINDOW = TS_NG_ASTIME_WINDOW*3600.0      !convert hours -> seconds
    REWIND(ASSIMUNIT)

    if(DBG_SET(dbg_scl)) &
         & write(IPT,*) "Read_Name_List:"

    if(DBG_SET(dbg_scl)) &
         & write(UNIT=IPT,NML=NML_TS_NGASSIMILATION)

    ! Read TS OI ASSIMILATION Settings
    READ(UNIT=ASSIMUNIT, NML=NML_TS_OIASSIMILATION,IOSTAT=ios)
    if(ios /= 0 ) then
       if(DBG_SET(dbg_log)) write(UNIT=IPT,NML=NML_TS_OIASSIMILATION)
       CALL FATAL_ERROR("Can Not Read NameList NML_TS_OIASSIMILATION from file: "//trim(FNAME))
    end if
    TS_OI_ASTIME_WINDOW = TS_OI_ASTIME_WINDOW*3600.0      !convert hours -> seconds
    REWIND(ASSIMUNIT)

    if(DBG_SET(dbg_scl)) &
         & write(IPT,*) "Read_Name_List:"

    if(DBG_SET(dbg_scl)) &
         & write(UNIT=IPT,NML=NML_TS_OIASSIMILATION)

!------------------------------------------------------------------------------|
!   MODIFY VARIABLES TO CORRESPOND TO CORRECT UNITS              
!------------------------------------------------------------------------------|
!   IF(CUR_NGASSIM)CUR_NG_ASTIME_WINDOW = CUR_NG_ASTIME_WINDOW*3600. !!CONVERT HOURS --> SECONDS
!   IF(CUR_OIASSIM)CUR_OI_ASTIME_WINDOW = CUR_OI_ASTIME_WINDOW*3600. !!CONVERT HOURS --> SECONDS

!   IF(TS_NGASSIM)TS_NG_ASTIME_WINDOW = TS_NG_ASTIME_WINDOW*3600. !!CONVERT HOURS --> SECONDS
!   IF(TS_OIASSIM)TS_OI_ASTIME_WINDOW = TS_OI_ASTIME_WINDOW*3600. !!CONVERT HOURS --> SECONDS

    IF (DBG_SET(DBG_LOG)) THEN
       WRITE(IPT,*)''
       WRITE(IPT,*)'!        DATA ASSIMILATION PARAMETERS       '

!       IF(CUR_ASSIM)THEN
!          WRITE(IPT,*)'!  # CUR_ASSIM       :  ACTIVE'
!          WRITE(IPT,*)'!  # CUR_ASSIM_FILE      : '//TRIM(CUR_ASSIM_FILE)
!          WRITE(IPT,*)'!  # CUR_RADIUS          :',CUR_RADIUS
!          WRITE(IPT,*)'!  # CUR_WEIGHT_MAX      :',CUR_WEIGHT_MAX
!          WRITE(IPT,*)'!  # CUR_TIMESCALE       :',CUR_TIMESCALE   
!          WRITE(IPT,*)'!  # CUR_TIME_WINDOW     :',CUR_TIME_WINDOW
!          WRITE(IPT,*)''
!       ELSE
!          WRITE(IPT,*)'!  # CUR_ASSIM           :  NOT ACTIVE'
!          WRITE(IPT,*)''
!       END IF

!qxu{
       IF(CUR_NGASSIM)THEN
          WRITE(IPT,*)'!  # CUR_NGASSIM         :  ACTIVE'
          WRITE(IPT,*)'!  # CUR_NGASSIM_FILE    : '//TRIM(CUR_NGASSIM_FILE)
          WRITE(IPT,*)'!  # CUR_NG_RADIUS       :',CUR_NG_RADIUS
          WRITE(IPT,*)'!  # CUR_GALPHA          :',CUR_GALPHA
          WRITE(IPT,*)'!  # CUR_GAMA            :',CUR_GAMA   
          WRITE(IPT,*)'!  # CUR_NG_ASTIME_WINDOW (seconds):',CUR_NG_ASTIME_WINDOW
       ELSE
          WRITE(IPT,*)'!  # CUR_NGASSIM         :  NOT ACTIVE'
       END IF
!qxu}       

       IF(CUR_OIASSIM)THEN
          WRITE(IPT,*)'!  # CUR_OIASSIM         :  ACTIVE'
          WRITE(IPT,*)'!  # CUR_OIASSIM_FILE    : '//TRIM(CUR_OIASSIM_FILE)
          WRITE(IPT,*)'!  # CUR_OI_RADIUS       :',CUR_OI_RADIUS
          WRITE(IPT,*)'!  # CUR_OI_ASTIME_WINDOW (seconds):',CUR_OI_ASTIME_WINDOW
!          WRITE(IPT,*)'!  # CUR_MAX_LAYER       :',CUR_MAX_LAYER
          WRITE(IPT,*)'!  # CUR_N_INFLU         :',CUR_N_INFLU
       ELSE
          WRITE(IPT,*)'!  # CUR_OIASSIM          :  NOT ACTIVE'
       END IF
       
       IF(SST_ASSIM)THEN
          WRITE(IPT,*)'!  # SST_ASSIM           :  ACTIVE'
          WRITE(IPT,*)'!  # SST_RADIUS          :',SST_RADIUS
          WRITE(IPT,*)'!  # SST_ASSIM_FILE      : '//TRIM(SST_ASSIM_FILE)
          WRITE(IPT,*)'!  # SST_TIMESCALE       :',SST_TIMESCALE
          WRITE(IPT,*)'!  # SST_WEIGHT_MAX      :',SST_WEIGHT_MAX   
          WRITE(IPT,*)'!  # SST_TIME_WINDOW(seconds)     :',SST_TIME_WINDOW
          WRITE(IPT,*)'!  # SST_N_PER_INTERVAL  :',SST_N_PER_INTERVAL
          WRITE(IPT,*)''
       ELSE
          WRITE(IPT,*)'!  # SST_ASSIM           :  NOT ACTIVE'
          WRITE(IPT,*)''
       END IF

       IF(SSTGRD_ASSIM)THEN
          WRITE(IPT,*)'!  # SSTGRD_ASSIM           :  ACTIVE'
! lwang added for SST mld assimilation
          IF (SSTGRD_MLD)THEN
             WRITE(IPT,*)'!  # SSTGRD_MLD             :   ACTIVE'
          ELSE
             WRITE(IPT,*)'!  # SSTGRD_MLD             :   NOT ACTIVE'
          END IF
! lwang
          WRITE(IPT,*)'!  # SSTGRD_ASSIM_FILE      : '//TRIM(SSTGRD_ASSIM_FILE)
          WRITE(IPT,*)'!  # SSTGRD_TIMESCALE       :',SSTGRD_TIMESCALE
          WRITE(IPT,*)'!  # SSTGRD_WEIGHT_MAX      :',SSTGRD_WEIGHT_MAX   
          WRITE(IPT,*)'!  # SSTGRD_TIME_WINDOW (seconds)     :',SSTGRD_TIME_WINDOW
          WRITE(IPT,*)'!  # SSTGRD_N_PER_INTERVAL  :',SSTGRD_N_PER_INTERVAL
          WRITE(IPT,*)''
       ELSE
          WRITE(IPT,*)'!  # SSTGRD_ASSIM           :  NOT ACTIVE'
          WRITE(IPT,*)''
       END IF

       IF(SSSGRD_ASSIM)THEN
          WRITE(IPT,*)'!  # SSSGRD_ASSIM           :  ACTIVE'
! lwang added for SSS mld assimilation
!          IF (SSSGRD_MLD)THEN
!             WRITE(IPT,*)'!  # SSSGRD_MLD             :   ACTIVE'
!          ELSE
!             WRITE(IPT,*)'!  # SSSGRD_MLD             :   NOT ACTIVE'
!          END IF
! lwang
          WRITE(IPT,*)'!  # SSSGRD_ASSIM_FILE      : '//TRIM(SSSGRD_ASSIM_FILE)
          WRITE(IPT,*)'!  # SSSGRD_TIMESCALE       :',SSSGRD_TIMESCALE
          WRITE(IPT,*)'!  # SSSGRD_WEIGHT_MAX      :',SSSGRD_WEIGHT_MAX   
          WRITE(IPT,*)'!  # SSSGRD_TIME_WINDOW (seconds)     :',SSSGRD_TIME_WINDOW
          WRITE(IPT,*)'!  # SSSGRD_N_PER_INTERVAL  :',SSSGRD_N_PER_INTERVAL
          WRITE(IPT,*)''
       ELSE
          WRITE(IPT,*)'!  # SSSGRD_ASSIM           :  NOT ACTIVE'
          WRITE(IPT,*)''
       END IF

       IF(TSGRD_ASSIM)THEN
          WRITE(IPT,*)'!  # TSGRD_ASSIM           :  ACTIVE'
          WRITE(IPT,*)'!  # TSGRD_ASSIM_FILE      : '//TRIM(TSGRD_ASSIM_FILE)
          WRITE(IPT,*)'!  # TSGRD_TIMESCALE       :',TSGRD_TIMESCALE
          WRITE(IPT,*)'!  # TSGRD_WEIGHT_MAX      :',TSGRD_WEIGHT_MAX  
          WRITE(IPT,*)'!  # TSGRD_TIME_WINDOW (seconds)     :',TSGRD_TIME_WINDOW
          WRITE(IPT,*)'!  # TSGRD_N_PER_INTERVAL  :',TSGRD_N_PER_INTERVAL
          WRITE(IPT,*)''
       ELSE
          WRITE(IPT,*)'!  # TSGRD_ASSIM           :  NOT ACTIVE'
          WRITE(IPT,*)''
       END IF

       IF(TS_NGASSIM)THEN
          WRITE(IPT,*)'!  # TS_NGASSIM       :  ACTIVE'
          WRITE(IPT,*)'!  # TS_NGASSIM_FILE     : '//TRIM(TS_NGASSIM_FILE)
          WRITE(IPT,*)'!  # TS_NG_RADIUS           :',TS_NG_RADIUS
          WRITE(IPT,*)'!  # TS_GAMA             :',TS_GAMA
          WRITE(IPT,*)'!  # TS_GALPHA           :',TS_GALPHA   
!          WRITE(IPT,*)'!  # TS_WEIGHT_MAX      :',TS_WEIGHT_MAX
!          WRITE(IPT,*)'!  # TS_TIMESCALE       :',TS_TIMESCALE   
          WRITE(IPT,*)'!  # TS_NG_ASTIME_WINDOW(seconds)     :',TS_NG_ASTIME_WINDOW
          WRITE(IPT,*)''
       ELSE
          WRITE(IPT,*)'!  # TS_ASSIM           :  NOT ACTIVE'
          WRITE(IPT,*)''
       END IF

       IF(TS_OIASSIM)THEN
          WRITE(IPT,*)'!  # TS_OIASSIM          :  ACTIVE'
          WRITE(IPT,*)'!  # TS_OIASSIM_FILE     : '//TRIM(TS_OIASSIM_FILE)
          WRITE(IPT,*)'!  # TS_OI_RADIUS        :',TS_OI_RADIUS
          WRITE(IPT,*)'!  # TS_OIGALPHA         :',TS_OIGALPHA
          WRITE(IPT,*)'!  # TS_OI_ASTIME_WINDOW(seconds) :',TS_OI_ASTIME_WINDOW
!         WRITE(IPT,*)'!  # TS_MAX_LAYER        :',TS_MAX_LAYER
          WRITE(IPT,*)'!  # TS_N_INFLU          :',TS_N_INFLU
          WRITE(IPT,*)'!  # TS_NSTEP_OI         :',TS_NSTEP_OI
          WRITE(IPT,*)''
       ELSE
          WRITE(IPT,*)'!  # TS_OIASSIM         :  NOT ACTIVE'
          WRITE(IPT,*)''
       END IF
    END IF
    
    IF(SST_ASSIM .AND. SSTGRD_ASSIM) CALL FATAL_ERROR &
         & ('Using two kinds of sst assimilation does not make any sense!')

    IF(TS_NGASSIM .AND. TSGRD_ASSIM) CALL FATAL_ERROR &
         & ('Using two kinds of ts assimilation does not make any sense!')

    IF(TS_OIASSIM .AND. TSGRD_ASSIM) CALL FATAL_ERROR &
         & ('Using two kinds of ts assimilation does not make any sense!')

    IF(CUR_OIASSIM.AND.CUR_NGASSIM) CALL FATAL_ERROR &
         & ('Using two kinds of current assimilation does not make any sense!')

    IF(TS_OIASSIM .AND. TS_NGASSIM) CALL FATAL_ERROR &
         & ('Using two kinds of TS assimilation does not make any sense!')

    ! SET THE FVCOM RUN MODE BASED ON WHAT TYPE OF ASSIMILATION WE ARE DOING
!    IF(SST_ASSIM .OR. SSTGRD_ASSIM) THEN
!       FVCOM_RUN_MODE = FVCOM_NUDGE_AVG_SST
!    END IF
      
    ! SET THE FVCOM RUN MODE BASED ON WHAT TYPE OF ASSIMILATION WE ARE DOING
!    IF(TS_ASSIM .OR. TSGRD_ASSIM) THEN
!       FVCOM_RUN_MODE = FVCOM_NUDGE_AVG_TSGRD
!    END IF
 
!    IF(SST_ASSIM .OR. SSTGRD_ASSIM) THEN
!      FVCOM_RUN_MODE = FVCOM_NUDGE_ASSIM
!    END IF  

    FVCOM_RUN_MODE = FVCOM_NUDGE_OI_ASSIM

!    IF(CUR_ASSIM) THEN
!       IF(CUR_TIMESCALE * DTI >= 1.0_sp) CALL FATAL_ERROR &
!           ('The e-folding time scale for the cur nudging is to short for the model time step!') 
!    END IF

    IF(CUR_NGASSIM) THEN
       IF(CUR_GALPHA * DTI >= 1.0_sp) CALL FATAL_ERROR &
           ('The e-folding time scale for the cur nudging is to short for the model time step!') 
    END IF
           
    IF(SST_ASSIM) THEN

       IF (SST_TIMESCALE * DTI >= 1.0_sp) CALL FATAL_ERROR &
            ('The efolding time scale for the sst nudging is to short for the model time step!') 

    ELSE IF(SSTGRD_ASSIM) THEN
       IF (SSTGRD_TIMESCALE * DTI >= 1.0_sp) CALL FATAL_ERROR &
            ('The efolding time scale for the sst nudging is to short for the model time step!') 

    END IF

    IF(SSSGRD_ASSIM) THEN
       IF (SSSGRD_TIMESCALE * DTI >= 1.0_sp) CALL FATAL_ERROR &
            ('The efolding time scale for the sss nudging is to short for the model time step!') 

    END IF

    IF(TS_NGASSIM) THEN
       IF(TS_GALPHA * DTI >= 1.0_sp) CALL FATAL_ERROR &
           ('The e-folding time scale for the TS nudging is to short for the model time step!') 
    END IF
           
!    IF(TS_NGASSIM) THEN
!
!       IF (TS_TIMESCALE * DTI >= 1.0_sp) CALL FATAL_ERROR &
!            ('The efolding time scale for the TS nudging is to short for the model time step!') 
!
!    ELSE IF(TSGRD_ASSIM) THEN
     IF(TSGRD_ASSIM) THEN
       IF (TSGRD_TIMESCALE * DTI >= 1.0_sp) CALL FATAL_ERROR &
            ('The efolding time scale for the TS nudging is to short for the model time step!') 

    END IF

!---> Siqi Li, intel23@20240220 Check values of TS_NSTEP_OI and CUR_NSTEP_OI
    IF (TS_OIASSIM .AND. TS_NSTEP_OI==0.) CALL FATAL_ERROR &
            ('TS_NSTEP_OI CANNOT BE 0.0 WHEN TS_OIASSIM IS APPLIED.')
    IF (.NOT. TS_OIASSIM) TS_NSTEP_OI = -1.0
    IF (CUR_OIASSIM .AND. CUR_NSTEP_OI==0.) CALL FATAL_ERROR &
            ('CUR_NSTEP_OI CANNOT BE 0.0 WHEN CUR_OIASSIM IS APPLIED.')
    IF (.NOT. CUR_OIASSIM) CUR_NSTEP_OI = -1.0
!<--- Siqi Li

    IF (DBG_SET(DBG_SBR)) WRITE(IPT,*) "END: SET_ASSIM_PARAM"

    RETURN
  END SUBROUTINE SET_ASSIM_PARAM
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|

!==============================================================================!
  SUBROUTINE SETUP_DATA_ASSIMILATION
!==============================================================================!
    IMPLICIT NONE

    IF(DBG_SET(DBG_LOG)) WRITE(IPT,*) "START SETUP_DATA_ASSIMILATION"

    IF(SST_ASSIM) THEN

       ALLOCATE(ASSIM_SST)
       ASSIM_SST%RADIUS     = SST_RADIUS
       ASSIM_SST%WEIGHT_MAX = SST_WEIGHT_MAX
       ASSIM_SST%TIMESCALE  = SST_TIMESCALE
       ASSIM_SST%TIME_WINDOW= SST_TIME_WINDOW
       
       CALL OPEN_SST_ASSIM(ASSIM_SST%FILE)

       ALLOCATE(ASSIM_SST%OBS_LOC)
       ALLOCATE(ASSIM_SST%OBS_DAT)

       CALL LOAD_SST_ASSIM


    END IF

    IF(SSTGRD_ASSIM) THEN
       CALL OPEN_SSTGRD_ASSIM

       CALL SET_SSTGRD_ASSIM
    END IF

    IF(SSSGRD_ASSIM) THEN
       CALL OPEN_SSSGRD_ASSIM

       CALL SET_SSSGRD_ASSIM
    END IF

    IF(SSHGRD_ASSIM) THEN
       CALL OPEN_SSHGRD_ASSIM
       CALL SET_SSHGRD_ASSIM
    END IF

    IF(TSGRD_ASSIM) THEN
       CALL OPEN_TSGRD_ASSIM
       CALL SET_TSGRD_ASSIM
       CALL SET_MONTHLY_TS_MEAN(NC_TSAVG_ASSIM)

       IF(DBG_SET(DBG_LOG)) WRITE(IPT,*) "SETUP ASSIMULTION RSTFILE"
       CALL SETUP_RSTFILE_ASSIM
    END IF

!    IF(TS_ASSIM) THEN
!       CALL OPEN_TS_ASSIM(ASSIM_SST%FILE)
!
!       CALL SET_TS_ASSIM
!    END IF

!    IF(CUR_ASSIM) THEN
!       CALL OPEN_CUR_ASSIM(ASSIM_SST%FILE)

!       CALL SET_CUR_ASSIM
!    END IF

!qxu{ 
    IF(TS_NGASSIM .OR. TS_OIASSIM) CALL SET_TS_ASSIM_DATA
    IF(CUR_NGASSIM .OR. CUR_OIASSIM) CALL SET_CUR_ASSIM_DATA
!qxu}

    IF(DBG_SET(DBG_LOG)) WRITE(IPT,*) "END SETUP_DATA_ASSIMILATION"
  END SUBROUTINE SETUP_DATA_ASSIMILATION
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|

!==============================================================================!
  SUBROUTINE OPEN_SST_ASSIM(NCF)
!==============================================================================!
    IMPLICIT NONE
    TYPE(NCFILE), POINTER :: NCF,NCT
    character(len=160) :: pathnfile
    
    pathnfile= trim(INPUT_DIR)//trim(SST_ASSIM_FILE)
    
    
    ! INITIALIZE TYPE TO HOLD FILE METADATA
    
    CALL NC_INIT(NCF,pathnfile)
    
!!$    ! OPEN THE FILE AND LOAD METADATA       
!!$    If(.not. NCF%OPEN) then
!!$       Call NC_OPEN(NCF)
!!$       CALL NC_LOAD(NCF)
!!$       NCT => NCF
!!$       FILEHEAD => ADD(FILEHEAD,NCT)
!!$    end if
    
  END SUBROUTINE OPEN_SST_ASSIM
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|

!==============================================================================!
  SUBROUTINE OPEN_SSTGRD_ASSIM
!==============================================================================!
    IMPLICIT NONE
    TYPE(NCFILE), POINTER :: NCF
    integer :: charnum
    logical :: fexist,back
    character(len=160) :: pathnfile
    
    ! INITIALIZE TYPE TO HOLD FILE METADATA
    pathnfile= trim(INPUT_DIR)//trim(SSTGRD_ASSIM_FILE)

    CALL NC_INIT(NCF,pathnfile)
    
    ! OPEN THE FILE AND LOAD METADATA       
    If(.not. NCF%OPEN) then
       Call NC_OPEN(NCF)
       CALL NC_LOAD(NCF)
       FILEHEAD => ADD(FILEHEAD,NCF)
    end if

  END SUBROUTINE OPEN_SSTGRD_ASSIM
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|

!==============================================================================!
  SUBROUTINE OPEN_SSSGRD_ASSIM
!==============================================================================!
    IMPLICIT NONE
    TYPE(NCFILE), POINTER :: NCF
    integer :: charnum
    logical :: fexist,back
    character(len=160) :: pathnfile
    
    ! INITIALIZE TYPE TO HOLD FILE METADATA
    pathnfile= trim(INPUT_DIR)//trim(SSSGRD_ASSIM_FILE)

    CALL NC_INIT(NCF,pathnfile)
    
    ! OPEN THE FILE AND LOAD METADATA       
    If(.not. NCF%OPEN) then
       Call NC_OPEN(NCF)
       CALL NC_LOAD(NCF)
       FILEHEAD => ADD(FILEHEAD,NCF)
    end if

  END SUBROUTINE OPEN_SSSGRD_ASSIM
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|

!==============================================================================!
  SUBROUTINE OPEN_SSHGRD_ASSIM
!==============================================================================!
    IMPLICIT NONE
    TYPE(NCFILE), POINTER :: NCF
    integer :: charnum
    logical :: fexist,back
    character(len=160) :: pathnfile
    
    ! INITIALIZE TYPE TO HOLD FILE METADATA
    pathnfile= trim(INPUT_DIR)//trim(SSHGRD_ASSIM_FILE)

    CALL NC_INIT(NCF,pathnfile)
    
    ! OPEN THE FILE AND LOAD METADATA       
    If(.not. NCF%OPEN) then
       Call NC_OPEN(NCF)
       CALL NC_LOAD(NCF)
       FILEHEAD => ADD(FILEHEAD,NCF)
    end if

  END SUBROUTINE OPEN_SSHGRD_ASSIM

!==============================================================================!
  SUBROUTINE OPEN_TSGRD_ASSIM
!==============================================================================!
    IMPLICIT NONE
    TYPE(NCFILE), POINTER :: NCF
    integer :: charnum
    logical :: fexist,back
    character(len=160) :: pathnfile
    
    ! INITIALIZE TYPE TO HOLD FILE METADATA
    pathnfile= trim(INPUT_DIR)//trim(TSGRD_ASSIM_FILE)

    CALL NC_INIT(NCF,pathnfile)
   
    ! OPEN THE FILE AND LOAD METADATA       
    If(.not. NCF%OPEN) then
       Call NC_OPEN(NCF)
       CALL NC_LOAD(NCF)
       FILEHEAD => ADD(FILEHEAD,NCF)
    end if

  END SUBROUTINE OPEN_TSGRD_ASSIM


!==============================================================================!
!  SUBROUTINE OPEN_CUR_ASSIM(NCF)
!==============================================================================!
!    IMPLICIT NONE
!    TYPE(NCFILE), POINTER :: NCF,NCT
!    character(len=160) :: pathnfile
    
!    pathnfile= trim(INPUT_DIR)//trim(CUR_NGASSIM_FILE)
    
    
!    ! INITIALIZE TYPE TO HOLD FILE METADATA
    
!    CALL NC_INIT(NCF,pathnfile)
    
!!$    ! OPEN THE FILE AND LOAD METADATA       
!!$    If(.not. NCF%OPEN) then
!!$       Call NC_OPEN(NCF)
!!$       CALL NC_LOAD(NCF)
!!$       NCT => NCF
!!$       FILEHEAD => ADD(FILEHEAD,NCT)
!!$    end if


!  END SUBROUTINE OPEN_CUR_ASSIM
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|

!==============================================================================!
!  SUBROUTINE OPEN_TS_ASSIM(NCF)
!==============================================================================!
!    IMPLICIT NONE
!    TYPE(NCFILE), POINTER :: NCF,NCT
!    character(len=160) :: pathnfile
    
!    pathnfile= trim(INPUT_DIR)//trim(TS_NGASSIM_FILE)
    
    
!    ! INITIALIZE TYPE TO HOLD FILE METADATA
    
!    CALL NC_INIT(NCF,pathnfile)
    
!!$    ! OPEN THE FILE AND LOAD METADATA       
!!$    If(.not. NCF%OPEN) then
!!$       Call NC_OPEN(NCF)
!!$       CALL NC_LOAD(NCF)
!!$       NCT => NCF
!!$       FILEHEAD => ADD(FILEHEAD,NCT)
!!$    end if

!  END SUBROUTINE OPEN_TS_ASSIM
!==============================================================================|

   SUBROUTINE LOAD_SST_ASSIM
     IMPLICIT NONE

     INTEGER I,TCNT,NCNT
     CHARACTER(LEN=160) :: FNAME
     LOGICAL :: FEXIST
     REAL(SP):: TEMPF
     INTEGER,  ALLOCATABLE, DIMENSION(:) :: ITEMP
     REAL(SP), ALLOCATABLE, DIMENSION(:) :: FTEMP
     REAL(SP):: X0,Y0,T0

     INTEGER J,K,ECNT,ITMP,IOS
     REAL(SP)::DX,DY,RD
       
!------------------------------------------------------------------------------!
       
     FNAME = ASSIM_SST%FILE%FNAME
!
!--Make Sure SST Assimilation Data File Exists---------------------------------!
!
   INQUIRE(FILE=TRIM(FNAME),EXIST=FEXIST)
   IF(.NOT.FEXIST)THEN
      CALL FATAL_ERROR('THE SST OBSERVATION FILE: ',&
           & TRIM(FNAME),&
           &' DOES NOT EXIST')
   END IF
     
!
!--Read Number SST Measurements and Data Set Size------------------------------!
!


   OPEN(1,FILE=TRIM(FNAME),STATUS='OLD') ; REWIND(1)
   READ(1,*) TCNT
   READ(1,*) TEMPF,NCNT


   ASSIM_SST%OBS_LOC%N_TIMES = TCNT
   ASSIM_SST%OBS_LOC%N_LOCS  = NCNT

   ALLOCATE(ASSIM_SST%OBS_LOC%X(NCNT,TCNT))
   ALLOCATE(ASSIM_SST%OBS_LOC%Y(NCNT,TCNT))
   ALLOCATE(ASSIM_SST%OBS_LOC%OBSTIME(TCNT))

   ALLOCATE(ASSIM_SST%OBS_DAT%DATA(NCNT,TCNT))
   ALLOCATE(ASSIM_SST%OBS_DAT%MASK(NCNT,TCNT))

   REWIND(1)  ; READ(1,*)
   
!
!--Read SST Data---------------------------------------------------------------!
!
   DO I=1,TCNT
     READ(1,*) TEMPF,NCNT 
     DO J=1,NCNT
       READ(1,*) X0,Y0,T0
       ASSIM_SST%OBS_LOC%X(J,I)=X0
       ASSIM_SST%OBS_LOC%Y(J,I)=Y0

       ASSIM_SST%OBS_DAT%DATA(J,I)=T0

       ASSIM_SST%OBS_LOC%OBSTIME(I) = SECONDS2TIME(TEMPF)

     END DO
   END DO

!
!--Close SST Observation Data File---------------------------------------------!
!
   CLOSE(1)

!
!--Shift Coordinates-of SST Observation Locations------------------------------!
!
   ASSIM_SST%OBS_LOC%X = ASSIM_SST%OBS_LOC%X - VXMIN
   ASSIM_SST%OBS_LOC%Y = ASSIM_SST%OBS_LOC%Y - VYMIN


   ASSIM_SST%OBS_LOC%OBSTIME = ASSIM_SST%OBS_LOC%OBSTIME + RUNFILE_StartTime


   END SUBROUTINE LOAD_SST_ASSIM
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   SUBROUTINE SET_SSTGRD_ASSIM
!------------------------------------------------------------------------------!
!  SET UP ASSIMILATION DATA FOR SST OBSERVATIONS                               |
!------------------------------------------------------------------------------!

   IMPLICIT NONE
   INTEGER I
   REAL(DP) :: TEMP      
   ! SOME NC POINTERS

   TYPE(NCATT), POINTER :: ATT
   TYPE(NCDIM), POINTER :: DIM
   TYPE(NCVAR), POINTER :: VAR
   
   ! SOME HANDY VARIABLES TO PLAY WITH
   LOGICAL FOUND  
   TYPE(TIME) :: FSTART, FEND,TCNT,ONEDAY
   !------------------------------------------------------------------------------!
       
   ! GET THE FILE POINTER
   SST_FILE => FIND_FILE(FILEHEAD,trim(SSTGRD_ASSIM_FILE),FOUND)
   IF(.not. FOUND) CALL FATAL_ERROR &
        & ("COULD NOT FIND SSTGRD_ASSIM_FILE FILE OBJECT",&
        & "FILE NAME: "//TRIM(SSTGRD_ASSIM_FILE))
   
   ! CHECK THE ATTRIBUTES
   ATT => FIND_ATT(SST_FILE,"source",FOUND)
   IF(.not. FOUND) CALL FATAL_ERROR &
        & ("IN SST_ASSIMGRD_FILE FILE OBJECT",&
        & "FILE NAME: "//TRIM(SSTGRD_ASSIM_FILE),&
        &"COULD NOT FIND GLOBAL ATTRIBURE: 'source'")
   
   IF(ATT%CHR(1)(1:5) /= "FVCOM") CALL FATAL_ERROR &
        &('IN SSTGRD_ASSIM_FILE FILE OBJECT',&
        & "FILE NAME: "//TRIM(SSTGRD_ASSIM_FILE),&
        & "THE GLOBAL ATTRIBURE 'source' SHOULD BE 'FVCOM' ")
   
   ! LOOK FOR THE DIMENSIONS 
   DIM => FIND_DIM(SST_FILE,'node',FOUND) ! NODE
   IF(.not. FOUND) CALL FATAL_ERROR &
        & ("IN SSTGRD_ASSIM_FILE OBJECT",&
        & "FILE NAME: "//TRIM(SSTGRD_ASSIM_FILE),&
        &"COULD NOT FIND DIMENSION 'node'")
   
   IF (DIM%DIM /= MGL) CALL FATAL_ERROR&
        & ("THE NUMBER OF NODES IN THE SST GRID ASSIM FILE DOES NOT MATCH THE GRID FILE!")
   
   DIM => FIND_DIM(SST_FILE,'time',FOUND) ! TIME
   IF(.not. FOUND) CALL FATAL_ERROR &
        & ("IN SSTGRD_ASSIM_FILE OBJECT",&
        & "FILE NAME: "//TRIM(SSTGRD_ASSIM_FILE),&
        &"COULD NOT FIND DIMENSION 'time'")
   
   N_TIMES_SST = DIM%DIM ! SET THE VARIABLE VALUE
   
   ONEDAY = days2time(1.0_DP)
   
   ! CHECK THE BEGIN TIME
   FSTART = GET_FILE_TIME(SST_FILE,1)
   
   IF (FSTART > STARTTIME + oneday/2) THEN
      IF(DBG_SET(DBG_LOG)) THEN
         CALL PRINT_REAL_TIME(FSTART,IPT,"FIRST TIME IN SST GRID ASSIM FILE")
         CALL PRINT_REAL_TIME(STARTTIME,IPT,"MODEL START TIME")
      END IF
      CALL FATAL_ERROR("THE SST GRID ASSIM START TIME IS INCORRECT",&
           & "THE MODEL STARTS MORE THAN 12 HOURS BEFORE THE FIRST SST DATA")
   END IF
   
   ! CHECK THE END TIME
   FEND = GET_FILE_TIME(SST_FILE,N_TIMES_SST)
   
   IF (FEND < ENDTIME - oneday/2) THEN
      IF(DBG_SET(DBG_LOG)) THEN
         CALL PRINT_REAL_TIME(FEND,IPT,"LAST TIME IN SST GRID ASSIM FILE")
         CALL PRINT_REAL_TIME(ENDTIME,IPT,"MODEL END TIME")
      END IF
      CALL FATAL_ERROR("THE SST GRID ASSIM END TIME IS INCORRECT",&
           & "THE MODEL ENDS MORE THAN 12 HOURS AFTER THE LAST SST DATA")
   END IF
   
   ! CHECK THE FILE INTERVAL - EXPECTING DAILY DATA
   TCNT = FSTART + ONEDAY *(N_TIMES_SST-1)
   
   IF (.NOT. FEND == TCNT) THEN
      IF(DBG_SET(DBG_LOG)) THEN
         CALL PRINT_REAL_TIME(FEND,IPT,"LAST TIME IN SST GRID ASSIM FILE")
         CALL PRINT_REAL_TIME(TCNT,IPT,"EXPECTED END TIME FOR DAILY DATA")
      END IF
      CALL FATAL_ERROR("THE SST GRID ASSIM FILE TIME STEP IS NOT DAILY",&
           & "THE START TIME PLUS NUMBER OF DAYS IN THE FILE DOES N&
           &OT EQUAL THE END TIME?")
   END IF
   
   ! GET INTERVAL FOR SAVING SST STATE 
   SST_SAVE_INTERVAL = ONEDAY / SSTGRD_N_PER_INTERVAL

   ! ALLOCATE MEMORY
   ALLOCATE(SST_OBS(M))   
   ALLOCATE(SST_AVG(M))
   ALLOCATE(SST_SAVED(M,1:SSTGRD_N_PER_INTERVAL))
! lwang added for SST mld assimilation
   IF (SSTGRD_MLD)THEN
      ALLOCATE(T_SAVED(M,KBM1,1:SSTGRD_N_PER_INTERVAL))
      ALLOCATE(S_SAVED(M,KBM1,1:SSTGRD_N_PER_INTERVAL))
      ALLOCATE(TT_AVG(M,KBM1))
      ALLOCATE(SS_AVG(M,KBM1))
      ALLOCATE(RHO_AVG(M,KBM1))
      ALLOCATE(MLD_RHO(M))
   END IF
! lwang
# if defined (ENKF)
   ALLOCATE(SST_AVG_ENKF(M,ENKF_NENS))
   ALLOCATE(SST_SAVED_ENKF(M,1:SSTGRD_N_PER_INTERVAL,ENKF_NENS))
# endif

   VAR => FIND_VAR(SST_FILE,'sst',FOUND)
   IF (.NOT.FOUND) CALL FATAL_ERROR &
        ("THE VARIABLE 'sst' IS MISSING FROM THE SSTGRD_ASSIM FILE?")

   CALL NC_CONNECT_AVAR(VAR,SST_OBS)
   VAR_SST =>VAR
   

   ! SET THE FILE STACK COUNT
   ! LOOK FOR TIME WITHIN ONE DTI OF MID-DAY

   FSTART = StartTime + ONEDAY/2

   DO I =1 ,N_TIMES_SST

      TCNT = GET_FILE_TIME(SST_FILE,I)

      ! IF TIME IS BEFORE MID POINT THE FIRST DAY
      IF (TCNT < FSTART - IMDTI) CYCLE
      
      ! IF IT IS ALSO LESS THEN THIS
      IF (TCNT < FSTART + IMDTI) THEN
         ! WE FOUND IT
         SST_FILE%FTIME%NEXT_STKCNT = I
         EXIT

      ELSE ! THRE IS NO VALID TIME IN THE FILE

         CALL FATAL_ERROR &
              & ("THERE IS NO VALID FIRST TIME IN THE SST OBSERVATION FILE")
      END IF
   END DO


   RETURN
   END SUBROUTINE SET_SSTGRD_ASSIM
!==============================================================================|
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   SUBROUTINE SET_SSSGRD_ASSIM
!------------------------------------------------------------------------------!
!  SET UP ASSIMILATION DATA FOR SSS OBSERVATIONS                               |
!------------------------------------------------------------------------------!

   IMPLICIT NONE
   INTEGER I
   REAL(DP) :: TEMP      
   ! SOME NC POINTERS

   TYPE(NCATT), POINTER :: ATT
   TYPE(NCDIM), POINTER :: DIM
   TYPE(NCVAR), POINTER :: VAR
   
   ! SOME HANDY VARIABLES TO PLAY WITH
   LOGICAL FOUND  
   TYPE(TIME) :: FSTART, FEND,TCNT,ONEDAY
   !------------------------------------------------------------------------------!
       
   ! GET THE FILE POINTER
   SSS_FILE => FIND_FILE(FILEHEAD,trim(SSSGRD_ASSIM_FILE),FOUND)
   IF(.not. FOUND) CALL FATAL_ERROR &
        & ("COULD NOT FIND SSSGRD_ASSIM_FILE FILE OBJECT",&
        & "FILE NAME: "//TRIM(SSSGRD_ASSIM_FILE))
   
   ! CHECK THE ATTRIBUTES
   ATT => FIND_ATT(SSS_FILE,"source",FOUND)
   IF(.not. FOUND) CALL FATAL_ERROR &
        & ("IN SSS_ASSIMGRD_FILE FILE OBJECT",&
        & "FILE NAME: "//TRIM(SSSGRD_ASSIM_FILE),&
        &"COULD NOT FIND GLOBAL ATTRIBURE: 'source'")
   
   IF(ATT%CHR(1)(1:5) /= "FVCOM") CALL FATAL_ERROR &
        &('IN SSSGRD_ASSIM_FILE FILE OBJECT',&
        & "FILE NAME: "//TRIM(SSSGRD_ASSIM_FILE),&
        & "THE GLOBAL ATTRIBURE 'source' SHOULD BE 'FVCOM' ")
   
   ! LOOK FOR THE DIMENSIONS 
   DIM => FIND_DIM(SSS_FILE,'node',FOUND) ! NODE
   IF(.not. FOUND) CALL FATAL_ERROR &
        & ("IN SSSGRD_ASSIM_FILE OBJECT",&
        & "FILE NAME: "//TRIM(SSSGRD_ASSIM_FILE),&
        &"COULD NOT FIND DIMENSION 'node'")
   
   IF (DIM%DIM /= MGL) CALL FATAL_ERROR&
        & ("THE NUMBER OF NODES IN THE SSS GRID ASSIM FILE DOES NOT MATCH THE GRID FILE!")
   
   DIM => FIND_DIM(SSS_FILE,'time',FOUND) ! TIME
   IF(.not. FOUND) CALL FATAL_ERROR &
        & ("IN SSSGRD_ASSIM_FILE OBJECT",&
        & "FILE NAME: "//TRIM(SSSGRD_ASSIM_FILE),&
        &"COULD NOT FIND DIMENSION 'time'")
   
   N_TIMES_SSS = DIM%DIM ! SET THE VARIABLE VALUE
   
   ONEDAY = days2time(1.0_DP)
   
   ! CHECK THE BEGIN TIME
   FSTART = GET_FILE_TIME(SSS_FILE,1)
   
   IF (FSTART > STARTTIME + oneday/2) THEN
      IF(DBG_SET(DBG_LOG)) THEN
         CALL PRINT_REAL_TIME(FSTART,IPT,"FIRST TIME IN SSS GRID ASSIM FILE")
         CALL PRINT_REAL_TIME(STARTTIME,IPT,"MODEL START TIME")
      END IF
      CALL FATAL_ERROR("THE SSS GRID ASSIM START TIME IS INCORRECT",&
           & "THE MODEL STARTS MORE THAN 12 HOURS BEFORE THE FIRST SSS DATA")
   END IF
   
   ! CHECK THE END TIME
   FEND = GET_FILE_TIME(SSS_FILE,N_TIMES_SSS)
   
   IF (FEND < ENDTIME - oneday/2) THEN
      IF(DBG_SET(DBG_LOG)) THEN
         CALL PRINT_REAL_TIME(FEND,IPT,"LAST TIME IN SSS GRID ASSIM FILE")
         CALL PRINT_REAL_TIME(ENDTIME,IPT,"MODEL END TIME")
      END IF
      CALL FATAL_ERROR("THE SSS GRID ASSIM END TIME IS INCORRECT",&
           & "THE MODEL ENDS MORE THAN 12 HOURS AFTER THE LAST SSS DATA")
   END IF
   
   ! CHECK THE FILE INTERVAL - EXPECTING DAILY DATA
   TCNT = FSTART + ONEDAY *(N_TIMES_SSS-1)
   
   IF (.NOT. FEND == TCNT) THEN
      IF(DBG_SET(DBG_LOG)) THEN
         CALL PRINT_REAL_TIME(FEND,IPT,"LAST TIME IN SSS GRID ASSIM FILE")
         CALL PRINT_REAL_TIME(TCNT,IPT,"EXPECTED END TIME FOR DAILY DATA")
      END IF
      CALL FATAL_ERROR("THE SSS GRID ASSIM FILE TIME STEP IS NOT DAILY",&
           & "THE START TIME PLUS NUMBER OF DAYS IN THE FILE DOES N&
           &OT EQUAL THE END TIME?")
   END IF
   
   ! GET INTERVAL FOR SAVING SSS STATE 
   SSS_SAVE_INTERVAL = ONEDAY / SSSGRD_N_PER_INTERVAL

   ! ALLOCATE MEMORY
   ALLOCATE(SSS_OBS(M))   
   ALLOCATE(SSS_AVG(M))
   ALLOCATE(SSS_SAVED(M,1:SSSGRD_N_PER_INTERVAL))
   ALLOCATE(SSS_WEIGHT(M))
! lwang added for SSS mld assimilation
!   IF (SSTGRD_MLD)THEN
!      ALLOCATE(T_SAVED(M,KBM1,1:SSSGRD_N_PER_INTERVAL))
!      ALLOCATE(S_SAVED(M,KBM1,1:SSSGRD_N_PER_INTERVAL))
!      ALLOCATE(TT_AVG(M,KBM1))
!      ALLOCATE(SS_AVG(M,KBM1))
!      ALLOCATE(RHO_AVG(M,KBM1))
!      ALLOCATE(MLD_RHO(M))
!   END IF
! lwang
# if defined (ENKF)
   ALLOCATE(SSS_AVG_ENKF(M,ENKF_NENS))
   ALLOCATE(SSS_SAVED_ENKF(M,1:SSSGRD_N_PER_INTERVAL,ENKF_NENS))
# endif

   VAR => FIND_VAR(SSS_FILE,'sss',FOUND)
   IF (.NOT.FOUND) CALL FATAL_ERROR &
        ("THE VARIABLE 'sss' IS MISSING FROM THE SSSGRD_ASSIM FILE?")

   CALL NC_CONNECT_AVAR(VAR,SSS_OBS)
   VAR_SSS =>VAR
   

   VAR => FIND_VAR(SSS_FILE,'weight',FOUND)
   IF (.NOT.FOUND) CALL FATAL_ERROR &
        ("THE VARIABLE 'weight' IS MISSING FROM THE SSSGRD_ASSIM FILE?")

   CALL NC_CONNECT_AVAR(VAR,SSS_WEIGHT)
   CALL NC_READ_VAR(VAR)
   CALL NC_DISCONNECT(VAR)
   

   ! SET THE FILE STACK COUNT
   ! LOOK FOR TIME WITHIN ONE DTI OF MID-DAY

   FSTART = StartTime + ONEDAY/2

   DO I =1 ,N_TIMES_SSS

      TCNT = GET_FILE_TIME(SSS_FILE,I)

      ! IF TIME IS BEFORE MID POINT THE FIRST DAY
      IF (TCNT < FSTART - IMDTI) CYCLE
      
      ! IF IT IS ALSO LESS THEN THIS
      IF (TCNT < FSTART + IMDTI) THEN
         ! WE FOUND IT
         SSS_FILE%FTIME%NEXT_STKCNT = I
         EXIT

      ELSE ! THRE IS NO VALID TIME IN THE FILE

         CALL FATAL_ERROR &
              & ("THERE IS NO VALID FIRST TIME IN THE SSS OBSERVATION FILE")
      END IF
   END DO


   RETURN
   END SUBROUTINE SET_SSSGRD_ASSIM
!==============================================================================|

   SUBROUTINE SET_SSHGRD_ASSIM
!------------------------------------------------------------------------------!
!  SET UP ASSIMILATION DATA FOR SST OBSERVATIONS                               |
!------------------------------------------------------------------------------!

   IMPLICIT NONE
   INTEGER I
   REAL(DP) :: TEMP      
   ! SOME NC POINTERS

   TYPE(NCATT), POINTER :: ATT
   TYPE(NCDIM), POINTER :: DIM
   TYPE(NCVAR), POINTER :: VAR
   
   ! SOME HANDY VARIABLES TO PLAY WITH
   LOGICAL FOUND  
   TYPE(TIME) :: FSTART, FEND,TCNT,ONEDAY
   !------------------------------------------------------------------------------!
       
   ! GET THE FILE POINTER
   SSH_FILE => FIND_FILE(FILEHEAD,trim(SSHGRD_ASSIM_FILE),FOUND)
   IF(.not. FOUND) CALL FATAL_ERROR &
        & ("COULD NOT FIND SSHGRD_ASSIM_FILE FILE OBJECT",&
        & "FILE NAME: "//TRIM(SSHGRD_ASSIM_FILE))
   
   ! CHECK THE ATTRIBUTES
   ATT => FIND_ATT(SSH_FILE,"source",FOUND)
   IF(.not. FOUND) CALL FATAL_ERROR &
        & ("IN SSH_ASSIMGRD_FILE FILE OBJECT",&
        & "FILE NAME: "//TRIM(SSHGRD_ASSIM_FILE),&
        &"COULD NOT FIND GLOBAL ATTRIBURE: 'source'")
   
   IF(ATT%CHR(1)(1:5) /= "FVCOM") CALL FATAL_ERROR &
        &('IN SSHGRD_ASSIM_FILE FILE OBJECT',&
        & "FILE NAME: "//TRIM(SSHGRD_ASSIM_FILE),&
        & "THE GLOBAL ATTRIBURE 'source' SHOULD BE 'FVCOM' ")
   
   ! LOOK FOR THE DIMENSIONS 
   DIM => FIND_DIM(SSH_FILE,'node',FOUND) ! NODE
   IF(.not. FOUND) CALL FATAL_ERROR &
        & ("IN SSHGRD_ASSIM_FILE OBJECT",&
        & "FILE NAME: "//TRIM(SSHGRD_ASSIM_FILE),&
        &"COULD NOT FIND DIMENSION 'node'")
   
   IF (DIM%DIM /= MGL) CALL FATAL_ERROR&
        & ("THE NUMBER OF NODES IN THE SSH GRID ASSIM FILE DOES NOT MATCH THE GRID FILE!")
   
   DIM => FIND_DIM(SSH_FILE,'time',FOUND) ! TIME
   IF(.not. FOUND) CALL FATAL_ERROR &
        & ("IN SSHGRD_ASSIM_FILE OBJECT",&
        & "FILE NAME: "//TRIM(SSHGRD_ASSIM_FILE),&
        &"COULD NOT FIND DIMENSION 'time'")
   
   N_TIMES_SSH = DIM%DIM ! SET THE VARIABLE VALUE
   
   ONEDAY = days2time(1.0_DP)
   
   ! CHECK THE BEGIN TIME
   FSTART = GET_FILE_TIME(SSH_FILE,1)
   
   IF (FSTART > STARTTIME + oneday/2) THEN
      IF(DBG_SET(DBG_LOG)) THEN
         CALL PRINT_REAL_TIME(FSTART,IPT,"FIRST TIME IN SSH GRID ASSIM FILE")
         CALL PRINT_REAL_TIME(STARTTIME,IPT,"MODEL START TIME")
      END IF
      CALL FATAL_ERROR("THE SSH GRID ASSIM START TIME IS INCORRECT",&
           & "THE MODEL STARTS MORE THAN 12 HOURS BEFORE THE FIRST SSH DATA")
   END IF
   
   ! CHECK THE END TIME
   FEND = GET_FILE_TIME(SSH_FILE,N_TIMES_SSH)
   
   IF (FEND < ENDTIME - oneday/2) THEN
      IF(DBG_SET(DBG_LOG)) THEN
         CALL PRINT_REAL_TIME(FEND,IPT,"LAST TIME IN SSH GRID ASSIM FILE")
         CALL PRINT_REAL_TIME(ENDTIME,IPT,"MODEL END TIME")
      END IF
      CALL FATAL_ERROR("THE SSH GRID ASSIM END TIME IS INCORRECT",&
           & "THE MODEL ENDS MORE THAN 12 HOURS AFTER THE LAST SSH DATA")
   END IF
   
   ! CHECK THE FILE INTERVAL - EXPECTING DAILY DATA
   TCNT = FSTART + ONEDAY *(N_TIMES_SSH-1)

   IF (.NOT. FEND == TCNT) THEN
      IF(DBG_SET(DBG_LOG)) THEN
         CALL PRINT_REAL_TIME(FEND,IPT,"LAST TIME IN SSH GRID ASSIM FILE")
         CALL PRINT_REAL_TIME(TCNT,IPT,"EXPECTED END TIME FOR DAILY DATA")
      END IF
      CALL FATAL_ERROR("THE SSH GRID ASSIM FILE TIME STEP IS NOT DAILY",&
           & "THE START TIME PLUS NUMBER OF DAYS IN THE FILE DOES N&
           &OT EQUAL THE END TIME?")
   END IF
   
   ! GET INTERVAL FOR SAVING SST STATE 
   SSH_SAVE_INTERVAL = ONEDAY / SSHGRD_N_PER_INTERVAL

   ! ALLOCATE MEMORY
   ALLOCATE(SSH_OBS(M))   
   ALLOCATE(SSH_AVG(M))
   ALLOCATE(SSH_SAVED(M,0:SSHGRD_N_PER_INTERVAL))
#  if defined (ENKF)
   ALLOCATE(SSH_AVG_ENKF(M,ENKF_NENS))
   ALLOCATE(SSH_SAVED_ENKF(M,1:SSTGRD_N_PER_INTERVAL,ENKF_NENS))
#  endif   

   VAR => FIND_VAR(SSH_FILE,'ssh',FOUND)
   IF (.NOT.FOUND) CALL FATAL_ERROR &
        ("THE VARIABLE 'ssh' IS MISSING FROM THE SSHGRD_ASSIM FILE?")

   CALL NC_CONNECT_AVAR(VAR,SSH_OBS)
   VAR_SSH =>VAR
   

   ! SET THE FILE STACK COUNT
   ! LOOK FOR TIME WITHIN ONE DTI OF MID-DAY

   FSTART = StartTime + ONEDAY/2

   DO I =1 ,N_TIMES_SSH

      TCNT = GET_FILE_TIME(SSH_FILE,I)

      ! IF TIME IS BEFORE MID POINT THE FIRST DAY
      IF (TCNT < FSTART - IMDTI) CYCLE
      
      ! IF IT IS ALSO LESS THEN THIS
      IF (TCNT < FSTART + IMDTI) THEN
         ! WE FOUND IT
         SSH_FILE%FTIME%NEXT_STKCNT = I
         EXIT

      ELSE ! THRE IS NO VALID TIME IN THE FILE

         CALL FATAL_ERROR &
              & ("THERE IS NO VALID FIRST TIME IN THE SSH OBSERVATION FILE")
      END IF
   END DO


   RETURN
 END SUBROUTINE SET_SSHGRD_ASSIM

!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   SUBROUTINE SET_TSGRD_ASSIM
!------------------------------------------------------------------------------!
!  SET UP ASSIMILATION DATA FOR TS OBSERVATIONS                               |
!------------------------------------------------------------------------------!

   IMPLICIT NONE
   INTEGER I
   REAL(DP) :: TEMP      
   ! SOME NC POINTERS

   TYPE(NCATT), POINTER :: ATT
   TYPE(NCDIM), POINTER :: DIM
   TYPE(NCVAR), POINTER :: VAR
   REAL(SP), POINTER :: STORAGE_ARR(:,:)
   
   ! SOME HANDY VARIABLES TO PLAY WITH
   LOGICAL FOUND  
   TYPE(TIME) :: FSTART, FEND,TCNT,ONEDAY
   INTEGER :: ERROR, STATUS
   !------------------------------------------------------------------------------!
       
   ! GET THE FILE POINTER
   TS_FILE => FIND_FILE(FILEHEAD,trim(TSGRD_ASSIM_FILE),FOUND)
   IF(.not. FOUND) CALL FATAL_ERROR &
        & ("COULD NOT FIND TSGRD_ASSIM_FILE FILE OBJECT",&
        & "FILE NAME: "//TRIM(TSGRD_ASSIM_FILE))
   
   ! CHECK THE ATTRIBUTES
   ATT => FIND_ATT(TS_FILE,"source",FOUND)
   IF(.not. FOUND) CALL FATAL_ERROR &
        & ("IN TS_ASSIMGRD_FILE FILE OBJECT",&
        & "FILE NAME: "//TRIM(TSGRD_ASSIM_FILE),&
        &"COULD NOT FIND GLOBAL ATTRIBURE: 'source'")
   
   IF(ATT%CHR(1)(1:5) /= "FVCOM") CALL FATAL_ERROR &
        &('IN TSGRD_ASSIM_FILE FILE OBJECT',&
        & "FILE NAME: "//TRIM(TSGRD_ASSIM_FILE),&
        & "THE GLOBAL ATTRIBURE 'source' SHOULD BE 'FVCOM' ")
   
   ! LOOK FOR THE DIMENSIONS 
   DIM => FIND_DIM(TS_FILE,'node',FOUND) ! NODE
   IF(.not. FOUND) CALL FATAL_ERROR &
        & ("IN TSGRD_ASSIM_FILE OBJECT",&
        & "FILE NAME: "//TRIM(SSTGRD_ASSIM_FILE),&
        &"COULD NOT FIND DIMENSION 'node'")
   
   IF (DIM%DIM /= MGL) CALL FATAL_ERROR&
        & ("THE NUMBER OF NODES IN THE SST GRID ASSIM FILE DOES NOT MATCH THE GRID FILE!")
   
   
   DIM => FIND_DIM(TS_FILE,'time',FOUND) ! TIME
   IF(.not. FOUND) CALL FATAL_ERROR &
        & ("IN TSGRD_ASSIM_FILE OBJECT",&
        & "FILE NAME: "//TRIM(SSTGRD_ASSIM_FILE),&
        &"COULD NOT FIND DIMENSION 'time'")
   
   N_TIMES_TSC = DIM%DIM ! SET THE VARIABLE VALUE
   
   ONEDAY = days2time(1.0_DP)
   
!   ! CHECK THE BEGIN TIME
!   FSTART = GET_FILE_TIME(TS_FILE,1)
!   
!   IF (FSTART > STARTTIME + oneday/2) THEN
!      IF(DBG_SET(DBG_LOG)) THEN
!         CALL PRINT_REAL_TIME(FSTART,IPT,"FIRST TIME IN TSC GRID ASSIM FILE")
!         CALL PRINT_REAL_TIME(STARTTIME,IPT,"MODEL START TIME")
!      END IF
!      CALL FATAL_ERROR("THE TS GRID ASSIM START TIME IS INCORRECT",&
!           & "THE MODEL STARTS MORE THAN 12 HOURS BEFORE THE FIRST TS DATA")
!   END IF
   
   ! CHECK THE END TIME
!   FEND = GET_FILE_TIME(TS_FILE,N_TIMES_TSC)
   
!   IF (FEND < ENDTIME - oneday/2) THEN
!      IF(DBG_SET(DBG_LOG)) THEN
!         CALL PRINT_REAL_TIME(FEND,IPT,"LAST TIME IN TS GRID ASSIM FILE")
!         CALL PRINT_REAL_TIME(ENDTIME,IPT,"MODEL END TIME")
!      END IF
!      CALL FATAL_ERROR("THE TSC  GRID ASSIM END TIME IS INCORRECT",&
!           & "THE MODEL ENDS MORE THAN 12 HOURS AFTER THE LAST TS DATA")
!   END IF
   
   ! CHECK THE FILE INTERVAL - EXPECTING DAILY DATA
!   TCNT = FSTART + ONEDAY *(N_TIMES_TSC-1)
!   
!   IF (.NOT. FEND == TCNT) THEN
!      IF(DBG_SET(DBG_LOG)) THEN
!         CALL PRINT_REAL_TIME(FEND,IPT,"LAST TIME IN TS GRID ASSIM FILE")
!         CALL PRINT_REAL_TIME(TCNT,IPT,"EXPECTED END TIME FOR DAILY DATA")
!      END IF
!      CALL FATAL_ERROR("THE TS GRID ASSIM FILE TIME STEP IS NOT DAILY",&
!           & "THE START TIME PLUS NUMBER OF DAYS IN THE FILE DOES N&
!           &OT EQUAL THE END TIME?")
!   END IF
    
   !TSGRD_N_PER_INTERVAL 
 
   ! GET INTERVAL FOR SAVING TS STATE 
   TSC_SAVE_INTERVAL = ONEDAY / TSGRD_N_PER_INTERVAL

!   IF(DBG_SET(DBG_LOG)) WRITE(IPT,*)"TSGRD_N_PER_INTERVAL:",TSGRD_N_PER_INTERVAL
!   IF(DBG_SET(DBG_LOG)) WRITE(IPT,*)"Memory:",   MEMCNT ! MT*KB*4*NDB 
   ! ALLOCATE MEMORY

!   TSGRD_N_PER_INTERVAL=TSGRD_N_PER_INTERVAL*Pmdays

!!  IF not allocate !
     !allocate here
   IF (ALLOCATED(TC_OBS)) DEALLOCATE(TC_OBS,STAT=ERROR)
   IF (ALLOCATED(TC_AVG)) DEALLOCATE(TC_AVG,STAT=ERROR)
   IF (ALLOCATED(TC0_AVG)) DEALLOCATE(TC0_AVG,STAT=ERROR)

   ALLOCATE(TC_OBS(M,KBM1))   
   ALLOCATE(TC_AVG(M,KBM1))
   ALLOCATE(TC0_AVG(M,KBM1))   ; TC0_AVG = 0.0_SP

   ALLOCATE(TC_SAVED(M,KBM1,1:TSGRD_N_PER_INTERVAL))

   MEMCNT = M*KB*3 + M*KB*TSGRD_N_PER_INTERVAL + MEMCNT
   IF(DBG_SET(DBG_LOG)) WRITE(IPT,*)"Memory:",   MEMCNT ! MT*KB*4*NDB 
   IF(DBG_SET(DBG_LOG)) WRITE(IPT,*)"TSGRD_N_PER_INTERVAL:",TSGRD_N_PER_INTERVAL
   
   IF (ALLOCATED(SC_OBS)) DEALLOCATE(SC_OBS,STAT=ERROR)
   IF (ALLOCATED(SC_AVG)) DEALLOCATE(SC_AVG,STAT=ERROR)
   IF (ALLOCATED(SC0_AVG)) DEALLOCATE(SC0_AVG,STAT=ERROR)

   ALLOCATE(SC_OBS(M,KBM1))   
   ALLOCATE(SC_AVG(M,KBM1))
   ALLOCATE(SC0_AVG(M,KBM1))  ; SC0_AVG = 0.0_SP

   ALLOCATE(SC_SAVED(M,KBM1,1:TSGRD_N_PER_INTERVAL))

   MEMCNT = M*KB*3 + M*KB*TSGRD_N_PER_INTERVAL + MEMCNT
   IF(DBG_SET(DBG_LOG)) WRITE(IPT,*)"Memory:",   MEMCNT ! MT*KB*4*NDB

   NULLIFY(TSC_T1_N, TSC_T1_P, TSC_S1_N, TSC_S1_P)

   VAR => FIND_VAR(TS_FILE,'temp_clim',FOUND)
   IF (.NOT.FOUND) CALL FATAL_ERROR &
        ("THE VARIABLE 'temp_clim' IS MISSING FROM THE TSGRD_ASSIM FILE?")

   ! MAKE SPACE FOR THE DATA FROM THE FILE
   TSC_T1_N => reference_var(var)
   ALLOCATE(STORAGE_ARR(1:M,KBM1), stat = status)
   IF(STATUS /= 0) CALL FATAL_ERROR("ALLOCATION ERROR IN TSGRD_ASSIM FORCING")
   CALL NC_CONNECT_PVAR(TSC_T1_N,STORAGE_ARR)
   NULLIFY(STORAGE_ARR)

   ! MAKE SPACE FOR THE DATA FROM THE FILE
   TSC_T1_P => reference_var(var)
   ALLOCATE(STORAGE_ARR(1:M,KBM1), stat = status)
   IF(STATUS /= 0) CALL FATAL_ERROR("ALLOCATION ERROR IN TSGRD_ASSIM FORCING")
   CALL NC_CONNECT_PVAR(TSC_T1_P,STORAGE_ARR)
   NULLIFY(STORAGE_ARR)

!   CALL NC_CONNECT_AVAR(VAR,TC_OBS)
!   VAR_TC =>VAR

   VAR => FIND_VAR(TS_FILE,'salinity_clim',FOUND)
   IF (.NOT.FOUND) CALL FATAL_ERROR &
        ("THE VARIABLE 'salinity_clim' IS MISSING FROM THE TSGRD_ASSIM FILE?")

   ! MAKE SPACE FOR THE DATA FROM THE FILE
   TSC_S1_N => reference_var(var)
   ALLOCATE(STORAGE_ARR(1:M,KBM1), stat = status)
   IF(STATUS /= 0) CALL FATAL_ERROR("ALLOCATION ERROR IN OFFLINE FORCING")
   CALL NC_CONNECT_PVAR(TSC_S1_N,STORAGE_ARR)
   NULLIFY(STORAGE_ARR)

   ! MAKE SPACE FOR THE DATA FROM THE FILE
   TSC_S1_P => reference_var(var)
   ALLOCATE(STORAGE_ARR(1:M,KBM1), stat = status)
   IF(STATUS /= 0) CALL FATAL_ERROR("ALLOCATION ERROR IN OFFLINE FORCING")
   CALL NC_CONNECT_PVAR(TSC_S1_P,STORAGE_ARR)
   NULLIFY(STORAGE_ARR)

!   CALL NC_CONNECT_AVAR(VAR,SC_OBS)
!   VAR_SC =>VAR

   RETURN
   END SUBROUTINE SET_TSGRD_ASSIM
!==============================================================================|
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
!   SUBROUTINE SET_TSGRD_ASSIM_julian
!------------------------------------------------------------------------------!
!  SET UP ASSIMILATION DATA FOR TS OBSERVATIONS                               |
!------------------------------------------------------------------------------!
!   USE ALL_VARS
!   USE MOD_PAR 

!   IMPLICIT NONE
!   INTEGER I
!   REAL(DP) :: TEMP      
!   ! SOME NC POINTERS

!   TYPE(NCATT), POINTER :: ATT
!   TYPE(NCDIM), POINTER :: DIM
!   TYPE(NCVAR), POINTER :: VAR
   
!   ! SOME HANDY VARIABLES TO PLAY WITH
!   LOGICAL FOUND  
!   TYPE(TIME) :: FSTART, FEND,TCNT,ONEDAY
!   INTEGER :: ERROR
   !------------------------------------------------------------------------------!
   
!!   ONEDAY = days2time(1.0_DP)
   
!   ! GET INTERVAL FOR SAVING TS STATE 
!   !TSC_SAVE_INTERVAL = ONEDAY / TSGRD_N_PER_INTERVAL

!   IF(DBG_SET(DBG_LOG)) WRITE(IPT,*)"TSGRD_N_PER_INTERVAL:",TSGRD_N_PER_INTERVAL
!   IF(DBG_SET(DBG_LOG)) WRITE(IPT,*)"Memory:",   MEMCNT ! MT*KB*4*NDB 
!   ! ALLOCATE MEMORY
   
  
!   TSC_SAVE_TIME =ASSIM_RESTART_TIME-days2time(real(Pmdays,kind=DP))/2.0
!   !TSGRD_N_PER_INTERVAL=TSGRD_N_PER_INTERVAL*Pmdays

!   TC_AVG=0.0_SP
!   SC_AVG=0.0_SP

!   RETURN
!   END SUBROUTINE SET_TSGRD_ASSIM_julian
!==============================================================================|

!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
!!   SUBROUTINE SET_TS_ASSIM
!------------------------------------------------------------------------------!
!!     IMPLICIT NONE

  
!!   END SUBROUTINE SET_TS_ASSIM
!==============================================================================|

!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
!!   SUBROUTINE SET_CUR_ASSIM
!------------------------------------------------------------------------------!
!!     IMPLICIT NONE

  
!!   END SUBROUTINE SET_CUR_ASSIM
!==============================================================================|


!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|
!==============================================================================!
   SUBROUTINE SET_CUR_ASSIM_DATA 
!==============================================================================!

!------------------------------------------------------------------------------!
!  SET UP ASSIMILATION DATA FOR CURRENT OBSERVATIONS                           |
!------------------------------------------------------------------------------!
   IMPLICIT NONE
   INTEGER I,J,K,NN,ECNT,ITMP,NCNT,IOS,NLAY
   CHARACTER(LEN=120) :: FNAME,ONAME
   CHARACTER(LEN= 2 ) :: NAC   
   INTEGER,  ALLOCATABLE, DIMENSION(:) :: ITEMP
   REAL(SP), ALLOCATABLE, DIMENSION(:) :: FTEMP
   REAL(SP):: X0,Y0,DX,DY,RD,SIGMA_C,ISOBATH_ANGLE,D_ANGLE,ANG_OBS_SIM,DIR_WEIGHT
   REAL(SP), PARAMETER :: ALF = 0.05_SP
   LOGICAL :: FEXIST
   INTEGER :: MAXEL,NBD_CNT
   REAL(SP) :: CUR_RADIUS 
   INTEGER :: JJ

   REAL(SP), DIMENSION(3) :: XTRI,YTRI 
   REAL(SP) :: RDLAST 
   INTEGER :: LOCIJ(2),MIN_LOC,IERR,Nsite_tmp 
   INTEGER :: ND1,ND2,ND3 
   REAL(SP) :: DELTA,COFA,COFB,COFC 
   REAL(SP) ::S11,S22,S33,RTMP,RRTMP 
   REAL(SP), DIMENSION(1:NGL,1) :: RDLIST 
   REAL(SP), DIMENSION(KB) :: ZZ_OB 
   REAL(SP), ALLOCATABLE :: ZZ_G(:,:)   
   REAL(SP) :: X0C,Y0C,HX,HY,H0,TEMP_H
   REAL(DP) :: ODAYS

   REAL(SP) :: X11_TMP, X22_TMP, X33_TMP

   IF (DBG_SET(DBG_SBR)) WRITE(IPT,*) "START: SET_CUR_ASSIM_DATA"

!------------------------------------------------------------------------------!
!  Read Number of Current Observations and Coordinates of Each                 !
!------------------------------------------------------------------------------!
    
!   FNAME = "./"//TRIM(INPUT_DIR)//"/"//trim(casename)//"_cur.xy"
   IF(CUR_NGASSIM .AND. .NOT. CUR_OIASSIM)THEN
     FNAME = "./"//TRIM(INPUT_DIR)//"/"//trim(CUR_NGASSIM_FILE)//".xy"
   ELSE IF(CUR_OIASSIM .AND. .NOT. CUR_NGASSIM)THEN
     FNAME = "./"//TRIM(INPUT_DIR)//"/"//trim(CUR_OIASSIM_FILE)//".xy"
   ELSE
     CALL FATAL_ERROR("CUR_NGASSIM and CUR_OIASSIM cannot be both true or false")
   END IF  
!
!--Make Sure Current Assimilation Data File Exists-----------------------------!
!
   INQUIRE(FILE=TRIM(FNAME),EXIST=FEXIST)
   IF(MSR .AND. .NOT.FEXIST)THEN
     WRITE(IPT,*)'CURRENT OBSERVATION FILE: ',FNAME,' DOES NOT EXIST'
     WRITE(IPT,*)'HALTING.....'
     CALL PSTOP
   END IF
     
!
!--Read Number of Current Measurement Stations---------------------------------!
!
   OPEN(1,FILE=TRIM(FNAME),STATUS='OLD')
   READ(1,*) N_ASSIM_CUR

   ALLOCATE(CUR_OBS(N_ASSIM_CUR))

!
!--Read X,Y Coordinate of Measurement Stations---------------------------------!
!

   DO I=1,N_ASSIM_CUR
     READ(1,*)ITMP,CUR_OBS(I)%X,CUR_OBS(I)%Y,CUR_OBS(I)%DEPTH,NLAY,CUR_OBS(I)%SITA
     CUR_OBS(I)%N_LAYERS = NLAY

     ALLOCATE(CUR_OBS(I)%ODEPTH(NLAY))
     DO J=1,NLAY
       READ(1,*)CUR_OBS(I)%ODEPTH(J)
       IF(CUR_OBS(I)%ODEPTH(J) > CUR_OBS(I)%DEPTH)THEN
         IF(MSR)WRITE(IPT,*)'CURRENT OBSERVATION LAYER',J,'OF CURRENT MOORING',I
         IF(MSR)WRITE(IPT,*)'EXCEEDS BATHYMETRIC DEPTH=',CUR_OBS(I)%ODEPTH(J),CUR_OBS(I)%DEPTH
         IF(MSR)WRITE(IPT,*)'HALTING...........'
         CALL PSTOP
       END IF
     END DO
   END DO
   CUR_MAX_LAYER = MAXVAL(CUR_OBS(1:N_ASSIM_CUR)%N_LAYERS)

!
!--Shift Coordinates-----------------------------------------------------------!
!
# if !defined (SPHERICAL) 
   CUR_OBS(:)%X = CUR_OBS(:)%X - VXMIN 
   CUR_OBS(:)%Y = CUR_OBS(:)%Y - VYMIN 
# endif

!# if defined (SPHERICAL) 
   IF(SERIAL)THEN
     XCG = XC
     YCG = YC
     XG = VX
     YG = VY
   END IF
#  if defined(MULTIPROCESSOR)
   IF(PAR)CALL ACOLLECT(MYID,MSRID,NPROCS,EMAP,XC,XCG)
   IF(PAR)CALL ACOLLECT(MYID,MSRID,NPROCS,EMAP,YC,YCG)
   IF(PAR)CALL ACOLLECT(MYID,MSRID,NPROCS,NMAP,VX,XG)
   IF(PAR)CALL ACOLLECT(MYID,MSRID,NPROCS,NMAP,VY,YG)
   IF(PAR)CALL MPI_BCAST(XCG,NGL+1,MPI_F,0,MPI_FVCOM_GROUP,IERR)
   IF(PAR)CALL MPI_BCAST(YCG,NGL+1,MPI_F,0,MPI_FVCOM_GROUP,IERR)
   IF(PAR)CALL MPI_BCAST(XG,MGL+1,MPI_F,0,MPI_FVCOM_GROUP,IERR)
   IF(PAR)CALL MPI_BCAST(YG,MGL+1,MPI_F,0,MPI_FVCOM_GROUP,IERR)
#  endif
!# endif
!  


!
!--find cell number (CUR_OBS(J)%N_CELL) of Obs.
!
   RRTMP = 100000.0     !100km
!   IF(CUR_NGASSIM)THEN
!         RRTMP = CUR_NG_RADIUS
!   ELSE IF(CUR_OIASSIM)THEN
!        RRTMP = CUR_OI_RADIUS
!   ELSE
!         WRITE(IPT,*) 'IN SUBROUTINE SET_CUR_ASSIM_DATA, ONE OF CUR_NGASSIM AND &
!                       CUR_OIASSIM MUST BE DEFINED AS TRUE.'
!         WRITE(IPT,*) 'HALTING.....'            
!         CALL PSTOP
!   END IF

   DO J= 1,N_ASSIM_CUR 
     X0 = CUR_OBS(J)%X
     Y0 = CUR_OBS(J)%Y
     INLOOP: DO I=1,NGL  
#    if !defined (SPHERICAL)
       Rtmp = SQRT((XCG(I)-X0)*(XCG(I)-X0)+(YCG(I)-Y0)*(YCG(I)-Y0))
#    else
       CALL ARC(X0,Y0,XCG(I),YCG(I),Rtmp)
#    endif
       IF(Rtmp < RRTMP) THEN
         X11_TMP = XG(NVG(I,1))-X0
         X22_TMP = XG(NVG(I,2))-X0
         X33_TMP = XG(NVG(I,3))-X0
#        if defined (SPHERICAL)
         IF(X11_TMP >  180.0_SP)THEN
           X11_TMP = -360.0_SP+X11_TMP
         ELSEIF(X11_TMP < -180.0_SP)THEN
           X11_TMP =  360.0_SP+X11_TMP
         END IF
         IF(X22_TMP >  180.0_SP)THEN
           X22_TMP = -360.0_SP+X22_TMP
         ELSEIF(X22_TMP < -180.0_SP)THEN
           X22_TMP =  360.0_SP+X22_TMP
         END IF
         IF(X33_TMP >  180.0_SP)THEN
           X33_TMP = -360.0_SP+X33_TMP
         ELSEIF(X33_TMP < -180.0_SP)THEN
           X33_TMP =  360.0_SP+X33_TMP
         END IF
#        endif
         S11 = X22_TMP*(YG(NVG(I,3))-Y0)-X33_TMP*(YG(NVG(I,2))-Y0)
         S22 = X33_TMP*(YG(NVG(I,1))-Y0)-X11_TMP*(YG(NVG(I,3))-Y0)
         S33 = X11_TMP*(YG(NVG(I,2))-Y0)-X22_TMP*(YG(NVG(I,1))-Y0)
         IF(S11 <= 0._SP .AND. S22 <= 0._SP .AND. S33<= 0._SP) THEN
           CUR_OBS(J)%N_CELL = I
           EXIT INLOOP      
         ELSE
           CUR_OBS(J)%N_CELL = 0
         ENDIF
       ELSE
         CUR_OBS(J)%N_CELL = -1
       ENDIF
     END DO INLOOP      
!     IF(MSR) WRITE(200,*) j,X0,Y0,CUR_OBS(J)%N_CELL
     IF(CUR_OBS(J)%N_CELL <= 0) THEN
       IF(MSR) WRITE(IPT,*)'ERROR--CURRENT OBS SITE:',J,' OUT OF DOMAN',&
               CUR_OBS(J)%N_CELL 
       CALL PSTOP
     ENDIF 
   ENDDO
             
!--Gather AW0G,AWXG & AWYG use for interp grid to Obs station
   IF(.NOT. ALLOCATED(AW0G))   ALLOCATE(AW0G(0:NGL,3)) 
   IF(.NOT. ALLOCATED(AWXG))   ALLOCATE(AWXG(0:NGL,3))
   IF(.NOT. ALLOCATED(AWYG))   ALLOCATE(AWYG(0:NGL,3))

   IF(SERIAL)THEN
     AW0G = AW0
     AWXG = AWX
     AWYG = AWY
   END IF
# if defined(MULTIPROCESSOR)
   IF(PAR)CALL ACOLLECT(MYID,MSRID,NPROCS,EMAP,AW0,AW0G)
   IF(PAR)CALL ACOLLECT(MYID,MSRID,NPROCS,EMAP,AWX,AWXG)
   IF(PAR)CALL ACOLLECT(MYID,MSRID,NPROCS,EMAP,AWY,AWYG)
   IF(PAR)CALL MPI_BCAST(AW0G,(NGL+1)*3,MPI_F,0,MPI_FVCOM_GROUP,IERR)
   IF(PAR)CALL MPI_BCAST(AWXG,(NGL+1)*3,MPI_F,0,MPI_FVCOM_GROUP,IERR)
   IF(PAR)CALL MPI_BCAST(AWYG,(NGL+1)*3,MPI_F,0,MPI_FVCOM_GROUP,IERR)
# endif
!
!--Close Current Observation Global File---------------------------------------!
!
   CLOSE(1)   

   IF(CUR_OIASSIM)THEN
!------------------------------------------------------------------------------!
!  Read Correlation Length of Current Observations                             !
!------------------------------------------------------------------------------!
       
!JQI   FNAME = "./"//TRIM(INPDIR)//"/"//trim(casename)//"_radius_cur.dat"

!JQI   INQUIRE(FILE=TRIM(FNAME),EXIST=FEXIST)
!JQI   IF(MSR .AND. .NOT.FEXIST)THEN
!JQI     WRITE(IPT,*)'CURRENT OBSERVATION FILE: ',FNAME,' DOES NOT EXIST'
!JQI     WRITE(IPT,*)'HALTING.....'
!JQI     CALL PSTOP
!JQI   END IF
     
!JQI   OPEN(1,FILE=TRIM(FNAME),STATUS='OLD')

   ALLOCATE(CUR_PARAM(2,N_ASSIM_CUR))

!JQI   DO I=1,N_ASSIM_CUR
!JQI     READ(1,*)PARAM_CUR(1,I),PARAM_CUR(2,I)
!JQI   END DO

!JQI   CLOSE(1)
     CUR_PARAM = CUR_OI_RADIUS       !30000.0_SP
   END IF
       
!
!------------------------------------------------------------------------------!
!  Open Current Observation Files for Each Observation Point and Read Data     !
!------------------------------------------------------------------------------!
   IF(CUR_NGASSIM .AND. .NOT. CUR_OIASSIM)THEN
     ONAME = "./"//TRIM(INPUT_DIR)//"/"//trim(CUR_NGASSIM_FILE)//".dat"
   ELSE IF(CUR_OIASSIM .AND. .NOT. CUR_NGASSIM)THEN
     ONAME = "./"//TRIM(INPUT_DIR)//"/"//trim(CUR_OIASSIM_FILE)//".dat"
   ELSE
     CALL FATAL_ERROR("CUR_NGASSIM and CUR_OIASSIM cannot be both true or false")
   END IF  
   INQUIRE(FILE=TRIM(ONAME),EXIST=FEXIST)
   IF(MSR .AND. .NOT.FEXIST)THEN
     WRITE(IPT,*)'CURRENT OBSERVATION FILE: ',ONAME,' DOES NOT EXIST'
     WRITE(IPT,*)'HALTING.....'
     CALL PSTOP
   END IF
   OPEN(1,FILE=ONAME,STATUS='old')  ; REWIND(1)

   DO I=1,N_ASSIM_CUR
!----Count Number of Data Entries for Observation I----------------------------!
!     DO WHILE(.TRUE.)
!       READ(1,*,IOSTAT=IOS)
!       IF(IOS < 0)EXIT
!       NCNT = NCNT + 1
!     END DO

     READ(1,*,IOSTAT=IOS) Nsite_tmp,NCNT     
     IF(IOS<0) then
       WRITE(IPT,*) 'ERROR in read ',trim(casename),'_cur.dat at site number:',I
       CALL PSTOP
     END IF
     CUR_OBS(I)%N_TIMES = NCNT
     
     IF(NCNT == 0)THEN
       IF(MSR)WRITE(IPT,*)'NO DATA FOR CURRENT OBSERVATION',I
       CALL PSTOP
     END IF

!----Allocate Arrays to Hold Current (UA,VA) and Time (TIME)-------------------!
     ALLOCATE(CUR_OBS(I)%TIMES(CUR_OBS(I)%N_TIMES))
     ALLOCATE(CUR_OBS(I)%UO( CUR_OBS(I)%N_TIMES , CUR_OBS(I)%N_LAYERS ))
     ALLOCATE(CUR_OBS(I)%VO( CUR_OBS(I)%N_TIMES , CUR_OBS(I)%N_LAYERS ))

!----Read in Current Data for Observation I------------------------------------!
     NLAY = CUR_OBS(I)%N_LAYERS
     DO J=1,CUR_OBS(I)%N_TIMES
       READ(1,*,IOSTAT=IOS) ODAYS,(CUR_OBS(I)%UO(J,K),CUR_OBS(I)%VO(J,K),K=1,NLAY)
       IF(IOS < 0)THEN         
         WRITE(IPT,*)'ERROR in read ',trim(casename),'_cur.dat at site:',I,'Time No:',J
         CALL PSTOP
       END IF  
       CUR_OBS(I)%TIMES(J) = DAYS2TIME(ODAYS)
     END DO

!----Convert Time to Seconds---------------------------------------------------!
!----Shift Jan 1 Based Time Data to Dec 1 Based Time Data-----CASESPECIFIC-----!
!     IF(trim(CASENAME) == 'gom')THEN
!       CUR_OBS(I)%TIMES = (CUR_OBS(I)%TIMES-1.0_SP)*24.0_SP*3600.0_SP !after 1996 
!     ELSE   
!       CUR_OBS(I)%TIMES = CUR_OBS(I)%TIMES*3600.0_SP*24.0_SP
!     END IF
 
!----Convert Current Data from cm/s to m/s-------------------------------------!
     CUR_OBS(I)%UO = CUR_OBS(I)%UO * .01_SP
     CUR_OBS(I)%VO = CUR_OBS(I)%VO * .01_SP
  END DO
  CLOSE(1)

!------------------------------------------------------------------------------!
!  Count Number of Points with Bad Data (UO = 0. + V0 = 0.)         
!------------------------------------------------------------------------------!
  NBD_CNT = 0
  DO I=1,N_ASSIM_CUR
    DO J=1,CUR_OBS(I)%N_TIMES
      DO K=1,CUR_OBS(I)%N_LAYERS
        IF(ABS(CUR_OBS(I)%UO(J,K)) + ABS(CUR_OBS(I)%VO(J,K)) < .0001) THEN
          NBD_CNT = NBD_CNT + 1
        END IF
      END DO
    END DO
  END DO
 
!------------------------------------------------------------------------------!
!  Compute Spatial Interpolation Weights for each Mooring Location 
!------------------------------------------------------------------------------!
!   DO I=1,N_ASSIM_CUR
!   LMIN = 100000000.
!     X0 = CUR_OBS(I)%X
!     Y0 = CUR_OBS(I)%Y
!     DO J=1,MGL
!       DX = ABS(XG(J)-X0)
!       DY = ABS(YG(J)-Y0)
!       IF(SQRT(DX**2 + DY**2) < LMIN)THEN
!         LMIN = SQRT(DX**2 + DY**2)--dbg=7
!         JMIN = J
!       END IF
!      END DO
!      CUR_OBS(I)%SITA = SITA_GD(JMIN) + 3.14159_SP/2.0_SP
!    END DO

   ALLOCATE(ITEMP(NGL),FTEMP(NGL),DA_CUR(NGL))     ; DA_CUR = 0
   DO I=1,N_ASSIM_CUR
     X0 = CUR_OBS(I)%X
     Y0 = CUR_OBS(I)%Y
     ISOBATH_ANGLE = CUR_OBS(I)%SITA*DEG2RAD       !/180.0_SP*3.1415926_SP
     ECNT = 0

     DO J=1,NGL
#      if defined (SPHERICAL)
       CALL ARCX(X0,Y0,XCG(J),YCG(J),DX)
       CALL ARCY(X0,Y0,XCG(J),YCG(J),DY)
       CALL ARC(X0,Y0,XCG(J),YCG(J),RD)
#      else
       DX = ABS(XCG(J)-X0)
       DY = ABS(YCG(J)-Y0)
       RD = SQRT(DX**2 + DY**2)
#      endif

       IF(CUR_NGASSIM)THEN
         CUR_RADIUS = CUR_NG_RADIUS
       ELSE IF(CUR_OIASSIM)THEN
         CUR_RADIUS = CUR_OI_RADIUS
       ELSE
         WRITE(IPT,*) 'IN SUBROUTINE SET_CUR_ASSIM_DATA, ONE OF CUR_NGASSIM AND ', &
                       'CUR_OIASSIM MUST BE DEFINED AS TRUE.'
         WRITE(IPT,*) 'HALTING.....'            
         CALL PSTOP
       END IF

       IF(RD <= CUR_RADIUS)THEN         
         DA_CUR(J)   = 1
         ECNT        = ECNT + 1      
         ITEMP(ECNT) =  J
         FTEMP(ECNT) = (CUR_RADIUS**2 - RD**2) / (CUR_RADIUS**2 + RD**2)

         IF(ISOBATH_ANGLE==0.0_SP)THEN
           DIR_WEIGHT = 1.0_SP
         ELSE
           ANG_OBS_SIM = ATAN2(DY,DX)
           D_ANGLE     = ANG_OBS_SIM - ISOBATH_ANGLE 
           D_ANGLE     = D_ANGLE - INT(D_ANGLE/PI)*PI      !3.1415926_SP)*3.1415926_SP
           D_ANGLE     = ABS(D_ANGLE)
!           DIR_WEIGHT  = (ABS(D_ANGLE-0.5*3.1415926_SP)+ALF*3.1415926_SP)/ &
!                        ((0.5_SP+ALF)*3.1415926_SP)
           DIR_WEIGHT  = (ABS(D_ANGLE-0.5*PI)+ALF*PI)/((0.5_SP+ALF)*PI)
           IF(J == CUR_OBS(J)%N_CELL) DIR_WEIGHT = 1.0_SP
         END IF
! qxu       FTEMP(ECNT) = FTEMP(ECNT)*DIR_WEIGHT
       END IF
     END DO

     IF(ECNT == 0)THEN
       WRITE(IPT,*)'ERROR SETTING UP CURRENT DATA ASSIMILATION'
       WRITE(IPT,*)'NO ELEMENTS LIE WITHIN RADIUS',CUR_RADIUS
       WRITE(IPT,*)'OF OBSERVATION POINT',I
       CALL PSTOP   
     ELSE
       CUR_OBS(I)%N_INTPTS = ECNT
       ALLOCATE(CUR_OBS(I)%INTPTS(ECNT))
       ALLOCATE(CUR_OBS(I)%X_WEIGHT(ECNT))
       CUR_OBS(I)%INTPTS(1:ECNT)  = ITEMP(1:ECNT)
       CUR_OBS(I)%X_WEIGHT(1:ECNT) = FTEMP(1:ECNT)
     END IF
   END DO
   DEALLOCATE(FTEMP,ITEMP)


     
!------------------------------------------------------------------------------!
!  Compute Sigma Layer Weights for Vertical Interpolation                      
!------------------------------------------------------------------------------!
   ALLOCATE(ZZ_G(0:MGL,KB))
   IF(.NOT. ALLOCATED(HG)) ALLOCATE(HG(0:MGL))
   IF(SERIAL)THEN
     ZZ_G = ZZ
     HG = H
   END IF  
#  if defined (MULTIPROCESSOR)   
   IF(PAR)CALL ACOLLECT(MYID,MSRID,NPROCS,NMAP,ZZ,ZZ_G) 
   IF(PAR)CALL ACOLLECT(MYID,MSRID,NPROCS,NMAP,H,HG) 

   IF(PAR)CALL MPI_BCAST(ZZ_G,(MGL+1)*KB,MPI_F,0,MPI_FVCOM_GROUP,IERR)
   IF(PAR)CALL MPI_BCAST(HG,MGL+1,MPI_F,0,MPI_FVCOM_GROUP,IERR)
#  endif
   DO I=1,N_ASSIM_CUR
     NLAY = CUR_OBS(I)%N_LAYERS
     ALLOCATE(CUR_OBS(I)%S_INT(NLAY,2))
     ALLOCATE(CUR_OBS(I)%S_WEIGHT(NLAY,2))
     X0 = CUR_OBS(I)%X
     Y0 = CUR_OBS(I)%Y
# if defined (SPHERICAL)
     DO NN=1,NGL
       CALL ARC(X0,Y0,XCG(NN),YCG(NN),RDLIST(NN,1))
     END DO
# else
     RDLIST(1:NGL,1) = SQRT((XCG(1:NGL)-X0)**2 + (YCG(1:NGL)-Y0)**2)
# endif
     RDLAST = -1.0_SP
in:  DO WHILE(.TRUE.)
       LOCIJ = MINLOC(RDLIST,RDLIST>RDLAST)
       MIN_LOC = LOCIJ(1)
       IF(MIN_LOC == 0)THEN
         EXIT in
       END IF
!---> Siqi Li, CHECKALL@20230818
       XTRI = reshape(XG(NVG(MIN_LOC,1:3)), (/3/))
       YTRI = reshape(YG(NVG(MIN_LOC,1:3)), (/3/))
!       XTRI = XG(NVG(MIN_LOC,1:3))
!       YTRI = YG(NVG(MIN_LOC,1:3))
!<--- 
       RDLAST = RDLIST(MIN_LOC,1)
       IF(ISINTRIANGLE1(XTRI,YTRI,X0,Y0))THEN
         JJ = MIN_LOC
         EXIT IN
       END IF
       RDLAST = RDLIST(MIN_LOC,1)
     END DO IN

     ND1=NVG(JJ,1)
     ND2=NVG(JJ,2)
     ND3=NVG(JJ,3)

# if defined (SPHERICAL)
     CALL ARCX(X0,Y0,XCG(JJ),YCG(JJ),X0C)
     CALL ARCX(X0,Y0,XCG(JJ),YCG(JJ),Y0C)
# else
     X0C = X0 - XCG(JJ)
     Y0C = Y0 - YCG(JJ)
# endif
     !----Linear Interpolation of Bathymetry------------------------------------------!
     H0 = AW0G(JJ,1)*HG(ND1)+AW0G(JJ,2)*HG(ND2)+AW0G(JJ,3)*HG(ND3)
     HX = AWXG(JJ,1)*HG(ND1)+AWXG(JJ,2)*HG(ND2)+AWXG(JJ,3)*HG(ND3)
     HY = AWYG(JJ,1)*HG(ND1)+AWYG(JJ,2)*HG(ND2)+AWYG(JJ,3)*HG(ND3)
     TEMP_H = H0 + HX*X0C + HY*Y0C !here is the interpolated observation depth

     DO K=1,KBM1
      !----Linear Interpolation of Bathymetry------------------------------------------!
      H0 = AW0G(JJ,1)*ZZ_G(ND1,K)*HG(ND1)+AW0G(JJ,2)*ZZ_G(ND2,K)*HG(ND2)+AW0G(JJ,3)*ZZ_G(ND3,K)*HG(ND3)
      HX = AWXG(JJ,1)*ZZ_G(ND1,K)*HG(ND1)+AWXG(JJ,2)*ZZ_G(ND2,K)*HG(ND2)+AWXG(JJ,3)*ZZ_G(ND3,K)*HG(ND3)
      HY = AWYG(JJ,1)*ZZ_G(ND1,K)*HG(ND1)+AWYG(JJ,2)*ZZ_G(ND2,K)*HG(ND2)+AWYG(JJ,3)*ZZ_G(ND3,K)*HG(ND3)
      ZZ_OB(K) = (H0 + HX*X0C + HY*Y0C)/TEMP_H
     END DO  

     DO J=1,NLAY
       SIGMA_C = -CUR_OBS(I)%ODEPTH(J)/TEMP_H
       DO K=2,KBM1
         IF(ZZ_OB(K) <= SIGMA_C .AND. ZZ_OB(K-1) > SIGMA_C)THEN 
           CUR_OBS(I)%S_INT(J,1) = K-1
           CUR_OBS(I)%S_INT(J,2) = K
           CUR_OBS(I)%S_WEIGHT(J,1) = (SIGMA_C-ZZ_OB(K))/(ZZ_OB(K-1)-ZZ_OB(K))
           CUR_OBS(I)%S_WEIGHT(J,2) = 1.0_SP - CUR_OBS(I)%S_WEIGHT(J,1) 
         END IF  
       END DO
       IF(ZZ_OB(1) <= SIGMA_C)THEN  !!OBSERVATION ABOVE CENTROID OF FIRST SIGMA LAYER
         CUR_OBS(I)%S_INT(J,1) = 1
         CUR_OBS(I)%S_INT(J,2) = 1
         CUR_OBS(I)%S_WEIGHT(J,1) = 1.0_SP
         CUR_OBS(I)%S_WEIGHT(J,2) = 0.0_SP
       END IF
       IF(ZZ_OB(KBM1) >= SIGMA_C)THEN !!OBSERVATION BELOW CENTROID OF BOTTOM SIGMA LAYER
         CUR_OBS(I)%S_INT(J,1) = KBM1
         CUR_OBS(I)%S_INT(J,2) = KBM1
         CUR_OBS(I)%S_WEIGHT(J,1) = 1.0_SP
         CUR_OBS(I)%S_WEIGHT(J,2) = 0.0_SP
       END IF
       if (msr) print *, "obs",i,"lay", j,SIGMA_C,CUR_OBS(I)%S_INT(J,1),CUR_OBS(I)%S_INT(J,2), CUR_OBS(I)%ODEPTH(J),CUR_OBS(I)%DEPTH,'scoor',zz_ob(1:kbm1)
     END DO
   END DO
!#  if defined (MULTIPROCESSOR)   
   DEALLOCATE(ZZ_G)  
!#  endif
!------------------------------------------------------------------------------!
!  Report Number of Interpolation Points, Location and Number of Data 
!------------------------------------------------------------------------------!
   IF(.NOT. MSR)RETURN

   WRITE(IPT,*)
   WRITE(IPT,*)'!            CURRENT OBSERVATION DATA           '
# if defined (SPHERICAL)
   WRITE(IPT,*)" MOORING#    LON       LAT    #INTERP PTS  #DATA TIMES  NEAR_CELL  SITA"
# else
   WRITE(IPT,*)" MOORING#   X(KM)      Y(KM)  #INTERP PTS  #DATA TIMES  NEAR_CELL  SITA"
# endif
   DO I=1,N_ASSIM_CUR
     MAXEL = MAXLOC(CUR_OBS(I)%X_WEIGHT,DIM=1)
     WRITE(IPT,'(2X,I5,3X,F8.1,3X,F8.1,3X,I6,5X,I6,5X,I6,5X,F8.1)') &
# if defined (SPHERICAL)
     I,CUR_OBS(I)%X,CUR_OBS(I)%Y, &
# else
     I,(CUR_OBS(I)%X+VXMIN)/1000.,(CUR_OBS(I)%Y+VYMIN)/1000., &
# endif
       CUR_OBS(I)%N_INTPTS,CUR_OBS(I)%N_TIMES,CUR_OBS(I)%INTPTS(MAXEL),&
       CUR_OBS(I)%SITA
   END DO
   WRITE(IPT,*)
   WRITE(IPT,*)'NUMBER OF BAD CURRENT DATA POINTS: ',NBD_CNT
   WRITE(IPT,*)" MOORING #   BEGIN TIME  END TIME"
   DO I=1,N_ASSIM_CUR
!   WRITE(IPT,*)I,CUR_OBS(I)%TIMES(1)/(24.*3600.),&
!       CUR_OBS(I)%TIMES(CUR_OBS(I)%N_TIMES)/(24.*3600.)
   WRITE(IPT,*)I,CUR_OBS(I)%TIMES(1)%MJD,&
       CUR_OBS(I)%TIMES(CUR_OBS(I)%N_TIMES)%MJD
   END DO
   IF (DBG_SET(DBG_SBR)) WRITE(IPT,*) "END: SET_CUR_ASSIM_DATA"

 
   RETURN
   END SUBROUTINE SET_CUR_ASSIM_DATA

!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|

   SUBROUTINE CURRENT_ASSIMILATION
!==============================================================================|
!  USE CURRENT OBSERVATION DATA TO ADJUST VELOCITY COMPONENTS                  |
!==============================================================================|
   IMPLICIT NONE
   REAL(SP), ALLOCATABLE, DIMENSION(:,:) :: UINT,VINT,UCORR,VCORR,UG,VG,TWGHT
   REAL(SP), ALLOCATABLE, DIMENSION(:,:) :: UCORR1,VCORR1
   REAL(SP), ALLOCATABLE, DIMENSION(:)   :: FTEMP
   REAL(SP) :: WEIGHT,DEFECT,CORRECTION,DT_MIN,SIMTIME,T_THRESH,WGHT,TOT_WGHT
   REAL(SP) :: U1,U2,V1,V2,W1,W2,WEIGHT1,WEIGHT2
   TYPE(TIME) ::DIFTIME
   INTEGER I,J,K,J1,K1,K2,NLAY,ITIMEA,NTIME,IERR
   INTEGER COUNT
   INTRINSIC MINLOC

   INTEGER IP,JN1,JN2,JN3
   REAL(SP) XSC,YSC,COFT0,COFTX,COFTY
!==============================================================================|

   IF (DBG_SET(DBG_SBR)) WRITE(IPT,*) "START: CURRENT_ASSIMILATION" 
!------------------------------------------------------------------------------!
!  Check the Temporal and Spatial OBS Availability                             ! 
!------------------------------------------------------------------------------!
   CUR_OBS%T_WEIGHT = 0. 
   IF(CUR_NGASSIM)THEN
     T_THRESH = CUR_NG_ASTIME_WINDOW   
   ELSE IF(CUR_OIASSIM)THEN  
     T_THRESH = CUR_OI_ASTIME_WINDOW   
   ELSE
     WRITE(IPT,*) "EITHER CUR_NGASSIM OR CUR_OIASSIM MUST BE SET TRUE"
     CALL PSTOP
   END IF       
!   SIMTIME = TIME*86400
   SIMTIME = DTI*FLOAT(IINT)

   COUNT = 0
   DO I=1,N_ASSIM_CUR       
     NTIME = CUR_OBS(I)%N_TIMES
     ALLOCATE(FTEMP(NTIME)) 
!    FTEMP(1:NTIME) = ABS(SIMTIME - CUR_OBS(I)%TIMES(1:NTIME))
     DO j=1,NTIME
        FTEMP(J) = SECONDS(IntTime - CUR_OBS(I)%TIMES(J))
        FTEMP(J) = ABS(FTEMP(J))
     ENDDO
     DT_MIN = MINVAL(FTEMP(1:NTIME))
     CUR_OBS(I)%N_T_WEIGHT = MINLOC(FTEMP,DIM=1)

     IF(DT_MIN < T_THRESH)THEN     
       IF(DT_MIN < .5_SP*T_THRESH) THEN
         CUR_OBS(I)%T_WEIGHT = 1.0_SP
       ELSE
         CUR_OBS(I)%T_WEIGHT = (T_THRESH-DT_MIN)/T_THRESH*2.0_SP
       END IF
       COUNT = COUNT + 1
     END IF

     DEALLOCATE(FTEMP)
   END DO
   IF(COUNT==0)RETURN  ! No OBS data 
!------------------------------------------------------------------------------!
!  Gather U and V Fields to Master Processor                                   ! 
!------------------------------------------------------------------------------!
   ALLOCATE(UG(0:NGL,KB))    ;UG = 0.0_SP
   ALLOCATE(VG(0:NGL,KB))    ;VG = 0.0_SP
#  if defined (MULTIPROCESSOR)
   IF(PAR)THEN
!     CALL GATHER(LBOUND(UF,1),  UBOUND(UF,1),  N,NGL,KB,MYID,NPROCS,EMAP,UF,UG)
!     CALL GATHER(LBOUND(VF,1),  UBOUND(VF,1),  N,NGL,KB,MYID,NPROCS,EMAP,VF,VG)
     CALL ACOLLECT(MYID,MSRID,NPROCS,EMAP,UF,UG)
     CALL ACOLLECT(MYID,MSRID,NPROCS,EMAP,VF,VG)
   END IF
#  endif
   IF(SERIAL)THEN
     UG(1:NGL,1:KBM1) = UF(1:NGL,1:KBM1)
     VG(1:NGL,1:KBM1) = VF(1:NGL,1:KBM1)
   END IF
!------------------------------------------------------------------------------!
!  Calculate Temporal Weight of Measurement (I) at Time(TIME)                  ! 
!------------------------------------------------------------------------------!
   IF(MSR)THEN
!!JQI   CUR_OBS%T_WEIGHT = 0. 
!!JQI   T_THRESH         = CUR_NG_ASTIME_WINDOW   
!   SIMTIME          = TIME*86400
!!JQI   SIMTIME          = DTI*FLOAT(IINT)

!!JQI   DO I=1,N_ASSIM_CUR       
!!JQI     NTIME = CUR_OBS(I)%N_TIMES
!!JQI     ALLOCATE(FTEMP(NTIME)) 
!     FTEMP(1:NTIME) = ABS(SIMTIME - CUR_OBS(I)%TIMES(1:NTIME))
!!JQI     DO J=1,NTIME
!!JQI        FTEMP(J) = SECONDS(IntTime - CUR_OBS(I)%TIMES(J))
!!JQI        FTEMP(J) = ABS(FTEMP(J))
!!JQI     ENDDO
!!JQI     DT_MIN = MINVAL(FTEMP(1:NTIME))
!!JQI     CUR_OBS(I)%N_T_WEIGHT = MINLOC(FTEMP,DIM=1)

!!JQI     IF(DT_MIN < T_THRESH)THEN     
!!JQI       IF(DT_MIN < .5_SP*T_THRESH) THEN
!!JQI         CUR_OBS(I)%T_WEIGHT = 1.0_SP
!!JQI       ELSE
!!JQI         CUR_OBS(I)%T_WEIGHT = (T_THRESH-DT_MIN)/T_THRESH*2.0_SP
!!JQI       END IF
!!JQI     END IF

!!JQI     DEALLOCATE(FTEMP)
!!JQI   END DO
   
       
!------------------------------------------------------------------------------!
!  Interpolate Simulation Data to Local Observation Point                      ! 
!------------------------------------------------------------------------------!
       
   ALLOCATE(UINT(N_ASSIM_CUR,CUR_MAX_LAYER)) ; UINT = 0. 
   ALLOCATE(VINT(N_ASSIM_CUR,CUR_MAX_LAYER)) ; VINT = 0.

   DO I=1,N_ASSIM_CUR  
     DO J=1,CUR_OBS(I)%N_INTPTS
       J1        = CUR_OBS(I)%INTPTS(J)
       WGHT      = CUR_OBS(I)%X_WEIGHT(J)
       NLAY      = CUR_OBS(I)%N_LAYERS
       DO K=1,NLAY
         U1 = UG(J1,CUR_OBS(I)%S_INT(K,1))
         U2 = UG(J1,CUR_OBS(I)%S_INT(K,2))
         V1 = VG(J1,CUR_OBS(I)%S_INT(K,1))
         V2 = VG(J1,CUR_OBS(I)%S_INT(K,2))
         W1 = CUR_OBS(I)%S_WEIGHT(K,1)
         W2 = CUR_OBS(I)%S_WEIGHT(K,2)
         UINT(I,K) = UINT(I,K) + (U1*W1 + U2*W2)*WGHT 
         VINT(I,K) = VINT(I,K) + (V1*W1 + V2*W2)*WGHT 
       END DO
     END DO
     TOT_WGHT = SUM(CUR_OBS(I)%X_WEIGHT(1:CUR_OBS(I)%N_INTPTS))
     UINT(I,1:NLAY) = UINT(I,1:NLAY)/TOT_WGHT
     VINT(I,1:NLAY) = VINT(I,1:NLAY)/TOT_WGHT
   END DO
     
!------------------------------------------------------------------------------!
!  Compute Local Correction by Interpolating Observed/Computed Defect          ! 
!------------------------------------------------------------------------------!

   ALLOCATE(TWGHT(NGL,KBM1))   ; TWGHT = 0.
   ALLOCATE(UCORR(NGL,KBM1))   ; UCORR   = 0.
   ALLOCATE(VCORR(NGL,KBM1))   ; VCORR   = 0.

   IF(CUR_NGASSIM)THEN
    DO I=1,N_ASSIM_CUR
     DO J=1,CUR_OBS(I)%N_INTPTS
       J1     = CUR_OBS(I)%INTPTS(J)
       ITIMEA  = CUR_OBS(I)%N_T_WEIGHT
       NLAY   = CUR_OBS(I)%N_LAYERS
       DO K=1,NLAY
         IF(ABS(CUR_OBS(I)%UO(ITIMEA,K)) + ABS(CUR_OBS(I)%VO(ITIMEA,K)) >= .0001)THEN  !lwang added
         K1           = CUR_OBS(I)%S_INT(K,1)
         K2           = CUR_OBS(I)%S_INT(K,2)
         W1           = CUR_OBS(I)%S_WEIGHT(K,1)
         W2           = CUR_OBS(I)%S_WEIGHT(K,2)
         WEIGHT1      = CUR_OBS(I)%T_WEIGHT*CUR_OBS(I)%X_WEIGHT(J)*W1
         WEIGHT2      = CUR_OBS(I)%T_WEIGHT*CUR_OBS(I)%X_WEIGHT(J)*W2
         TWGHT(J1,K1) = TWGHT(J1,K1) + WEIGHT1   
         TWGHT(J1,K2) = TWGHT(J1,K2) + WEIGHT2   
         DEFECT       = CUR_OBS(I)%UO(ITIMEA,K) - UINT(I,K)
         CORRECTION   = CUR_GAMA*DEFECT

!         UCORR(J1,K1) = UCORR(J1,K1) + CORRECTION*WEIGHT1
!         UCORR(J1,K2) = UCORR(J1,K2) + CORRECTION*WEIGHT2
         UCORR(J1,K1) = UCORR(J1,K1) + CORRECTION*WEIGHT1*WEIGHT1
         UCORR(J1,K2) = UCORR(J1,K2) + CORRECTION*WEIGHT2*WEIGHT2

         DEFECT       = CUR_OBS(I)%VO(ITIMEA,K) - VINT(I,K)
         CORRECTION   = CUR_GAMA*DEFECT
!         VCORR(J1,K1) = VCORR(J1,K1) + CORRECTION*WEIGHT1
!         VCORR(J1,K2) = VCORR(J1,K2) + CORRECTION*WEIGHT2
         VCORR(J1,K1) = VCORR(J1,K1) + CORRECTION*WEIGHT1*WEIGHT1
         VCORR(J1,K2) = VCORR(J1,K2) + CORRECTION*WEIGHT2*WEIGHT2

!        GEOFF NEW
! lwang modified at Jul 18, 2019
!         IF(ABS(CUR_OBS(I)%UO(ITIMEA,K)) + ABS(CUR_OBS(I)%VO(ITIMEA,K)) < .0001)THEN
!           TWGHT(J1,K1) = 0.
!           TWGHT(J1,K2) = 0.
! lwang
         END IF
       END DO
     END DO
    END DO
!------------------------------------------------------------------------------!
!  Nudge Simulation Data Using Local Corrections                               ! 
!------------------------------------------------------------------------------!

    DO I=1,NGL
     DO K=1,KBM1
       IF(DA_CUR(I) == 1 .AND. TWGHT(I,K) > 1.0E-08)THEN
         UG(I,K) = UG(I,K) + DTI*CUR_GALPHA*UCORR(I,K)/TWGHT(I,K)
         VG(I,K) = VG(I,K) + DTI*CUR_GALPHA*VCORR(I,K)/TWGHT(I,K)
       END IF
     END DO
    END DO

    DEALLOCATE(TWGHT,UCORR,VCORR,UINT,VINT)
   ELSE IF(CUR_OIASSIM)THEN
     DO I=1,N_ASSIM_CUR
       ITIMEA  = CUR_OBS(I)%N_T_WEIGHT
       NLAY   = CUR_OBS(I)%N_LAYERS
       DO K=1,NLAY
         K1           = CUR_OBS(I)%S_INT(K,1)
         K2           = CUR_OBS(I)%S_INT(K,2)
         W1           = CUR_OBS(I)%S_WEIGHT(K,1)
         W2           = CUR_OBS(I)%S_WEIGHT(K,2)
         WEIGHT1      = CUR_OBS(I)%T_WEIGHT*W1
         WEIGHT2      = CUR_OBS(I)%T_WEIGHT*W2
         TWGHT(I,K1) = TWGHT(I,K1) + WEIGHT1   
         TWGHT(I,K2) = TWGHT(I,K2) + WEIGHT2   
         DEFECT       = CUR_OBS(I)%UO(ITIMEA,K) - UINT(I,K)
         CORRECTION   = DEFECT
         UCORR(I,K1) = UCORR(I,K1) + CORRECTION*WEIGHT1
         UCORR(I,K2) = UCORR(I,K2) + CORRECTION*WEIGHT2
         DEFECT       = CUR_OBS(I)%VO(ITIMEA,K) - VINT(I,K)
         CORRECTION   = DEFECT
         VCORR(I,K1) = VCORR(I,K1) + CORRECTION*WEIGHT1
         VCORR(I,K2) = VCORR(I,K2) + CORRECTION*WEIGHT2
         IF(ABS(CUR_OBS(I)%UO(ITIMEA,K)) + ABS(CUR_OBS(I)%VO(ITIMEA,K)) < .0001)THEN
           TWGHT(I,K1) = 0.
           TWGHT(I,K2) = 0.
         END IF
       END DO
     END DO

     DO I=1,N_ASSIM_CUR
       DO K=1,KBM1
         IF(TWGHT(I,K) > 1.0E-8)THEN
           UCORR(I,K)=UCORR(I,K)/TWGHT(I,K)
	   VCORR(I,K)=VCORR(I,K)/TWGHT(I,K)
         END IF
       END DO
     END DO
       	 
!------------------------------------------------------------------------------!
!  Simulation Data Using Local Corrections                               ! 
!------------------------------------------------------------------------------!
     ALLOCATE(UCORR1(NGL,KBM1));UCORR1=0.0_SP
     ALLOCATE(VCORR1(NGL,KBM1));VCORR1=0.0_SP
   
     DO K=1,KBM1
       CALL CUR_OPTIMINTERP(UCORR(:,K),VCORR(:,K),UCORR1(:,K),VCORR1(:,K))
     END DO

     DO I=1,NGL
       DO K=1,KBM1
         IF(DA_CUR(I) == 1)THEN
!          UG(I,K) = UG(I,K)+UCORR1(I,K)
!          VG(I,K) = VG(I,K)+VCORR1(I,K)
           UG(I,K) = UG(I,K)+ CUR_OIGALPHA*UCORR1(I,K)
           VG(I,K) = VG(I,K)+ CUR_OIGALPHA*VCORR1(I,K)
         END IF
       END DO
     END DO

     DEALLOCATE(TWGHT,UCORR,VCORR,UINT,VINT)
     DEALLOCATE(UCORR1,VCORR1)
   ELSE
     WRITE(IPT,*)'EITHER CUR_NGASSIM OR CUR_OIASSIM SHOULD BE SET AS TRUE'
     CALL PSTOP
   END IF
   END IF  !!MASTER
!------------------------------------------------------------------------------!
!  Disperse New Data Fields to Slave Processors                                ! 
!------------------------------------------------------------------------------!
   IF(SERIAL)THEN
     UF(1:N,1:KBM1) = UG(1:N,1:KBM1)
     VF(1:N,1:KBM1) = VG(1:N,1:KBM1)
   END IF
#  if defined (MULTIPROCESSOR) 
!QXU{
   CALL MPI_BARRIER(MPI_FVCOM_GROUP,IERR)
!QXU}
   CALL MPI_BCAST(UG,(NGL+1)*KB,MPI_F,0,MPI_FVCOM_GROUP,IERR)
   CALL MPI_BCAST(VG,(NGL+1)*KB,MPI_F,0,MPI_FVCOM_GROUP,IERR)
!QXU{
   CALL MPI_BARRIER(MPI_FVCOM_GROUP,IERR)
!QXU}

   IF(PAR)THEN
     DO I=1,N
       UF(I,1:KBM1) = UG(EGID(I),1:KBM1)
       VF(I,1:KBM1) = VG(EGID(I),1:KBM1)
     END DO
   END IF
#  endif
   DEALLOCATE(UG,VG)
          
   IF (DBG_SET(DBG_SBR)) WRITE(IPT,*) "END: CURRENT_ASSIMILATION" 
     
   RETURN
   END SUBROUTINE CURRENT_ASSIMILATION

!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|

!==============================================================================|
!==============================================================================|
   SUBROUTINE CUR_OPTIMINTERP(F1,F2,FI1,FI2)
   USE MOD_OPTIMAL_INTERPOLATION
   IMPLICIT NONE

!------------------------------------------------------------------------------|
!  xi(1,:) and xi(2,:) represent the x and y coordindate of the grid of the    |
!  interpolated field                                                          |
!  fi and vari are the interpolated field and its error variance resp.         |
!------------------------------------------------------------------------------|
   REAL(SP) :: XI(2,NGL),FI1(NGL),FI2(NGL),VARI(NGL)

!------------------------------------------------------------------------------|
!  x(1,:) and x(2,:) represent the x and y coordindate of the observations     |
!  f and var are observations and their error variance resp.                   |
!------------------------------------------------------------------------------|
   REAL(SP) :: X(2,N_ASSIM_CUR),VAR(N_ASSIM_CUR),F1(N_ASSIM_CUR),F2(N_ASSIM_CUR)

!------------------------------------------------------------------------------|
!  param: inverse of the correlation length                                    |
!------------------------------------------------------------------------------|
   REAL(SP) :: PARAM(2,N_ASSIM_CUR)

   INTEGER  :: I,J,MM

   IF (DBG_SET(DBG_SBR)) WRITE(IPT,*) "START: CUR_OPTIMINTERP" 
!------------------------------------------------------------------------------|
!  create a regular 2D grid                                                    |
!------------------------------------------------------------------------------|
   DO I=1,NGL
     XI(1,I) = XCG(I)
     XI(2,I) = YCG(I)
   END DO	
   
!------------------------------------------------------------------------------|   
!  param is the inverse of the correlation length                              |
!------------------------------------------------------------------------------|
   PARAM = 1.0_SP/CUR_PARAM 
   MM = CUR_N_INFLU
 
!------------------------------------------------------------------------------| 
!  the error variance of the observations                                      |
!------------------------------------------------------------------------------|
   VAR = 0.0_SP   

   DO I=1,N_ASSIM_CUR
     X(1,I) = CUR_OBS(I)%X
     X(2,I) = CUR_OBS(I)%Y
   END DO  

!------------------------------------------------------------------------------|
!  fi is the interpolated function and vari its error variance                 |
!------------------------------------------------------------------------------|
   CALL OPTIMINTERP(X,F1,VAR,PARAM,MM,XI,FI1,VARI)
   CALL OPTIMINTERP(X,F2,VAR,PARAM,MM,XI,FI2,VARI)

   IF (DBG_SET(DBG_SBR)) WRITE(IPT,*) "END: CUR_OPTIMINTERP" 
   RETURN
   END SUBROUTINE CUR_OPTIMINTERP
!==============================================================================|
!==============================================================================|

!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|


   SUBROUTINE SET_TS_ASSIM_DATA 

!------------------------------------------------------------------------------!
!  SET UP ASSIMILATION DATA FOR TEMP/SAL OBSERVATIONS                          |
!------------------------------------------------------------------------------!
   IMPLICIT NONE
   INTEGER I,J,K,ECNT,ITMP,NCNT,IOS,NLAY
   CHARACTER(LEN=120) :: FNAME,ONAME
   CHARACTER(LEN= 2 ) :: NAC   
   INTEGER,  ALLOCATABLE, DIMENSION(:) :: ITEMP
   REAL(SP), ALLOCATABLE, DIMENSION(:) :: FTEMP
   REAL(SP):: X0,Y0,DX,DY,RD,SIGMA_C,ISOBATH_ANGLE,D_ANGLE,ANG_OBS_SIM,DIR_WEIGHT
   REAL(SP), PARAMETER :: ALF = 0.05_SP
   LOGICAL :: FEXIST
   INTEGER :: MAXEL,NBD_CNT
   REAL(SP) :: TS_RADIUS 
   INTEGER :: JMIN 
   REAL(SP):: LMIN

   REAL(SP), DIMENSION(1:NGL,1) :: RDLIST
   REAL(SP), DIMENSION(3) :: XTRI,YTRI
   REAL(SP) :: RDLAST
   INTEGER :: LOCIJ(2),MIN_LOC,JJ,IERR,Nsite_tmp
   INTEGER :: ND1,ND2,ND3,NN
   REAL(SP) :: DELTA,COFA,COFB,COFC
   REAL(SP) ::S11,S22,S33,RTMP,RRTMP
   REAL(SP), DIMENSION(KB) :: ZZ_OB
!#  if defined (MULTIPROCESSOR)   
   REAL(SP), ALLOCATABLE :: ZZ_G(:,:)  
!# endif
   REAL(SP) :: X0C,Y0C,HX,HY,H0,TEMP_H
   REAL(DP) :: ODAYS

   REAL(SP) :: X11_TMP, X22_TMP, X33_TMP
      
   IF(DBG_SET(DBG_SBR)) write(ipt,*) "START: SET_TS_ASSIM_DATA" 

!------------------------------------------------------------------------------!
!  Read Number of Scalar Observations and Coordinates of Each                  !
!------------------------------------------------------------------------------!
       
!   FNAME = "./"//TRIM(INPUT_DIR)//"/"//trim(casename)//"_ts.xy"
   IF(TS_NGASSIM .AND. .NOT. TS_OIASSIM)THEN
     FNAME = "./"//TRIM(INPUT_DIR)//"/"//trim(TS_NGASSIM_FILE)//".xy"
   ELSE IF(TS_OIASSIM .AND. .NOT. TS_NGASSIM)THEN
     FNAME = "./"//TRIM(INPUT_DIR)//"/"//trim(TS_OIASSIM_FILE)//".xy"
   ELSE
     CALL FATAL_ERROR("TS_NGASSIM and TS_OIASSIM cannot be both true or false")
   END IF  
!
!--Make Sure Temperature and Salinity Assimilation Data File Exists-----------------------------!
!
   INQUIRE(FILE=TRIM(FNAME),EXIST=FEXIST)
   IF(MSR .AND. .NOT.FEXIST)THEN
     WRITE(IPT,*)'TEMP/SALINITY OBSERVATION FILE: ',FNAME,' DOES NOT EXIST'
     WRITE(IPT,*)'HALTING.....'
     CALL PSTOP
   END IF
     
!
!--Read Number of T/S Measurement Stations---------------------------------!
!
   OPEN(1,FILE=TRIM(FNAME),STATUS='OLD')
   READ(1,*) N_ASSIM_TS                  !nomber of TS Obs station
   ALLOCATE(TS_OBS(N_ASSIM_TS))          !Type for TS_OBS

!
!--Read X,Y Coordinate of Measurement Stations---------------------------------!
!
   DO I=1,N_ASSIM_TS  
     READ(1,*)ITMP,TS_OBS(I)%X,TS_OBS(I)%Y,TS_OBS(I)%DEPTH,NLAY,TS_OBS(I)%SITA
     TS_OBS(I)%N_LAYERS = NLAY
     ALLOCATE(TS_OBS(I)%ODEPTH(NLAY))
     DO J=1,NLAY
       READ(1,*)TS_OBS(I)%ODEPTH(J)
       IF(TS_OBS(I)%ODEPTH(J) > TS_OBS(I)%DEPTH)THEN
         IF(MSR)WRITE(IPT,*)'OBSERVATION DEPTH',J,'OF TEMP/SALINITY OBS',I
         IF(MSR)WRITE(IPT,*)'EXCEEDS BATHYMETRIC DEPTH=',TS_OBS(I)%ODEPTH(J),TS_OBS(I)%DEPTH
         IF(MSR)WRITE(IPT,*)'HALTING...........'
         CALL PSTOP
       END IF
     END DO
   END DO
   TS_MAX_LAYER = MAXVAL(TS_OBS(1:N_ASSIM_TS)%N_LAYERS)

!
!--Shift Coordinates-----------------------------------------------------------!
!
# if !defined (SPHERICAL) 
   TS_OBS(:)%X = TS_OBS(:)%X - VXMIN 
   TS_OBS(:)%Y = TS_OBS(:)%Y - VYMIN 
# endif
   
!# if defined (SPHERICAL) 
   IF(SERIAL)THEN
     XCG = XC
     YCG = YC
     XG = VX
     YG = VY
   END IF
#  if defined(MULTIPROCESSOR)
   IF(PAR)CALL ACOLLECT(MYID,MSRID,NPROCS,EMAP,XC,XCG)
   IF(PAR)CALL ACOLLECT(MYID,MSRID,NPROCS,EMAP,YC,YCG)
   IF(PAR)CALL ACOLLECT(MYID,MSRID,NPROCS,NMAP,VX,XG)
   IF(PAR)CALL ACOLLECT(MYID,MSRID,NPROCS,NMAP,VY,YG)
   IF(PAR)CALL MPI_BCAST(XCG,NGL+1,MPI_F,0,MPI_FVCOM_GROUP,IERR)
   IF(PAR)CALL MPI_BCAST(YCG,NGL+1,MPI_F,0,MPI_FVCOM_GROUP,IERR)
   IF(PAR)CALL MPI_BCAST(XG,MGL+1,MPI_F,0,MPI_FVCOM_GROUP,IERR)
   IF(PAR)CALL MPI_BCAST(YG,MGL+1,MPI_F,0,MPI_FVCOM_GROUP,IERR)
#  endif
!# endif
!  
!
!--find the cell number (TS_OBS(:)%N_CELL) of Obs station---------------------
!
   RRTMP = 100000.0     !100km
!   IF(TS_NGASSIM)THEN
!       RRTMP = TS_NG_RADIUS
!   ELSE IF(TS_OIASSIM)THEN
!       RRTMP = TS_OI_RADIUS
!   ELSE
!       WRITE(IPT,*) 'IN SUBROUTINE SET_TS_ASSIM_DATA, ONE OF TS_NGASSIM AND &
!                         TS_OIASSIM MUST BE DEFINED AS TRUE.'
!      WRITE(IPT,*) 'HALTING.....'            
!       CALL PSTOP
!   END IF

   DO J= 1,N_ASSIM_TS 
     X0 = TS_OBS(J)%X
     Y0 = TS_OBS(J)%Y
     INLOOP: DO I=1,NGL   
#    if !defined (SPHERICAL)
       Rtmp = SQRT((XCG(I)-X0)*(XCG(I)-X0)+(YCG(I)-Y0)*(YCG(I)-Y0))
#    else
       CALL ARC(X0,Y0,XCG(I),YCG(I),Rtmp)
#    endif
       IF(Rtmp < RRTMP) THEN
         X11_TMP = XG(NVG(I,1))-X0
         X22_TMP = XG(NVG(I,2))-X0
         X33_TMP = XG(NVG(I,3))-X0 
#        if defined (SPHERICAL)
         IF(X11_TMP >  180.0_SP)THEN
           X11_TMP = -360.0_SP+X11_TMP
         ELSEIF(X11_TMP < -180.0_SP)THEN
           X11_TMP =  360.0_SP+X11_TMP
         END IF
         IF(X22_TMP >  180.0_SP)THEN
           X22_TMP = -360.0_SP+X22_TMP
         ELSEIF(X22_TMP < -180.0_SP)THEN
           X22_TMP =  360.0_SP+X22_TMP
         END IF
         IF(X33_TMP >  180.0_SP)THEN
           X33_TMP = -360.0_SP+X33_TMP
         ELSEIF(X33_TMP < -180.0_SP)THEN
           X33_TMP =  360.0_SP+X33_TMP
         END IF
#        endif
         S11 = X22_TMP*(YG(NVG(I,3))-Y0)-X33_TMP*(YG(NVG(I,2))-Y0)
         S22 = X33_TMP*(YG(NVG(I,1))-Y0)-X11_TMP*(YG(NVG(I,3))-Y0)
         S33 = X11_TMP*(YG(NVG(I,2))-Y0)-X22_TMP*(YG(NVG(I,1))-Y0)
         IF(S11 <= 0._SP .AND. S22 <= 0._SP .AND. S33 <= 0._SP) THEN
           TS_OBS(J)%N_CELL = I
           EXIT INLOOP      
         ELSE
           TS_OBS(J)%N_CELL = 0
         ENDIF
       ELSE
         TS_OBS(J)%N_CELL = -1
       ENDIF
     END DO INLOOP      
     IF(TS_OBS(J)%N_CELL <= 0) THEN
       IF(MSR) WRITE(IPT,*)'ERROR--T/S OBS SITE:',J,' OUT OF DOMAN',&
                            TS_OBS(J)%N_CELL 
       CALL PSTOP
     ENDIF

   ENDDO             
!--Gather AW0G,AWXG & AWYG use for interp grid to Obs station
   IF(.NOT. ALLOCATED(AW0G)) ALLOCATE(AW0G(0:NGL,3))
   IF(.NOT. ALLOCATED(AWXG)) ALLOCATE(AWXG(0:NGL,3))
   IF(.NOT. ALLOCATED(AWYG)) ALLOCATE(AWYG(0:NGL,3))
   
   IF(SERIAL)THEN
     AW0G = AW0
     AWXG = AWX
     AWYG = AWY
   END IF
#  if defined (MULTIPROCESSOR)
   IF(PAR)THEN     
     CALL ACOLLECT(MYID,MSRID,NPROCS,EMAP,AW0,AW0G)
     CALL ACOLLECT(MYID,MSRID,NPROCS,EMAP,AWX,AWXG)
     CALL ACOLLECT(MYID,MSRID,NPROCS,EMAP,AWY,AWYG)
     CALL MPI_BCAST(AW0G,(NGL+1)*3,MPI_F,0,MPI_FVCOM_GROUP,IERR)
     CALL MPI_BCAST(AWXG,(NGL+1)*3,MPI_F,0,MPI_FVCOM_GROUP,IERR)
     CALL MPI_BCAST(AWYG,(NGL+1)*3,MPI_F,0,MPI_FVCOM_GROUP,IERR)
   END IF
#  endif     
!
!--Close Current Observation Global File---------------------------------------!
!
   CLOSE(1)
       
   IF(TS_OIASSIM)THEN
!------------------------------------------------------------------------------!
!  Read Correlation Length of Scalar Observations                             !
!------------------------------------------------------------------------------!
       
!JQI   FNAME = "./"//TRIM(INPDIR)//"/"//trim(casename)//"_radius_ts.dat"

!JQI   INQUIRE(FILE=TRIM(FNAME),EXIST=FEXIST)
!JQI   IF(MSR .AND. .NOT.FEXIST)THEN
!JQI     WRITE(IPT,*)'CURRENT OBSERVATION FILE: ',FNAME,' DOES NOT EXIST'
!JQI     WRITE(IPT,*)'HALTING.....'
!JQI     CALL PSTOP
!JQI   END IF
     
!JQI   OPEN(1,FILE=TRIM(FNAME),STATUS='OLD')

   ALLOCATE(TS_PARAM(2,N_ASSIM_TS))

!JQI   DO I=1,N_ASSIM_TS
!JQI     READ(1,*)TS_PARAM(1,I),TS_PARAM(2,I)
!JQI   END DO

!JQI   CLOSE(1)
     TS_PARAM = TS_OI_RADIUS        !30000.0_SP
! lwang added for gom5
     DO I=1,N_ASSIM_TS
        if(TS_OBS(I)%DEPTH<=10.0)then
          TS_PARAM(:,I)=500.0
        else if (TS_OBS(I)%DEPTH>10.0 .and. TS_OBS(I)%DEPTH<=20.0)then
          TS_PARAM(:,I)=200.0*TS_OBS(I)%DEPTH
        else if (TS_OBS(I)%DEPTH>20.0 .and. TS_OBS(I)%DEPTH<=50.0)then
          TS_PARAM(:,I)=250.0*TS_OBS(I)%DEPTH
        endif
!        ! added for gom5 201701
!        if(TS_OBS(I)%X+VXMIN>=161300.0 .and. TS_OBS(I)%X+VXMIN<=326400.0 .and. &
!           TS_OBS(I)%Y+VYMIN>=-1079800.0 .and. TS_OBS(I)%Y+VYMIN<=-868600.0 &
!           .and. TS_OBS(I)%DEPTH<=20.0)then
!          TS_PARAM(:,I)=5000.0
!        endif
!        ! added for gom5 201704
!        if(TS_OBS(I)%X+VXMIN>=626550.0 .and. TS_OBS(I)%X+VXMIN<=736590.0 .and. &
!           TS_OBS(I)%Y+VYMIN>=-245030.0 .and. TS_OBS(I)%Y+VYMIN<=-215910.0 &
!           .and. TS_OBS(I)%DEPTH<=20.0)then
!          TS_PARAM(:,I)=5000.0
!        endif
!        ! added for gom5 201706
!        if(TS_OBS(I)%X+VXMIN>=1007800.0 .and. TS_OBS(I)%X+VXMIN<=1165900.0 .and. &
!           TS_OBS(I)%Y+VYMIN>=-657800.0 .and. TS_OBS(I)%Y+VYMIN<=-607600.0) then
!          TS_PARAM(:,I)=30000.0
!        endif
!        ! added for gom5 201711
!        if(TS_OBS(I)%X+VXMIN>=1456700.0 .and. TS_OBS(I)%X+VXMIN<=1603500.0 .and. &
!           TS_OBS(I)%Y+VYMIN>=-357400.0 .and. TS_OBS(I)%Y+VYMIN<=-215800.0) then
!          TS_PARAM(:,I)=30000.0
!        endif
!        ! added for gom5 201712
!        if(TS_OBS(I)%X+VXMIN>=1573200.0 .and. TS_OBS(I)%X+VXMIN<=1754800.0 .and. &
!          TS_OBS(I)%Y+VYMIN>=-351500.0 .and. TS_OBS(I)%Y+VYMIN<=-226100.0) then
!          TS_PARAM(:,I)=30000.0
!        endif
     END DO
! lwang

   END IF
   
!------------------------------------------------------------------------------!
!  Open Temp/Sal Observation Files for Each Observation Point and Read Data    !
!------------------------------------------------------------------------------!

!----Make Sure Temperature/Salinity Observation File Exists--------------------!
   IF(TS_NGASSIM .AND. .NOT. TS_OIASSIM)THEN
     ONAME = "./"//TRIM(INPUT_DIR)//"/"//trim(TS_NGASSIM_FILE)//".dat"
   ELSE IF(TS_OIASSIM .AND. .NOT. TS_NGASSIM)THEN
     ONAME = "./"//TRIM(INPUT_DIR)//"/"//trim(TS_OIASSIM_FILE)//".dat"
   ELSE
     CALL FATAL_ERROR("TS_NGASSIM and TS_OIASSIM cannot be both true or false")
   END IF  
   INQUIRE(FILE=TRIM(ONAME),EXIST=FEXIST)
   IF(MSR .AND. .NOT.FEXIST)THEN
     WRITE(IPT,*)'TEMP/SALINITY OBSERVATION FILE: ',ONAME,' DOES NOT EXIST'
     WRITE(IPT,*)'HALTING.....'
     CALL PSTOP
   END IF
!----Open Temp/Salinity Observation File for Read------------------------------!
   OPEN(1,FILE=ONAME,STATUS='old')  ; REWIND(1)

   DO I=1,N_ASSIM_TS
     READ(1,*,IOSTAT=IOS) nsite_tmp,NCNT
     IF(IOS<0) then
       WRITE(IPT,*) 'ERROR in read ',trim(casename),'_ts.dat at site number:',I
       CALL PSTOP
     ENDIF
     TS_OBS(I)%N_TIMES = NCNT
      
     IF(NCNT == 0)THEN
       IF(MSR)WRITE(IPT,*)'NO DATA FOR TS OBSERVATION',I
       CALL PSTOP
     END IF

!----Allocate Arrays to Hold Temp/Salinity (TEMP/SAL) and Time (TIME)----------!
     ALLOCATE(TS_OBS(I)%TIMES(TS_OBS(I)%N_TIMES))
     ALLOCATE(TS_OBS(I)%TEMP( TS_OBS(I)%N_TIMES , TS_OBS(I)%N_LAYERS ))
     ALLOCATE(TS_OBS(I)%SAL(  TS_OBS(I)%N_TIMES , TS_OBS(I)%N_LAYERS ))

!----Read in Current Data for Observation I------------------------------------!
     NLAY = TS_OBS(I)%N_LAYERS
     DO J=1,TS_OBS(I)%N_TIMES
       READ(1,*,IOSTAT=IOS)ODAYS,(TS_OBS(I)%TEMP(J,K),TS_OBS(I)%SAL(J,K),K=1,NLAY)
       IF(IOS < 0) THEN         ! ios=0 if all goes ok.
         WRITE(IPT,*)'ERROR in read ',trim(casename),'_ts.dat at site:',I,  &
                     'Time No:',J
         CALL PSTOP
       ENDIF  
       TS_OBS(I)%TIMES(J) = DAYS2TIME(ODAYS)
     END DO
     

!----Convert Time to Seconds---------------------------------------------------!
!----Shift Jan 1 Based Time Data to Dec 1 Based Time Data-----CASESPECIFIC-----!
!     IF(trim(CASENAME) == 'gom')THEN
!       TS_OBS(I)%TIMES = ((TS_OBS(I)%TIMES-1.0_SP)*24.0_SP+744.0_SP)*3600.0_SP
!     ELSE   
!       TS_OBS(I)%TIMES = TS_OBS(I)%TIMES*3600.0_SP*24.0_SP
!     END IF
 
!----Convert Temperature and Salinity to PSU/Celsius-(If Necessary)------------!
     TS_OBS(I)%TEMP = TS_OBS(I)%TEMP 
     TS_OBS(I)%SAL  = TS_OBS(I)%SAL  
  END DO
  CLOSE(1)

!------------------------------------------------------------------------------!
!  Count Number of Points with Bad Data (TEMP = 0. .OR. SAL = 0.)         
!------------------------------------------------------------------------------!
  NBD_CNT = 0
  DO I=1,N_ASSIM_TS
    DO J=1,TS_OBS(I)%N_TIMES
      DO K=1,TS_OBS(I)%N_LAYERS
        IF(TS_OBS(I)%TEMP(J,K) < -90. .OR. TS_OBS(I)%SAL(J,K) < -90.) THEN
          NBD_CNT = NBD_CNT + 1
        END IF
      END DO
    END DO
  END DO
 
!------------------------------------------------------------------------------!
!  Compute Spatial Interpolation Weights for each Mooring Location 
!------------------------------------------------------------------------------!
!   LMIN = 100000000.
!   DO I=1,N_ASSIM_TS
!     X0 = TS_OBS(I)%X
!     Y0 = TS_OBS(I)%Y
!     DO J=1,MGL
!       DX = ABS(XG(J)-X0)
!       DY = ABS(YG(J)-Y0)
!       IF(SQRT(DX**2 + DY**2) < LMIN)THEN
!         LMIN = SQRT(DX**2 + DY**2)
!         JMIN = J
!       END IF
!      END DO
!      TS_OBS(I)%SITA = SITA_GD(JMIN) + 3.14159_SP/2.0_SP
!    end do


   ALLOCATE(ITEMP(MGL),FTEMP(MGL),DA_TS(MGL))     ; DA_TS = 0

   DO I=1,N_ASSIM_TS
     X0 = TS_OBS(I)%X
     Y0 = TS_OBS(I)%Y
     ISOBATH_ANGLE = TS_OBS(I)%SITA*DEG2RAD        !/180.0_SP*3.1415926_SP
     ECNT = 0
     DO J=1,MGL
#      if defined (SPHERICAL)
       CALL ARCX(X0,Y0,XG(J),YG(J),DX)
       CALL ARCY(X0,Y0,XG(J),YG(J),DY)
       CALL ARC(X0,Y0,XG(J),YG(J),RD)
#      else
       DX = ABS(XG(J)-X0)
       DY = ABS(YG(J)-Y0)
       RD = SQRT(DX**2 + DY**2)
#      endif

       IF(TS_NGASSIM)THEN
         TS_RADIUS = TS_NG_RADIUS
       ELSE IF(TS_OIASSIM)THEN
         TS_RADIUS = TS_OI_RADIUS
       ELSE
!JQI         WRITE(IPT,*) 'IN SUBROUTINE SET_TS_ASSIM_DATA, ONE OF TS_NGASSIM AND ',&
!JQI	              'TS_OIASSIM MUST BE DEFINED AS TRUE.'
         WRITE(IPT,*) 'IN SUBROUTINE SET_TS_ASSIM_DATA, ONE OF TS_NGASSIM AND TS_OIASSIM MUST BE DEFINED AS TRUE.'
         WRITE(IPT,*) 'HALTING.....'       
         CALL PSTOP
       END IF 

! added by lwang for gom5
       if(TS_OBS(I)%DEPTH<=10.0)then
          TS_RADIUS=500.0
       else if (TS_OBS(I)%DEPTH>10.0 .and. TS_OBS(I)%DEPTH<=20.0)then
          TS_RADIUS=200.0*TS_OBS(I)%DEPTH   
       else if (TS_OBS(I)%DEPTH>20.0 .and. TS_OBS(I)%DEPTH<=50.0)then
          TS_RADIUS=250.0*TS_OBS(I)%DEPTH
       endif
!        ! added for gom5 201701
!       if(X0+VXMIN>= 161300.0 .and. X0+VXMIN<= 326400.0 .and. &
!          Y0+VYMIN>= -1079800.0 .and. Y0+VYMIN<=-868600.0 .and. &
!          TS_OBS(I)%DEPTH<=20.0)then
!          TS_RADIUS=5000.0
!       endif
!        ! added for gom5 201704
!       if(X0+VXMIN>=626550.0 .and. X0+VXMIN<=736590.0 .and. &
!          Y0+VYMIN>=-245030.0 .and. Y0+VYMIN<=-215910.0 .and. &
!          TS_OBS(I)%DEPTH<=20.0)then
!          TS_RADIUS=5000.0
!       endif
!        ! added for gom5 201706
!        if(X0+VXMIN>=1007800.0 .and. X0+VXMIN<=1165900.0 .and. &
!           Y0+VYMIN>=-657800.0 .and. Y0+VYMIN<=-607600.0)then
!          TS_RADIUS=30000.0
!        endif
!        ! added for gom5 201711
!        if(X0+VXMIN>=1456700.0 .and. X0+VXMIN<=1603500.0 .and. &
!           Y0+VYMIN>=-357400.0 .and. Y0+VYMIN<=-215800.0)then
!          TS_RADIUS=30000.0
!        endif
!        ! added for gom5 201712
!        if(X0+VXMIN>=1573200.0 .and. X0+VXMIN<=1754800.0 .and. &
!           Y0+VYMIN>=-351500.0 .and. Y0+VYMIN<=-226100.0)then
!          TS_RADIUS=30000.0
!        endif
!        ! added for great bay
!        if(X0+VXMIN>=850410.0 .and. X0+VXMIN<=876770.0 .and. &
!           Y0+VYMIN>=10950.0 .and. Y0+VYMIN<=31490.0 .and. &
!           TS_OBS(I)%DEPTH>=50.0)then
!          TS_RADIUS=11000.0
!        endif
! lwang
         
       IF(RD <= TS_RADIUS)THEN
         DA_TS(J)   = 1
         ECNT        = ECNT + 1      
         ITEMP(ECNT) =  J
         FTEMP(ECNT) = (TS_RADIUS**2 - RD**2) / (TS_RADIUS**2 + RD**2)
         IF(ISOBATH_ANGLE==0)THEN
           DIR_WEIGHT = 1.0_SP
         ELSE
           ANG_OBS_SIM = ATAN2(DY,DX)
           D_ANGLE     = ANG_OBS_SIM - ISOBATH_ANGLE
           D_ANGLE     = D_ANGLE - INT(D_ANGLE/PI)*PI      !3.1415926_SP)*3.1415926_SP
           D_ANGLE     = ABS(D_ANGLE)
!           DIR_WEIGHT  = (ABS(D_ANGLE-0.5*3.1415926_SP)+ALF*3.1415926_SP)/ &
!                         ((0.5_SP+ALF)*3.1415926_SP)
           DIR_WEIGHT  = (ABS(D_ANGLE-0.5*PI)+ALF*PI)/((0.5_SP+ALF)*PI)
!           IF(J==TS_OBS(J)%N_CELL)DIR_WEIGHT = 1.0_SP
         END IF
         FTEMP(ECNT) = FTEMP(ECNT)*DIR_WEIGHT
       END IF
     END DO

     !---> Siqi Li, 20221101
     ! Make sure all the observation can at least influence one
     ! node, especially at the boundary, where the resolution is
     ! relatively low.
     IF (ECNT ==0) THEN
         K = TS_OBS(I)%N_CELL
#      if defined (SPHERICAL) 
         ! Siqi Li, OI@20230920
         CALL ARC(X0,Y0,XG(NVG(K, 1)),YG(NVG(K, 1)),XTRI(1))
         CALL ARC(X0,Y0,XG(NVG(K, 2)),YG(NVG(K, 2)),XTRI(2))
         CALL ARC(X0,Y0,XG(NVG(K, 3)),YG(NVG(K, 3)),XTRI(3))
#      else
         XTRI(1) = SQRT( (X0 - XG(NVG(K, 1)))**2 + (Y0 - YG(NVG(K, 1)))**2 )
         XTRI(2) = SQRT( (X0 - XG(NVG(K, 2)))**2 + (Y0 - YG(NVG(K, 2)))**2 )
         XTRI(3) = SQRT( (X0 - XG(NVG(K, 3)))**2 + (Y0 - YG(NVG(K, 3)))**2 )
#      endif
         DO K = 1, 3
             IF (TS_RADIUS < XTRI(K)) THEN
                 J = K
                 TS_RADIUS = XTRI(K)
             END IF
         END DO
         J = NVG(K, J)
#      if defined (SPHERICAL)
         CALL ARCX(X0,Y0,XG(J),YG(J),DX)
         CALL ARCY(X0,Y0,XG(J),YG(J),DY)
#      else
         DX = ABS(XG(J)-X0)
         DY = ABS(YG(J)-Y0)
#      endif
         DA_TS(J) = 1
         ECNT = ECNT + 1
         ITEMP(ECNT) = J
         FTEMP(ECNT) = (TS_RADIUS**2 - RD**2) / (TS_RADIUS**2 + RD**2)
         IF(ISOBATH_ANGLE==0)THEN
           DIR_WEIGHT = 1.0_SP
         ELSE
           ANG_OBS_SIM = ATAN2(DY,DX)
           D_ANGLE     = ANG_OBS_SIM - ISOBATH_ANGLE
           D_ANGLE     = D_ANGLE - INT(D_ANGLE/PI)*PI !3.1415926_SP)*3.1415926_SP
           D_ANGLE     = ABS(D_ANGLE)
!           DIR_WEIGHT  = (ABS(D_ANGLE-0.5*3.1415926_SP)+ALF*3.1415926_SP)/ &
!                         ((0.5_SP+ALF)*3.1415926_SP)
           DIR_WEIGHT  = (ABS(D_ANGLE-0.5*PI)+ALF*PI)/((0.5_SP+ALF)*PI)
!           IF(J==TS_OBS(J)%N_CELL)DIR_WEIGHT = 1.0_SP
         END IF
         FTEMP(ECNT) = FTEMP(ECNT)*DIR_WEIGHT
     END IF
     !<--- Siqi Li

     IF(ECNT == 0)THEN
       WRITE(IPT,*)'ERROR SETTING UP TEMP/SAL DATA ASSIMILATION'
       WRITE(IPT,*)'NO NODES LIE WITHIN RADIUS',TS_RADIUS
       WRITE(IPT,*)'OF OBSERVATION POINT',I
       CALL PSTOP   
     ELSE
       TS_OBS(I)%N_INTPTS = ECNT
       ALLOCATE(TS_OBS(I)%INTPTS(ECNT))
       ALLOCATE(TS_OBS(I)%X_WEIGHT(ECNT))
       TS_OBS(I)%INTPTS(1:ECNT)  = ITEMP(1:ECNT)
       TS_OBS(I)%X_WEIGHT(1:ECNT) = FTEMP(1:ECNT)
     END IF
   END DO
   DEALLOCATE(FTEMP,ITEMP)

!------------------------------------------------------------------------------!
!  Compute Sigma Layer Weights for Vertical Interpolation            
!------------------------------------------------------------------------------!
   ALLOCATE(ZZ_G(0:MGL,KB))  
   IF(.NOT. ALLOCATED(HG)) ALLOCATE(HG(0:MGL))
   IF(SERIAL)THEN
     ZZ_G = ZZ
     HG = H
   END IF      
#  if defined (MULTIPROCESSOR)   
   IF(PAR)CALL ACOLLECT(MYID,MSRID,NPROCS,NMAP,ZZ,ZZ_G)
   IF(PAR)CALL ACOLLECT(MYID,MSRID,NPROCS,NMAP,H,HG) 
   IF(PAR)CALL MPI_BCAST(ZZ_G,(MGL+1)*KB,MPI_F,0,MPI_FVCOM_GROUP,IERR)
   IF(PAR)CALL MPI_BCAST(HG,MGL+1,MPI_F,0,MPI_FVCOM_GROUP,IERR)
#  endif

   DO I=1,N_ASSIM_TS
     NLAY = TS_OBS(I)%N_LAYERS
     ALLOCATE(TS_OBS(I)%S_INT(NLAY,2))
     ALLOCATE(TS_OBS(I)%S_WEIGHT(NLAY,2))
     
     X0 = TS_OBS(I)%X
     Y0 = TS_OBS(I)%Y
# if defined (SPHERICAL)
     DO NN=1,NGL
       CALL ARC(X0,Y0,XCG(NN),YCG(NN),RDLIST(NN,1))
     END DO
# else
     RDLIST(1:NGL,1) = SQRT((XCG(1:NGL)-X0)**2 + (YCG(1:NGL)-Y0)**2)
# endif
     RDLAST = -1.0_SP
in:  DO WHILE(.TRUE.)
       LOCIJ = MINLOC(RDLIST,RDLIST>RDLAST)
       MIN_LOC = LOCIJ(1)
       IF(MIN_LOC == 0)THEN
         EXIT in
       END IF
!---> Siqi Li, CHECKALL@20230818
       XTRI = reshape(XG(NVG(MIN_LOC,1:3)), (/3/))
       YTRI = reshape(YG(NVG(MIN_LOC,1:3)), (/3/))
!       XTRI = XG(NVG(MIN_LOC,1:3))
!       YTRI = YG(NVG(MIN_LOC,1:3))
!<--- 
       RDLAST = RDLIST(MIN_LOC,1)
       IF(ISINTRIANGLE1(XTRI,YTRI,X0,Y0))THEN
         JJ = MIN_LOC
         EXIT IN
       END IF
       RDLAST = RDLIST(MIN_LOC,1)
     END DO IN      

     ND1=NVG(JJ,1)
     ND2=NVG(JJ,2)
     ND3=NVG(JJ,3)

# if defined (SPHERICAL)
     CALL ARCX(X0,Y0,XCG(JJ),YCG(JJ),X0C)
     CALL ARCX(X0,Y0,XCG(JJ),YCG(JJ),Y0C)
# else
     X0C = X0 - XCG(JJ)
     Y0C = Y0 - YCG(JJ)
# endif
     !----Linear Interpolation of Bathymetry------------------------------------------!
     H0 = AW0G(JJ,1)*HG(ND1)+AW0G(JJ,2)*HG(ND2)+AW0G(JJ,3)*HG(ND3)
     HX = AWXG(JJ,1)*HG(ND1)+AWXG(JJ,2)*HG(ND2)+AWXG(JJ,3)*HG(ND3)
     HY = AWYG(JJ,1)*HG(ND1)+AWYG(JJ,2)*HG(ND2)+AWYG(JJ,3)*HG(ND3)
     TEMP_H = H0 + HX*X0C + HY*Y0C !here is the interpolated observation depth

     DO K=1,KBM1
      !----Linear Interpolation of Bathymetry------------------------------------------!
      H0 = AW0G(JJ,1)*ZZ_G(ND1,K)*HG(ND1)+AW0G(JJ,2)*ZZ_G(ND2,K)*HG(ND2)+AW0G(JJ,3)*ZZ_G(ND3,K)*HG(ND3)
      HX = AWXG(JJ,1)*ZZ_G(ND1,K)*HG(ND1)+AWXG(JJ,2)*ZZ_G(ND2,K)*HG(ND2)+AWXG(JJ,3)*ZZ_G(ND3,K)*HG(ND3)
      HY = AWYG(JJ,1)*ZZ_G(ND1,K)*HG(ND1)+AWYG(JJ,2)*ZZ_G(ND2,K)*HG(ND2)+AWYG(JJ,3)*ZZ_G(ND3,K)*HG(ND3)
      ZZ_OB(K) = (H0 + HX*X0C + HY*Y0C)/TEMP_H
     END DO  

!     DELTA=(XG(ND2)-XG(ND1))*(YG(ND3)-YG(ND1))-     &
!           (XG(ND3)-XG(ND1))*(YG(ND2)-YG(ND1))

!     IF(SERIAL)THEN
!     DO K=1,KBM1
!       COFA=(YG(ND3)-YG(ND1))*(ZZ(ND2,K)-ZZ(ND1,K))-   &
!            (YG(ND2)-YG(ND1))*(ZZ(ND3,K)-ZZ(ND1,K))
!       COFB=(XG(ND2)-XG(ND1))*(ZZ(ND3,K)-ZZ(ND1,K))-   &
!            (XG(ND3)-XG(ND1))*(ZZ(ND2,K)-ZZ(ND1,K))
!       COFA=COFA/DELTA
!       COFB=COFB/DELTA
!       COFC=ZZ(ND1,K)-COFA*XG(ND1)-COFB*YG(ND1)
!       ZZ_OB(K)=COFA*X0+COFB*Y0+COFC
!     END DO  
!     END IF

!#  if defined (MULTIPROCESSOR)   
!     IF(PAR)THEN
!     DO K=1,KBM1
!       COFA=(YG(ND3)-YG(ND1))*(ZZ_G(ND2,K)-ZZ_G(ND1,K))-   &
!            (YG(ND2)-YG(ND1))*(ZZ_G(ND3,K)-ZZ_G(ND1,K))
!       COFB=(XG(ND2)-XG(ND1))*(ZZ_G(ND3,K)-ZZ_G(ND1,K))-   &
!            (XG(ND3)-XG(ND1))*(ZZ_G(ND2,K)-ZZ_G(ND1,K))
!       COFA=COFA/DELTA
!       COFB=COFB/DELTA
!       COFC=ZZ_G(ND1,K)-COFA*XG(ND1)-COFB*YG(ND1)
!       ZZ_OB(K)=COFA*X0+COFB*Y0+COFC
!     END DO  
!     END IF
!#  endif
     
     DO J=1,NLAY
       SIGMA_C = -TS_OBS(I)%ODEPTH(J)/TEMP_H         !TS_OBS(I)%DEPTH
       DO K=2,KBM1
         IF(ZZ_OB(K) <= SIGMA_C .AND. ZZ_OB(K-1) > SIGMA_C)THEN 
           TS_OBS(I)%S_INT(J,1) = K-1
           TS_OBS(I)%S_INT(J,2) = K
           TS_OBS(I)%S_WEIGHT(J,1) = (SIGMA_C-ZZ_OB(K))/(ZZ_OB(K-1)-ZZ_OB(K))
           TS_OBS(I)%S_WEIGHT(J,2) = 1.0_SP - TS_OBS(I)%S_WEIGHT(J,1) 
         END IF  
       END DO
       IF(ZZ_OB(1) <= SIGMA_C)THEN  !!OBSERVATION ABOVE CENTROID OF FIRST SIGMA LAYER
         TS_OBS(I)%S_INT(J,1) = 1
         TS_OBS(I)%S_INT(J,2) = 1
         TS_OBS(I)%S_WEIGHT(J,1) = 1.0_SP
         TS_OBS(I)%S_WEIGHT(J,2) = 0.0_SP
       END IF
       IF(ZZ_OB(KBM1) > SIGMA_C)THEN !!OBSERVATION BELOW CENTROID OF BOTTOM SIGMA LAYER
         TS_OBS(I)%S_INT(J,1) = KBM1
         TS_OBS(I)%S_INT(J,2) = KBM1
         TS_OBS(I)%S_WEIGHT(J,1) = 1.0_SP
         TS_OBS(I)%S_WEIGHT(J,2) = 0.0_SP
       END IF

     END DO
   END DO

   DEALLOCATE(ZZ_G)  

!------------------------------------------------------------------------------!
!  Report Number of Interpolation Points, Location and Number of Data 
!------------------------------------------------------------------------------!
   IF(.NOT. MSR)RETURN

   WRITE(IPT,*)
   WRITE(IPT,*)'!            TEMP/SALINITY OBSERVATION DATA           '
#  if defined (SPHERICAL)
   WRITE(IPT,*)" MOORING#    LON       LAT    #INTERP PTS  #DATA TIMES  NEAR_NODE  SITA"
#  else
   WRITE(IPT,*)" MOORING#   X(KM)      Y(KM)  #INTERP PTS  #DATA TIMES  NEAR_NODE  SITA"
#  endif
   DO I=1,N_ASSIM_TS
     MAXEL = MAXLOC(TS_OBS(I)%X_WEIGHT,DIM=1)
     WRITE(IPT,'(2X,I5,3X,F8.1,3X,F8.1,3X,I6,5X,I6,5X,I6,5X,F8.1)') &
#  if defined (SPHERICAL)
     I,TS_OBS(I)%X,TS_OBS(I)%Y, &
#  else
     I,(TS_OBS(I)%X+VXMIN)/1000.,(TS_OBS(I)%Y+VYMIN)/1000., &
#  endif
       TS_OBS(I)%N_INTPTS,TS_OBS(I)%N_TIMES,TS_OBS(I)%INTPTS(MAXEL),&
       TS_OBS(I)%SITA
   END DO
   WRITE(IPT,*)
   WRITE(IPT,*)'NUMBER OF BAD TS DATA POINTS: ',NBD_CNT
   WRITE(IPT,*)" MOORING #   BEGIN TIME  END TIME"
   DO I=1,N_ASSIM_TS
!   WRITE(IPT,*)I,TS_OBS(I)%TIMES(1)/(24.*3600.),&
!       TS_OBS(I)%TIMES(TS_OBS(I)%N_TIMES)/(24.*3600.)
    WRITE(IPT,*)I,TS_OBS(I)%TIMES(1)%MJD,&
        TS_OBS(I)%TIMES(TS_OBS(I)%N_TIMES)%MJD
   END DO
   IF (DBG_SET(DBG_SBR)) WRITE(IPT,*) "END: SET_TS_ASSIM_DATA"

   RETURN
   END SUBROUTINE SET_TS_ASSIM_DATA

   SUBROUTINE SET_TS_ASSIM_DATA_WINDOW

!------------------------------------------------------------------------------!
!  SET UP ASSIMILATION DATA FOR TEMP/SAL OBSERVATIONS in ASSIMILATION WINDOW   |
!------------------------------------------------------------------------------!
   IMPLICIT NONE
   INTEGER I,J,IW,NLAY,NTIME
   REAL(SP), ALLOCATABLE, DIMENSION(:) :: FTEMP
   REAL(SP) :: T_THRESH,DT_MIN

!   INTEGER, ALLOCATABLE, DIMENSION(:)   :: ID_STATION

   IF(DBG_SET(DBG_SBR)) write(ipt,*) "START: SET_TS_ASSIM_DATA_WINDOW"

   IF(ALLOCATED(ID_STATION)) DEALLOCATE(ID_STATION)
   ALLOCATE(ID_STATION(N_ASSIM_TS))
!   T_THRESH = TS_OI_ASTIME_WINDOW+12.0_SP*3600.0_SP   
   T_THRESH = TS_OI_ASTIME_WINDOW
!   IF(MSR) write(555,*) '-------------test---1--',T_THRESH
   IW = 0
   N_ASSIM_TS_W = 0
   DO I=1,N_ASSIM_TS
     NLAY  = TS_OBS(I)%N_LAYERS
     NTIME = TS_OBS(I)%N_TIMES
     ALLOCATE(FTEMP(NTIME))
     DO J=1,NTIME
       FTEMP(J) = SECONDS(IntTime - TS_OBS(I)%TIMES(J))
       FTEMP(J) = ABS(FTEMP(J))
     END DO
     DT_MIN = MINVAL(FTEMP(1:NTIME))
     IF(DT_MIN < T_THRESH) THEN
       IW = IW+1
       ID_STATION(IW)=I
     ENDIF
     DEALLOCATE(FTEMP)
   ENDDO
!   IF(MSR) write(555,*) '-------------test---2-IW=',IW
   N_ASSIM_TS_W = IW
   RETURN
   END SUBROUTINE SET_TS_ASSIM_DATA_WINDOW

!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|

   SUBROUTINE TEMP_ASSIMILATION

   IF(TS_NGASSIM)THEN
     CALL NG_DA('TEMPERATURE',TF1)
   ELSE IF(TS_OIASSIM)THEN  
     CALL OI_DA('TEMPERATURE',TF1)
   ELSE
     WRITE(IPT,*) "EITHER TS_NGASSIM OR TS_OIASSIM MUST BE SET TRUE"
     CALL PSTOP
   END IF  

   END SUBROUTINE TEMP_ASSIMILATION
!==============================================================================|
   SUBROUTINE SALT_ASSIMILATION

   IF(TS_NGASSIM)THEN
     CALL NG_DA('SALINITY',SF1)
   ELSE IF(TS_OIASSIM)THEN  
     CALL OI_DA('SALINITY',SF1)
   ELSE
     WRITE(IPT,*) "EITHER TS_NGASSIM OR TS_OIASSIM MUST BE SET TRUE"
     CALL PSTOP
   END IF  

   END SUBROUTINE SALT_ASSIMILATION
!==============================================================================|

   SUBROUTINE OI_DA(VARNAME, VAR)
!==============================================================================|
!  USE OBSERVATION DATA TO ADJUST TEMP FIELD BY OI METHOD
!  Lu Wang OI@20230608
!  MOdified it to ran parrallelly when doing optimal interpolation           
!  T_FLAG1 is set to avoid over adjusting
!  T_FLAG2 is set to avoid adjusting in node where the difference is too big
!          between the one in model and observation  
!==============================================================================|

#  if defined (PWP)
   USE MOD_PWP, only : MLD
#  endif

   IMPLICIT NONE
   CHARACTER(LEN=*), INTENT(IN) :: VARNAME
   REAL(SP), ALLOCATABLE, INTENT(INOUT)  :: VAR(:,:)
   REAL(SP), ALLOCATABLE        :: VAROBS(:,:)
   REAL(SP), ALLOCATABLE, DIMENSION(:,:) :: TINT,TCORR,TG,TCORR1
   REAL(SP), ALLOCATABLE, DIMENSION(:,:) :: TWGHT_T
   REAL(SP), ALLOCATABLE, DIMENSION(:)   :: FTEMP
   REAL, ALLOCATABLE, DIMENSION(:,:) :: T_FLAG1, T_FLAG2   
   REAL(SP) :: WEIGHT,DEFECT,CORRECTION,DT_MIN,SIMTIME,T_THRESH,WGHT,TOT_WGHT
   REAL(SP) :: U1,U2,V1,V2,W1,W2,WEIGHT1,WEIGHT2
   TYPE(TIME) ::DIFTIME
   INTEGER I,J,K,J1,K1,K2,NLAY,ITIMEA,NTIME,IERR
   INTRINSIC MINLOC
   INTEGER ID
   INTEGER IP,JN1,JN2,JN3
   REAL(SP) XSC,YSC,COFT0,COFTX,COFTY
   INTEGER N_T_WEIGHT
   REAL(SP) T_WEIGHT

   REAL(SP) t1, t2, t3, t4, t5, t6

!==============================================================================|

   IF (DBG_SET(DBG_SBR)) WRITE(IPT,*) "START: OI_TA" 

   CALL  SET_TS_ASSIM_DATA_WINDOW

   IF(N_ASSIM_TS_W.le.0) return
       
!------------------------------------------------------------------------------!
!  Gather T Fields to Master Processor                                         ! 
!------------------------------------------------------------------------------!
   ALLOCATE(TG(0:MGL,KB))        ;TG = 0.0_SP
#  if defined (MULTIPROCESSOR)
   IF(PAR)THEN
!     CALL GATHER(LBOUND(TF1,1),UBOUND(TF1,1),M,MGL,KB,MYID,NPROCS,NMAP,TF1,TG)
     CALL ACOLLECT(MYID,MSRID,NPROCS,NMAP,VAR,TG)
   END IF
#  endif
   IF(SERIAL)THEN
     TG(1:MGL,1:KBM1) = VAR(1:MGL,1:KBM1)
   END IF

!------------------------------------------------------------------------------!
!  Allocate variables
!------------------------------------------------------------------------------!

   ALLOCATE(TINT(N_ASSIM_TS_W,TS_MAX_LAYER)) ; TINT = 0. 
   ALLOCATE(TWGHT_T(N_ASSIM_TS_W,KBM1))   ; TWGHT_T = 0.
   ALLOCATE(TCORR(N_ASSIM_TS_W,KBM1))     ; TCORR   = 0.
   ALLOCATE(T_FLAG1(0:MGL,KB)) ; T_FLAG1 = 1.0
   ALLOCATE(T_FLAG2(0:MGL,KB)) ; T_FLAG2 = 1.0
   ALLOCATE(TCORR1(M,KBM1)); TCORR1=0.0_SP
 
IF(MSR)THEN
   T_WEIGHT = 0. 

   T_THRESH = TS_OI_ASTIME_WINDOW    

!   SIMTIME          = TIME*86400
   SIMTIME = DTI*FLOAT(IINT)

   DO I=1,N_ASSIM_TS_w
!------------------------------------------------------------------------------!
!  Calculate Temporal Weight of Measurement (I) at Time(TIME)                  ! 
!------------------------------------------------------------------------------!
     ID = ID_STATION(I)

     ALLOCATE(VAROBS(TS_OBS(Id)%N_TIMES , TS_OBS(Id)%N_LAYERS))
     SELECT CASE (VARNAME)
       CASE ('TEMPERATURE')
         VAROBS = TS_OBS(Id)%TEMP
       CASE ('SALINITY')
         VAROBS = TS_OBS(Id)%SAL
       CASE DEFAULT
         WRITE(IPT,*) 'UNKNOWN VARIABLE NAME'
         CALL PSTOP
     END SELECT


     NTIME = TS_OBS(Id)%N_TIMES
     ALLOCATE(FTEMP(NTIME)) 
!     FTEMP(1:NTIME) = ABS(SIMTIME - TS_OBS(I)%TIMES(1:NTIME))
     DO j=1,NTIME
        FTEMP(J) = SECONDS(IntTime - TS_OBS(Id)%TIMES(J))
        FTEMP(J) = ABS(FTEMP(J))
     ENDDO

     DT_MIN = MINVAL(FTEMP(1:NTIME))
     N_T_WEIGHT = MINLOC(FTEMP,DIM=1)

     IF(DT_MIN < T_THRESH)THEN     
       IF(DT_MIN < .5_SP*T_THRESH) THEN
         T_WEIGHT = 1.0_SP
       ELSE
         T_WEIGHT = (T_THRESH-DT_MIN)/T_THRESH*2.0_SP
       END IF
     END IF

     DEALLOCATE(FTEMP)
!------------------------------------------------------------------------------!
!  Interpolate Simulation Data to Local Observation Point                      ! 
!------------------------------------------------------------------------------!
     NLAY      = TS_OBS(Id)%N_LAYERS
     DO J=1,TS_OBS(Id)%N_INTPTS
       J1        = TS_OBS(Id)%INTPTS(J)
       WGHT      = TS_OBS(Id)%X_WEIGHT(J)
       DO K=1,NLAY
         U1 = TG(J1,TS_OBS(Id)%S_INT(K,1))
         U2 = TG(J1,TS_OBS(Id)%S_INT(K,2))
         W1 = TS_OBS(Id)%S_WEIGHT(K,1)
         W2 = TS_OBS(Id)%S_WEIGHT(K,2)
         TINT(I,K) = TINT(I,K) + (U1*W1 + U2*W2)*WGHT 
       END DO
     END DO

     TOT_WGHT = SUM(TS_OBS(Id)%X_WEIGHT(1:TS_OBS(Id)%N_INTPTS))
     TINT(I,1:NLAY) = TINT(I,1:NLAY)/TOT_WGHT
!------------------------------------------------------------------------------!
!  Compute Local Correction by Interpolating Observed/Computed Defect          ! 
!------------------------------------------------------------------------------!
     ITIMEA  = N_T_WEIGHT
     DO K=1,NLAY
       K1             = TS_OBS(Id)%S_INT(K,1)
       K2             = TS_OBS(Id)%S_INT(K,2)
       W1             = TS_OBS(Id)%S_WEIGHT(K,1)
       W2             = TS_OBS(Id)%S_WEIGHT(K,2)

       DEFECT         = VAROBS(ITIMEA,K) - TINT(I,K)

! lwang added for OI-TS_limit_control 
       DO J=1,TS_OBS(Id)%N_INTPTS
         J1 = TS_OBS(Id)%INTPTS(J)
         U1 = TG(J1,TS_OBS(Id)%S_INT(K,1))
         U2 = TG(J1,TS_OBS(Id)%S_INT(K,2))
         if (DEFECT>0.) then
           if (U1>=VAROBS(ITIMEA,K)) T_FLAG1(J1,TS_OBS(Id)%S_INT(K,1))=0.0
           if (U2>=VAROBS(ITIMEA,K)) T_FLAG1(J1,TS_OBS(Id)%S_INT(K,2))=0.0
         elseif (DEFECT<0.) then
           if (U1<=VAROBS(ITIMEA,K)) T_FLAG1(J1,TS_OBS(Id)%S_INT(K,1))=0.0
           if (U2<=VAROBS(ITIMEA,K)) T_FLAG1(J1,TS_OBS(Id)%S_INT(K,2))=0.0
         endif
         ! if the difference between model depth and obserbation depth is big
         ! then T_FLAG2 =0  20211208
         if (HG(J1)/TS_OBS(Id)%DEPTH>1.5 .or. HG(J1)/TS_OBS(Id)%DEPTH<0.67) then
            T_FLAG2(J1,TS_OBS(Id)%S_INT(K,1))=0
            T_FLAG2(J1,TS_OBS(Id)%S_INT(K,2))=0
         endif

       END DO !J
! lwang
       SELECT CASE (VARNAME)
         CASE ('TEMPERATURE')
           IF(ABS(DEFECT) < 70.0)THEN     !quality control lwang from 20 to 70
             WEIGHT1        = T_WEIGHT*W1
             WEIGHT2        = T_WEIGHT*W2
             TWGHT_T(I,K1) = TWGHT_T(I,K1) + WEIGHT1   
             TWGHT_T(I,K2) = TWGHT_T(I,K2) + WEIGHT2   
             CORRECTION     = DEFECT
             TCORR(I,K1)   = TCORR(I,K1) + CORRECTION*WEIGHT1
             TCORR(I,K2)   = TCORR(I,K2) + CORRECTION*WEIGHT2
           ENDIF
         CASE ('SALINITY')
           IF(ABS(DEFECT) < 30.0_SP) THEN             !quality control lwang from 20 to 70
             WEIGHT1        = T_WEIGHT*W1
             WEIGHT2        = T_WEIGHT*W2
             TWGHT_T(I,K1) = TWGHT_T(I,K1) + WEIGHT1   
             TWGHT_T(I,K2) = TWGHT_T(I,K2) + WEIGHT2   
             CORRECTION     = DEFECT
             TCORR(I,K1)   = TCORR(I,K1) + CORRECTION*WEIGHT1
             TCORR(I,K2)   = TCORR(I,K2) + CORRECTION*WEIGHT2
!----> Great Bay
!           ELSE IF(TS_OBS(Id)%X+VXMIN>=850410.0 .and. TS_OBS(Id)%X+VXMIN<=876770.0 .and. &
!                   TS_OBS(Id)%Y+VYMIN>=10950.0 .and. TS_OBS(Id)%Y+VYMIN<=31490.0 .and. &
!                   ABS(DEFECT) < 30.0_SP) THEN
!             WEIGHT1        = T_WEIGHT*W1
!             WEIGHT2        = T_WEIGHT*W2
!             TWGHT_T(I,K1) = TWGHT_T(I,K1) + WEIGHT1   
!             TWGHT_T(I,K2) = TWGHT_T(I,K2) + WEIGHT2   
!             CORRECTION     = DEFECT
!             TCORR(I,K1)   = TCORR(I,K1) + CORRECTION*WEIGHT1
!             TCORR(I,K2)   = TCORR(I,K2) + CORRECTION*WEIGHT2
           ENDIF
         CASE DEFAULT
           WRITE(IPT,*) 'UNKNOWN VARIABLE NAME'
           CALL PSTOP
       END SELECT

     END DO !K

       DO K=1,KBM1
         IF(TWGHT_T(I,K) > 1.0E-8)THEN
           TCORR(I,K)=TCORR(I,K)/TWGHT_T(I,K)
         END IF
       END DO

   DEALLOCATE(VAROBS)

   END DO !I

   END IF  !!MASTER 
!------------------------------------------------------------------------------!
!  'OI' Simulation Data Using Local Corrections                                ! 
!------------------------------------------------------------------------------!

# if defined (MULTIPROCESSOR) 
   CALL MPI_BCAST(TCORR,(N_ASSIM_TS_W)*KBM1,MPI_F,0,MPI_FVCOM_GROUP,IERR)
   CALL MPI_BCAST(T_FLAG1,(MGL+1)*KB,MPI_F,0,MPI_FVCOM_GROUP,IERR)
   CALL MPI_BCAST(T_FLAG2,(MGL+1)*KB,MPI_F,0,MPI_FVCOM_GROUP,IERR)
   CALL MPI_BCAST(DA_TS,(MGL),MPI_INT,0,MPI_FVCOM_GROUP,IERR)
#  endif

     DO K=1,KBM1
       CALL TS_OPTIMINTERP(TCORR(:,K),TCORR1(:,K))
     END DO

     DO I=1,M
!lwang       IF(SSTGRD_ASSIM .AND. VARNAME=='TEMPERATURE') THEN
!lwang         K1 = 2
!lwang       ELSE 
         K1 = 1
!lwang       ENDIF

#      if defined (PWP) 
       IF(MLD(I)<0) THEN
         K1 = 2
       ELSE 
         K1 = MLD(I)+1
       ENDIF
#      endif

       DO K=K1,KBM1
         IF(DA_TS(NGID(I)) == 1)THEN
!QXU         TG(I,K) = TG(I,K) + TCORR1(I,K)
!           TG(I,K) = TG(I,K) + TS_GALPHA*TCORR1(I,K)

           ! lwang added for OI-TS_limit_control  20190423
            VAR(I,K) = VAR(I,K) + TS_OIGALPHA*TCORR1(I,K)*T_FLAG1(NGID(I),K)*T_FLAG2(NGID(I),K)
            ! positive control
            IF (VARNAME == 'SALINITY') THEN
               VAR(I,K)=MAX(0.3,VAR(I,K))
            END IF
           ! lwang
         END IF
       END DO
     END DO

     DEALLOCATE(TWGHT_T,TCORR,TINT,TCORR1)
     DEALLOCATE(T_FLAG1)
     DEALLOCATE(T_FLAG2)

   IF (DBG_SET(DBG_SBR)) WRITE(IPT,*) "END: OI_TA" 

!IF (MSR) write(1005,*) t2-t1, t3-t2, t4-t3, t5-t4
   RETURN
   END SUBROUTINE OI_DA
!==============================================================================|

   SUBROUTINE NG_DA(VARNAME, VAR)
!==============================================================================|
!  USE TEMP OBSERVATION DATA TO ADJUST TEMP FIELD BY NUDGING METHOD            |
!==============================================================================|
#  if defined (PWP)
   USE MOD_PWP, only : MLD
#  endif


   IMPLICIT NONE
   CHARACTER(LEN=*), INTENT(IN) :: VARNAME
   REAL(SP), ALLOCATABLE, INTENT(INOUT)  :: VAR(:,:)
   REAL(SP), ALLOCATABLE, DIMENSION(:,:) :: TINT,TCORR,TG,TCORR1
   REAL(SP), ALLOCATABLE, DIMENSION(:,:) :: TWGHT_T
   REAL(SP), ALLOCATABLE, DIMENSION(:)   :: FTEMP
   REAL(SP) :: WEIGHT,DEFECT,CORRECTION,DT_MIN,SIMTIME,T_THRESH,WGHT,TOT_WGHT
   REAL(SP) :: U1,U2,V1,V2,W1,W2,WEIGHT1,WEIGHT2
   TYPE(TIME) ::DIFTIME
   INTEGER I,J,K,J1,K1,K2,NLAY,ITIMEA,NTIME,IERR
   INTRINSIC MINLOC
   INTEGER ID
   INTEGER IP,JN1,JN2,JN3
   REAL(SP) XSC,YSC,COFT0,COFTX,COFTY


#  if defined (PWP)
   INTEGER, ALLOCATABLE, DIMENSION(:) :: MLD_GLB
#  endif

!==============================================================================|

   IF (DBG_SET(DBG_SBR)) WRITE(IPT,*) "START: NG_ASSIMILATION" 

   CALL  SET_TS_ASSIM_DATA_WINDOW

   IF(N_ASSIM_TS_W.le.0) return
       
!------------------------------------------------------------------------------!
!  Gather T Fields to Master Processor                                         ! 
!------------------------------------------------------------------------------!
   ALLOCATE(TG(0:MGL,KB))        ;TG = 0.0_SP
#  if defined (MULTIPROCESSOR)
   IF(PAR)THEN
!     CALL GATHER(LBOUND(TF1,1),UBOUND(TF1,1),M,MGL,KB,MYID,NPROCS,NMAP,TF1,TG)
!     CALL ACOLLECT(MYID,MSRID,NPROCS,NMAP,TF1,TG)
     CALL ACOLLECT(MYID,MSRID,NPROCS,NMAP,VAR,TG)
   END IF
#  endif
   IF(SERIAL)THEN
!     TG(1:MGL,1:KBM1) = TF1(1:MGL,1:KBM1)
     TG(1:MGL,1:KBM1) = VAR(1:MGL,1:KBM1)
   END IF

#  if defined (PWP)
   ALLOCATE(MLD_GLB(0:MGL))
#  if defined (MULTIPROCESSOR)
   IF(PAR) CALL ACOLLECT(MYID,MSRID,NPROCS,NMAP,MLD,MLD_GLB)
#  endif
   IF(SERIAL) MLD_GLB(1:MGL) = MLD(1:MGL)
#  endif
!------------------------------------------------------------------------------!
!  Calculate Temporal Weight of Measurement (I) at Time(TIME)                  ! 
!------------------------------------------------------------------------------!

   IF(MSR)THEN
   TS_OBS%T_WEIGHT = 0. 

   T_THRESH = TS_NG_ASTIME_WINDOW    
    
!   SIMTIME          = TIME*86400
   SIMTIME = DTI*FLOAT(IINT)

   DO I=1,N_ASSIM_TS_w
     ID = ID_STATION(I)
     NTIME = TS_OBS(Id)%N_TIMES
     ALLOCATE(FTEMP(NTIME)) 
!     FTEMP(1:NTIME) = ABS(SIMTIME - TS_OBS(I)%TIMES(1:NTIME))
     DO j=1,NTIME
        FTEMP(J) = SECONDS(IntTime - TS_OBS(Id)%TIMES(J))
        FTEMP(J) = ABS(FTEMP(J))
     ENDDO
     DT_MIN = MINVAL(FTEMP(1:NTIME))
     TS_OBS(Id)%N_T_WEIGHT = MINLOC(FTEMP,DIM=1)

     IF(DT_MIN < T_THRESH)THEN     
       IF(DT_MIN < .5_SP*T_THRESH) THEN
         TS_OBS(Id)%T_WEIGHT = 1.0_SP
       ELSE
         TS_OBS(Id)%T_WEIGHT = (T_THRESH-DT_MIN)/T_THRESH*2.0_SP
       END IF
     END IF

     DEALLOCATE(FTEMP)
   END DO
   
       
!------------------------------------------------------------------------------!
!  Interpolate Simulation Data to Local Observation Point                      ! 
!------------------------------------------------------------------------------!
       
   ALLOCATE(TINT(N_ASSIM_TS,TS_MAX_LAYER)) ; TINT = 0. 

!   IF(TS_NGASSIM)THEN
   DO I=1,N_ASSIM_TS_w

       ID = ID_STATION(I) 
     DO J=1,TS_OBS(Id)%N_INTPTS
       J1        = TS_OBS(Id)%INTPTS(J)
       WGHT      = TS_OBS(Id)%X_WEIGHT(J)
       NLAY      = TS_OBS(Id)%N_LAYERS
       DO K=1,NLAY
         U1 = TG(J1,TS_OBS(Id)%S_INT(K,1))
         U2 = TG(J1,TS_OBS(Id)%S_INT(K,2))
         W1 = TS_OBS(Id)%S_WEIGHT(K,1)
         W2 = TS_OBS(Id)%S_WEIGHT(K,2)
         TINT(I,K) = TINT(I,K) + (U1*W1 + U2*W2)*WGHT 
       END DO
     END DO
     TOT_WGHT = SUM(TS_OBS(Id)%X_WEIGHT(1:TS_OBS(Id)%N_INTPTS))
     TINT(I,1:NLAY) = TINT(I,1:NLAY)/TOT_WGHT

   END DO

!------------------------------------------------------------------------------!
!  Compute Local Correction by Interpolating Observed/Computed Defect          ! 
!------------------------------------------------------------------------------!

   ALLOCATE(TWGHT_T(MGL,KBM1))   ; TWGHT_T = 0.
   ALLOCATE(TCORR(MGL,KBM1))     ; TCORR   = 0.

     DO I=1,N_ASSIM_TS_w
     ID = ID_STATION(I) 
       DO J=1,TS_OBS(Id)%N_INTPTS
         J1     = TS_OBS(Id)%INTPTS(J)
         ITIMEA  = TS_OBS(Id)%N_T_WEIGHT
         NLAY   = TS_OBS(Id)%N_LAYERS
         DO K=1,NLAY
           K1             = TS_OBS(Id)%S_INT(K,1)
           K2             = TS_OBS(Id)%S_INT(K,2)
           W1             = TS_OBS(Id)%S_WEIGHT(K,1)
           W2             = TS_OBS(Id)%S_WEIGHT(K,2)

           SELECT CASE (VARNAME)
             CASE ('TEMPERATURE')
               DEFECT         = TS_OBS(Id)%TEMP(ITIMEA,K) - TINT(I,K)
             CASE ('SALINITY')
               DEFECT         = TS_OBS(Id)%SAL(ITIMEA,K) - TINT(I,K)
             CASE DEFAULT
               WRITE(IPT,*) 'UNKNOWN VARIABLE NAME'
               CALL PSTOP
           END SELECT

           IF(ABS(DEFECT) < 70.0_SP)THEN     !quality control lwang from 20 to 70
             WEIGHT1        = TS_OBS(Id)%T_WEIGHT*TS_OBS(Id)%X_WEIGHT(J)*W1
             WEIGHT2        = TS_OBS(Id)%T_WEIGHT*TS_OBS(Id)%X_WEIGHT(J)*W2
             TWGHT_T(J1,K1) = TWGHT_T(J1,K1) + WEIGHT1   
             TWGHT_T(J1,K2) = TWGHT_T(J1,K2) + WEIGHT2   

             CORRECTION     = TS_GAMA*DEFECT
!           TCORR(J1,K1)   = TCORR(J1,K1) + CORRECTION*WEIGHT1
!           TCORR(J1,K2)   = TCORR(J1,K2) + CORRECTION*WEIGHT2
             TCORR(J1,K1)   = TCORR(J1,K1) + CORRECTION*WEIGHT1*WEIGHT1
             TCORR(J1,K2)   = TCORR(J1,K2) + CORRECTION*WEIGHT2*WEIGHT2
           ENDIF
         END DO
       END DO
     END DO

!------------------------------------------------------------------------------!
!  Nudge Simulation Data Using Local Corrections                               ! 
!------------------------------------------------------------------------------!

     DO I=1,MGL

       IF(SSTGRD_ASSIM) THEN
         K1 = 2
       ELSE
         K1 = 1
       ENDIF
#      if defined (PWP)
       IF(MLD_GLB(I)<0) THEN
         K1 = 2
       ELSE
         K1 = MLD_GLB(I)+1 
       ENDIF
#      endif

       DO K=K1,KBM1
         IF(DA_TS(I) == 1 .AND. TWGHT_T(I,K) > 1.0E-08)THEN
           TG(I,K) = TG(I,K) + DTI*TS_GALPHA*TCORR(I,K)/TWGHT_T(I,K)
         END IF
       END DO
     END DO

     DEALLOCATE(TWGHT_T,TCORR,TINT)

   END IF  !!MASTER


!------------------------------------------------------------------------------!
!  Disperse New Data Fields to Slave Processors                                ! 
!------------------------------------------------------------------------------!
   IF(SERIAL)THEN
!     TF1(1:M,1:KBM1) = TG(1:M,1:KBM1)
     VAR(1:M,1:KBM1) = TG(1:M,1:KBM1)
   END IF
#  if defined (MULTIPROCESSOR) 
   CALL MPI_BCAST(TG,(MGL+1)*KB,MPI_F,0,MPI_FVCOM_GROUP,IERR)
   IF(PAR)THEN
     DO I=1,M
!       TF1(I,1:KBM1) = TG(NGID(I),1:KBM1)
       VAR(I,1:KBM1) = TG(NGID(I),1:KBM1)
     END DO
   END IF
#  endif

   DEALLOCATE(TG)
#  if defined (PWP)
   DEALLOCATE(MLD_GLB)
#  endif
          
   IF (DBG_SET(DBG_SBR)) WRITE(IPT,*) "END: NG_ASSIMILATION" 

   RETURN
   END SUBROUTINE NG_DA
!==============================================================================|
!==============================================================================|

!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|

!==============================================================================|
!==============================================================================|
   SUBROUTINE TS_OPTIMINTERP(F,FI)
   USE MOD_OPTIMAL_INTERPOLATION
   IMPLICIT NONE

!------------------------------------------------------------------------------|
! xi(1,:) and xi(2,:) represent the x and y coordindate of the grid of the     |
! interpolated field                                                           |
! fi and vari are the interpolated field and its error variance resp.          |
!------------------------------------------------------------------------------|
!lwang OI@2023   REAL(SP) :: XI(2,MGL),FI(MGL),VARI(MGL)
  REAL(SP) :: XI(2,M),FI(M),VARI(M)


!------------------------------------------------------------------------------|
! x(1,:) and x(2,:) represent the x and y coordindate of the observations      |
! f and var are observations and their error variance resp.                    |
!------------------------------------------------------------------------------|
!   REAL(SP) :: X(2,N_ASSIM_TS),VAR(N_ASSIM_TS),F(N_ASSIM_TS)
  REAL(SP) :: X(2,N_ASSIM_TS_W),VAR(N_ASSIM_TS_W),F(N_ASSIM_TS_W)

!------------------------------------------------------------------------------|
! param: inverse of the correlation length                                     |
!------------------------------------------------------------------------------|
! lwang 20211018
!   REAL(SP) :: PARAM(2,N_ASSIM_TS)
   REAL(SP) :: PARAM(2,N_ASSIM_TS_W)

   INTEGER  :: I,J,MM   
   INTEGER ID
!------------------------------------------------------------------------------|
! create a regular 2D grid                                                     |
!------------------------------------------------------------------------------|
   DO I=1,M
!lwang OI@2023   DO I=1,MGL
!lwang OI@2023     XI(1,I) = XG(I)
!lwang OI@2023     XI(2,I) = YG(I)
     XI(1,I) = VX(I)
     XI(2,I) = VY(I)
   END DO	
!------------------------------------------------------------------------------|   
! param is the inverse of the correlation length                               |
!------------------------------------------------------------------------------|
! lwang 20211018 TS_PARAM is for all obs during the whole runing period
! but here we need PARAM(2,N_ASSIM_TS_W) 
!   PARAM = 1.0_SP/TS_PARAM             
 
   MM = TS_N_INFLU

!------------------------------------------------------------------------------|   
! the error variance of the observations                                       |
!------------------------------------------------------------------------------|
   VAR = 0.0_SP   
!------------------------------------------------------------------------------|
! location of observations                                                     |
!------------------------------------------------------------------------------|
   DO I=1,N_ASSIM_TS_w
     ID = ID_STATION(I)
     X(1,I) = TS_OBS(Id)%X
     X(2,I) = TS_OBS(Id)%Y
     !lwang 20211018
     PARAM(:,I) = 1.0_SP/TS_PARAM(:,ID)
   END DO  
!------------------------------------------------------------------------------|
! fi is the interpolated function and vari its error variance                  |
!------------------------------------------------------------------------------|
   CALL OPTIMINTERP(X,F,VAR,PARAM,MM,XI,FI,VARI)

   RETURN
   END SUBROUTINE TS_OPTIMINTERP
!==============================================================================|
!==============================================================================|



!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   SUBROUTINE SSTGRD_OBSERVATION_UPDATE
!------------------------------------------------------------------------------!
   IMPLICIT NONE

   CALL NC_READ_VAR(VAR_SST,SST_FILE%FTIME%NEXT_STKCNT)

   SST_FILE%FTIME%NEXT_STKCNT = SST_FILE%FTIME%NEXT_STKCNT + 1


   ! RESET THE INDEX AND THE TIME FOR USE IN THE ASSIMILATION CYCLE
   SST_SAVE_INDEX = 1
   SST_SAVE_TIME = IntTime_BUF + SST_SAVE_INTERVAL
   
!lwang sst assimilation 20220428
!   SST_SAVE_TIME0 = SST_SAVE_TIME
!lwang

   END SUBROUTINE SSTGRD_OBSERVATION_UPDATE
!==============================================================================|
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   SUBROUTINE SSSGRD_OBSERVATION_UPDATE
!------------------------------------------------------------------------------!
   IMPLICIT NONE

   CALL NC_READ_VAR(VAR_SSS,SSS_FILE%FTIME%NEXT_STKCNT)

   SSS_FILE%FTIME%NEXT_STKCNT = SSS_FILE%FTIME%NEXT_STKCNT + 1


   ! RESET THE INDEX AND THE TIME FOR USE IN THE ASSIMILATION CYCLE
   SSS_SAVE_INDEX = 1
   SSS_SAVE_TIME = IntTime_BUF + SSS_SAVE_INTERVAL
   
!lwang sss assimilation 20220428
!   SSS_SAVE_TIME0 = SSS_SAVE_TIME
!lwang

   END SUBROUTINE SSSGRD_OBSERVATION_UPDATE
!==============================================================================|

   SUBROUTINE SSHGRD_OBSERVATION_UPDATE
!------------------------------------------------------------------------------!
   IMPLICIT NONE

   !! specified to certain month
   CALL NC_READ_VAR(VAR_SSH,SSH_FILE%FTIME%NEXT_STKCNT)

   SSH_FILE%FTIME%NEXT_STKCNT = SSH_FILE%FTIME%NEXT_STKCNT + 1


   ! RESET THE INDEX AND THE TIME FOR USE IN THE ASSIMILATION CYCLE
   SSH_SAVE_INDEX = 1
   SSH_SAVE_TIME = IntTime_BUF + SSH_SAVE_INTERVAL
!qxu{for SSH assimilation by 04/01/2022
   SSH_SAVE_TIME0 = SSH_SAVE_TIME
!qxu
   

   END SUBROUTINE SSHGRD_OBSERVATION_UPDATE

!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|
   SUBROUTINE SSTGRD_NUDGE
  
!==============================================================================|
!  USE SST OBSERVATION DATA TO NUDGE SURFACE TEMPERATURE                       |
!==============================================================================|
#  if defined (PWP)
   USE MOD_PWP, only : MLD
#  endif
   IMPLICIT NONE
   REAL(SP) :: TDIFF,T_WEIGHT,TRUTH,ADJUSTMENT, S_AVG
   INTEGER I,K

!==============================================================================|


!------------------------------------------------------------------------------!
!  Calculate Temporal Weight of Measurement (I) at Time(TIME)                  ! 
!------------------------------------------------------------------------------!
# if defined (ENKF)
     SST_SAVED(1:M,:)=SST_SAVED_ENKF(1:M,:,ENKF_memberCONTR)
     SST_AVG(:)=SST_AVG_ENKF(:,ENKF_memberCONTR)
# endif

   IF(IntTime > SST_SAVE_TIME + SST_SAVE_INTERVAL/2) THEN
   
      SST_SAVE_INDEX = SST_SAVE_INDEX + 1

      SST_SAVE_TIME = SST_SAVE_TIME + SST_SAVE_INTERVAL
      
      IF(DBG_SET(DBG_LOG)) THEN
         WRITE(IPT,*) "Setting sst state # ",SST_SAVE_INDEX
!         CALL PRINT_REAL_TIME(SST_SAVE_TIME,IPT,"Set at")
      END IF

   END IF

   ! GET TIME DIFFERENCE IN SECONDS
   TDIFF = SECONDS(IntTime - SST_SAVE_TIME)
   TDIFF = ABS(TDIFF)

   IF(TDIFF < 0.5*SSTGRD_TIME_WINDOW) THEN
     T_WEIGHT = 1.0
   ELSE IF(TDIFF < SSTGRD_TIME_WINDOW) THEN
     T_WEIGHT = (SSTGRD_TIME_WINDOW-TDIFF)/SSTGRD_TIME_WINDOW*2.0
   ELSE
     T_WEIGHT = 0.0
   END IF
  
   IF(T_WEIGHT == 0.0) RETURN

   DO I=1,M
# if defined (WET_DRY)
     IF(WETTING_DRYING_ON.and.ISWETN(i)==0)cycle
# endif
      !TRUTH = MODEL_SAVED@INTERVAL + OBSERVED_AVG  - MODEL_AVG
      TRUTH = SST_SAVED(I,SST_SAVE_INDEX) + SST_OBS(I) - SST_AVG(I)
      ! ADJUSMENT = MAX_WEIGHT * (TRUTH-CURRENT) * (WEIGHT_BY_TIME)
      ADJUSTMENT = SSTGRD_WEIGHT_MAX*(TRUTH-T1(i,1))*T_WEIGHT
      ! RESULT = CURRENT + DTI*TIMESCALE * ADJUSTMENT 
! lwang modified for sst assim order Jan 2, 2020 
!      T1(I,1)=T1(I,1)+DTI*SSTGRD_TIMESCALE*ADJUSTMENT
      TF1(I,1)=TF1(I,1)+DTI*SSTGRD_TIMESCALE*ADJUSTMENT
! lwang Jan 2, 2020
! lwang added for the SST mld assimilation
      IF(SSTGRD_MLD)THEN
!        MLD_OUT(I)=MLD_RHO(I)   ! Siqi Li for MLD_output @ 2019-05-01  ! Siqi Li, 20210809
        DO K=1,KBM1
          IF (-ZZ(I,K)*D(I)<=MLD_RHO(I))THEN
! lwang modified for sst assim order Jan 2, 2020
!            T1(I,K)=T1(I,1)
            TF1(I,K)=TF1(I,1)
! lwang Jan 2, 220
            !MLD_Nsiglay(I)=K  ! Siqi Li for MLD_output @ 2019-05-01 ! @20210809
          ELSE
            EXIT
          END IF
        END DO
      END IF
! lwang
#     if defined (PWP)
      IF(MLD(I)>0) THEN
        S_AVG = 0.0_SP
        DO K=1, MLD(I)
          S_AVG = S_AVG + S1(I,K)/FLOAT(MLD(I))
        ENDDO
        S1(I,1) = S_AVG
        DO K=2,MLD(I)
! lwang modified for sst assim order Jan 2, 2020
!          T1(I,K)=T1(I,1)
          TF1(I,K)=TF1(I,1)
! lwang Jan 2, 2020
          S1(I,K)=S_AVG
        END DO
      ENDIF
#     endif

   ENDDO    

#    if defined (MULTIPROCESSOR)
     IF(PAR)CALL AEXCHANGE(NC,MYID,NPROCS,T1) !Interprocessor Exchange   !
!     IF(PAR)CALL AEXCHANGE(NC,MYID,NPROCS,S1)
!---> Siqi Li for MLD_output @ 2019-05-01
!     IF(PAR) CALL AEXCHANGE(NC,MYID,NPROCS,MLD_OUT) ! Removed by Siqi Li, @20210809
!     IF(PAR) CALL AEXCHANGE(NC,MYID,NPROCS,MLD_Nsiglay) ! Removed by Siqi Li, @20210809
!<--- Siqi
#    endif

   
   CALL N2E3D(T1,T)
!   CALL N2E3D(S1,S)

   RETURN
   END SUBROUTINE SSTGRD_NUDGE
!==============================================================================|
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|
   SUBROUTINE SSSGRD_NUDGE
  
!==============================================================================|
!  USE SSS OBSERVATION DATA TO NUDGE SURFACE SALINITY                          |
!==============================================================================|
#  if defined (PWP)
   USE MOD_PWP, only : MLD
#  endif
   IMPLICIT NONE
   REAL(SP) :: TDIFF,T_WEIGHT,TRUTH,ADJUSTMENT, S_AVG
   INTEGER I,K

!==============================================================================|


!------------------------------------------------------------------------------!
!  Calculate Temporal Weight of Measurement (I) at Time(TIME)                  ! 
!------------------------------------------------------------------------------!
# if defined (ENKF)
     SSS_SAVED(1:M,:)=SSS_SAVED_ENKF(1:M,:,ENKF_memberCONTR)
     SSS_AVG(:)=SSS_AVG_ENKF(:,ENKF_memberCONTR)
# endif

   IF(IntTime > SSS_SAVE_TIME + SSS_SAVE_INTERVAL/2) THEN
   
      SSS_SAVE_INDEX = SSS_SAVE_INDEX + 1

      SSS_SAVE_TIME = SSS_SAVE_TIME + SSS_SAVE_INTERVAL
      
      IF(DBG_SET(DBG_LOG)) THEN
         WRITE(IPT,*) "Setting sss state # ",SSS_SAVE_INDEX
!         CALL PRINT_REAL_TIME(SSS_SAVE_TIME,IPT,"Set at")
      END IF

   END IF

   ! GET TIME DIFFERENCE IN SECONDS
   TDIFF = SECONDS(IntTime - SSS_SAVE_TIME)
   TDIFF = ABS(TDIFF)

   IF(TDIFF < 0.5*SSSGRD_TIME_WINDOW) THEN
     T_WEIGHT = 1.0
   ELSE IF(TDIFF < SSSGRD_TIME_WINDOW) THEN
     T_WEIGHT = (SSSGRD_TIME_WINDOW-TDIFF)/SSSGRD_TIME_WINDOW*2.0
   ELSE
     T_WEIGHT = 0.0
   END IF
  
   IF(T_WEIGHT == 0.0) RETURN

   DO I=1,M
# if defined (WET_DRY)
     IF(WETTING_DRYING_ON.and.ISWETN(i)==0)cycle
# endif
      !TRUTH = MODEL_SAVED@INTERVAL + OBSERVED_AVG  - MODEL_AVG
      TRUTH = SSS_SAVED(I,SSS_SAVE_INDEX) + SSS_OBS(I) - SSS_AVG(I)
      ! ADJUSMENT = MAX_WEIGHT * (TRUTH-CURRENT) * (WEIGHT_BY_TIME)
      ADJUSTMENT = SSSGRD_WEIGHT_MAX*(TRUTH-S1(i,1))*T_WEIGHT*SSS_WEIGHT(I)
      ! RESULT = CURRENT + DTI*TIMESCALE * ADJUSTMENT 
! lwang modified for sst assim order Jan 2, 2020 
!      T1(I,1)=T1(I,1)+DTI*SSTGRD_TIMESCALE*ADJUSTMENT
!if (ngid(i)==46790) write(1001,*) sf1(i,1), sssgrd_timescale, adjustment
      SF1(I,1)=SF1(I,1)+DTI*SSSGRD_TIMESCALE*ADJUSTMENT
! lwang Jan 2, 2020  do not do mld assimilation for SSS 20230516
! lwang added for the SSS mld assimilation
!lwang      IF(SSTGRD_MLD)THEN
!        MLD_OUT(I)=MLD_RHO(I)   ! Siqi Li for MLD_output @ 2019-05-01  ! Siqi Li, 20210809
!lwang        DO K=1,KBM1
!lwang          IF (-ZZ(I,K)*D(I)<=MLD_RHO(I))THEN
! lwang modified for sst assim order Jan 2, 2020
!            T1(I,K)=T1(I,1)
!lwang            SF1(I,K)=SF1(I,1)
! lwang Jan 2, 220
            !MLD_Nsiglay(I)=K  ! Siqi Li for MLD_output @ 2019-05-01 ! @20210809
!lwang          ELSE
!lwang            EXIT
!lwang          END IF
!lwang        END DO
!lwang      END IF
! lwang
#     if defined (PWP)
      IF(MLD(I)>0) THEN
        S_AVG = 0.0_SP
        DO K=1, MLD(I)
          S_AVG = S_AVG + S1(I,K)/FLOAT(MLD(I))
        ENDDO
        S1(I,1) = S_AVG
        DO K=2,MLD(I)
! lwang modified for sst assim order Jan 2, 2020
!          T1(I,K)=T1(I,1)
          SF1(I,K)=SF1(I,1)
! lwang Jan 2, 2020
          S1(I,K)=S_AVG
        END DO
      ENDIF
#     endif

   ENDDO    

#    if defined (MULTIPROCESSOR)
!     IF(PAR)CALL AEXCHANGE(NC,MYID,NPROCS,T1) !Interprocessor Exchange   !
     IF(PAR)CALL AEXCHANGE(NC,MYID,NPROCS,S1)
!---> Siqi Li for MLD_output @ 2019-05-01
!     IF(PAR) CALL AEXCHANGE(NC,MYID,NPROCS,MLD_OUT) ! Removed by Siqi Li, @20210809
!     IF(PAR) CALL AEXCHANGE(NC,MYID,NPROCS,MLD_Nsiglay) ! Removed by Siqi Li, @20210809
!<--- Siqi
#    endif

   
!   CALL N2E3D(T1,T)
   CALL N2E3D(S1,S)

   RETURN
   END SUBROUTINE SSSGRD_NUDGE
!==============================================================================|

   SUBROUTINE SSHGRD_NUDGE
  
!==============================================================================|
!  USE SST OBSERVATION DATA TO NUDGE SURFACE TEMPERATURE                       |
!==============================================================================|
   IMPLICIT NONE
   REAL(SP) :: TDIFF,T_WEIGHT,TRUTH,ADJUSTMENT
   INTEGER I,K
   REAL(SP) :: F_SPATIAL, SSH_SAVED_R
   REAL(SP) :: VX_TMP
!qxu{for SSH assimilation by 04/01/2022
   !REAL(SP) ::R0,R1,R2
   REAL(DP) ::R0,R1,R2
!qxu}

!==============================================================================|

# if defined (ENKF)

     SSH_SAVED(1:M,:)=SSH_SAVED_ENKF(1:M,:,ENKF_memberCONTR)
     SSH_AVG(:)=SSH_AVG_ENKF(:,ENKF_memberCONTR)
# endif

!------------------------------------------------------------------------------!
!  Calculate Temporal Weight of Measurement (I) at Time(TIME)                  ! 
!------------------------------------------------------------------------------!
!qxu{for SSH assimilation by 04/01/2022
!   IF(IntTime > SSH_SAVE_TIME + SSH_SAVE_INTERVAL/2) THEN  !org
    IF(IntTime > SSH_SAVE_TIME ) THEN
!qxu}
   
      SSH_SAVE_INDEX = SSH_SAVE_INDEX + 1

      SSH_SAVE_TIME = SSH_SAVE_TIME + SSH_SAVE_INTERVAL
      
      IF(DBG_SET(DBG_LOG)) THEN
         WRITE(IPT,*) "Setting ssh state # ",SSH_SAVE_INDEX
!         CALL PRINT_REAL_TIME(SSH_SAVE_TIME,IPT,"Set at")
      END IF

   END IF
!qxu{for SSH assimilation by 04/01/2022
   IF(SSH_SAVE_INDEX.eq.1) SSH_SAVE_TIME0=SSH_SAVE_TIME
!qxu

   ! GET TIME DIFFERENCE IN SECONDS
!qxu{for SSH assimilation by 04/01/2022
!   TDIFF = SECONDS(IntTime - SSH_SAVE_TIME )       !org
!   TDIFF = SECONDS(IntTime - SSH_SAVE_TIME + SSH_SAVE_INTERVAL/2.0)   !case7_1: shift 0.5 hours
   TDIFF = SECONDS(IntTime - SSH_SAVE_TIME0 + SSH_SAVE_INTERVAL ) - SSHGRD_TIME_WINDOW

!qxu}

   TDIFF = ABS(TDIFF)

   IF(TDIFF < 0.5*SSHGRD_TIME_WINDOW) THEN
     T_WEIGHT = 1.0
   ELSE IF(TDIFF < SSHGRD_TIME_WINDOW) THEN
     T_WEIGHT = (SSHGRD_TIME_WINDOW-TDIFF)/SSHGRD_TIME_WINDOW*2.0
   ELSE
     T_WEIGHT = 0.0
   END IF
!qxu{for SSH assimilation t_weight, by 04/07/2022
!   IF(SSH_SAVE_INDEX.ge.2.and.SSH_SAVE_INDEX.le.23) T_WEIGHT=1.0
!qxu}  
   !IF(T_WEIGHT == 0.0) RETURN

   R0 = SECONDS(IntTime)
   R1 = SECONDS(SSH_SAVE_TIME)
   R2 = SECONDS(SSH_SAVE_INTERVAL)
   DO I=1,M

#     if defined (SPHERICAL)
      F_SPATIAL = 1.0_SP
#     endif
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!ysun DEC 20 2010
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1ysun MAY 10 2010 modified by lwang from Dr. Qi
!          IF(H(I)<=1000.0_SP) THEN
!            F_SPATIAL = 0.0_SP
!!          ELSEIF(H(I)>=500.0_SP) THEN
!!            F_SPATIAL = 1.0_SP
!          ELSE
!            F_SPATIAL = 1.0_SP
!          ENDIF
!qxu{change by 02/08/2022
!          IF(H(I)<=1000.0_SP) THEN
!            F_SPATIAL = 0.0_SP
!          ELSE IF (H(I)>1000.0_SP .AND. H(I)<=2500.0_SP) THEN
!            F_SPATIAL = (H(I)-1000.0_SP)/1500.0_SP
!          ELSE
!            F_SPATIAL = 1.0_SP
!          ENDIF

!@---> Siqi Li, SSH@20240501
! Remove the SSH control factor on depth 
!          IF(H(I)<=200.0_SP) THEN
!            F_SPATIAL = 0.0_SP
!          ELSE IF (H(I)>200.0_SP .AND. H(I)<=1000.0_SP) THEN
!            F_SPATIAL = (H(I)-200.0_SP)/800.0_SP
!          ELSE
!            F_SPATIAL = 1.0_SP
!          ENDIF
          F_SPATIAL = 1.0_SP
!@<---
!qxu}

      IF(IntTime>SSH_SAVE_TIME .AND. IntTime<= SSH_SAVE_TIME + SSH_SAVE_INTERVAL/2 ) THEN
        SSH_SAVED_R = ( SSH_SAVED(I,SSH_SAVE_INDEX)*(R1+R2-R0)+SSH_SAVED(I,SSH_SAVE_INDEX+1)*(R0-R1) )/R2
      ELSE
        SSH_SAVED_R = ( SSH_SAVED(I,SSH_SAVE_INDEX-1)*(R1-R0)+SSH_SAVED(I,SSH_SAVE_INDEX)*(R0-R1+R2) )/R2 
      ENDIF

      !TRUTH = MODEL_SAVED@INTERVAL + OBSERVED_AVG  - MODEL_AVG
!      TRUTH = SSH_SAVED(I,SSH_SAVE_INDEX) + SSH_OBS(I) - SSH_AVG(I)
      TRUTH = SSH_SAVED_R + SSH_OBS(I) - SSH_AVG(I)
      ! ADJUSMENT = MAX_WEIGHT * (TRUTH-CURRENT) * (WEIGHT_BY_TIME)
      ADJUSTMENT = SSHGRD_WEIGHT_MAX*(TRUTH-EL(i))*T_WEIGHT*F_SPATIAL
      ! RESULT = CURRENT + DTI*TIMESCALE * ADJUSTMENT 
      EL(I)=EL(I)+DTI*SSHGRD_TIMESCALE*ADJUSTMENT
      EL(I)=EL(I)*RAMP
   ENDDO    

   
#  if defined (MULTIPROCESSOR)
   IF(PAR)CALL AEXCHANGE(NC,MYID,NPROCS,EL) !Interprocessor Exchange   !
#  endif

   CALL N2E2D(EL,EL1)

#   if defined (ICE_EMBEDDING)
  DO I = 1, NT                                !!yding
    QTHICE1(I) = (QTHICE(NV(I,1))+QTHICE(NV(I,2))+QTHICE(NV(I,3)))/3.0_SP
  END DO

  D   = H + EL - QTHICE     !!yding
  D1  = H1 + EL1 - QTHICE1  !!yding

#   else

   D   = H + EL
   D1  = H1 + EL1

#   endif

   RETURN
   END SUBROUTINE SSHGRD_NUDGE

!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   SUBROUTINE TSGRD_OBSERVATION_UPDATE(NOW)
!------------------------------------------------------------------------------!
   IMPLICIT NONE

   TYPE(TIME), INTENT(IN) :: NOW
   TYPE(TIME)             :: WTIME
   TYPE(NCFTIME), POINTER :: FTM
   REAL(SP), POINTER      :: VNP_ARR(:,:), VPP_ARR(:,:)
   INTEGER :: STATUS

!   TS_FILE%FTIME%NEXT_STKCNT = Pmonth  !!!  the month

!   CALL NC_READ_VAR(VAR_TC,TS_FILE%FTIME%NEXT_STKCNT)
!   CALL NC_READ_VAR(VAR_SC,TS_FILE%FTIME%NEXT_STKCNT)

!!   TS_FILE%FTIME%NEXT_STKCNT = TS_FILE%FTIME%NEXT_STKCNT + 1

   WTIME = NOW

   FTM => TS_FILE%FTIME

   ! T OBSERVATION UPDATE
   CALL UPDATE_VAR_BRACKET(TS_FILE,TSC_T1_P,TSC_T1_N,WTIME,STATUS)
   IF (STATUS /= 0) THEN
     CALL FATAL_ERROR("COULD NOT UPATE TS BRACKET: BOUNDS EXCEEDED?")
   end if
    
   CALL NC_POINT_VAR(TSC_T1_N,VNP_ARR)
   CALL NC_POINT_VAR(TSC_T1_P,VPP_ARR)   
   TC_OBS = FTM%NEXT_WGHT * VNP_ARR + FTM%PREV_WGHT * VPP_ARR

   ! S OBSERVATION UPDATE
   CALL UPDATE_VAR_BRACKET(TS_FILE,TSC_S1_P,TSC_S1_N,WTIME,STATUS)
   IF (STATUS /= 0) THEN
     CALL FATAL_ERROR("COULD NOT UPATE TS BRACKET: BOUNDS EXCEEDED?")
   end if
    
   CALL NC_POINT_VAR(TSC_S1_N,VNP_ARR)
   CALL NC_POINT_VAR(TSC_S1_P,VPP_ARR)   
   SC_OBS = FTM%NEXT_WGHT * VNP_ARR + FTM%PREV_WGHT * VPP_ARR

   ! RESET THE INDEX AND THE TIME FOR USE IN THE ASSIMILATION CYCLE
   TSC_SAVE_INDEX = 1
   TSC_SAVE_TIME = IntTime_BUF + TSC_SAVE_INTERVAL

   END SUBROUTINE TSGRD_OBSERVATION_UPDATE

!==============================================================================|

!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|
   SUBROUTINE TSGRD_NUDGE
  
!==============================================================================|
!  USE TS OBSERVATION DATA TO NUDGE SURFACE TEMPERATURE                       |
!==============================================================================|
#  if defined (PWP)
   USE MOD_PWP, only : MLD
#  endif
   IMPLICIT NONE
   REAL(SP) :: TDIFF,T_WEIGHT,TRUTH,ADJUSTMENT
   INTEGER I,K,K1

!==============================================================================|

!     IF(.false.) THEN

!------------------------------------------------------------------------------!
!  Calculate Temporal Weight of Measurement (I) at Time(TIME)                  ! 
!------------------------------------------------------------------------------!
   IF(IntTime > TSC_SAVE_TIME + TSC_SAVE_INTERVAL/2) THEN
   
      TSC_SAVE_INDEX = TSC_SAVE_INDEX + 1

      TSC_SAVE_TIME = TSC_SAVE_TIME + TSC_SAVE_INTERVAL
      
      IF(DBG_SET(DBG_LOG)) THEN
         WRITE(IPT,*) "Setting T/S state # ",TSC_SAVE_INDEX
!         CALL PRINT_REAL_TIME(TSC_SAVE_TIME,IPT,"Set at")
      END IF

   END IF

   ! GET TIME DIFFERENCE IN SECONDS
   TDIFF = SECONDS(IntTime - TSC_SAVE_TIME)
   TDIFF = ABS(TDIFF)

   IF(TDIFF < 0.5*TSGRD_TIME_WINDOW) THEN
     T_WEIGHT = 1.0
   ELSE IF(TDIFF < TSGRD_TIME_WINDOW) THEN
     T_WEIGHT = (TSGRD_TIME_WINDOW-TDIFF)/TSGRD_TIME_WINDOW*2.0
   ELSE
     T_WEIGHT = 0.0
   END IF
  
   IF(T_WEIGHT == 0.0) RETURN

   DO I=1,M

      IF(SSTGRD_ASSIM) THEN
        K1 = 2
      ELSE
        K1 = 1
      ENDIF
#     if defined (PWP)
      IF(MLD(I)<0) THEN
        K1 = 2
      ELSE
        K1 = MLD(I)+1
      ENDIF
#     endif

      DO K=K1,KBM1
      !TRUTH = MODEL_SAVED@INTERVAL + OBSERVED_AVG  - MODEL_AVG
      TRUTH = TC_SAVED(I,K,TSC_SAVE_INDEX) + TC_OBS(I,K) - TC_AVG(I,K)
      ! ADJUSMENT = MAX_WEIGHT * (TRUTH-CURRENT) * (WEIGHT_BY_TIME)
      ADJUSTMENT = TSGRD_WEIGHT_MAX*(TRUTH-T1(I,K))*T_WEIGHT
      ! RESULT = CURRENT + DTI*TIMESCALE * ADJUSTMENT 
      T1(I,K)=T1(I,K)+DTI*TSGRD_TIMESCALE*ADJUSTMENT
      ENDDO
   ENDDO

   DO I=1,M
      DO K=1, KBM1
      !TRUTH = MODEL_SAVED@INTERVAL + OBSERVED_AVG  - MODEL_AVG
      TRUTH = SC_SAVED(I,K,TSC_SAVE_INDEX) + SC_OBS(I,K) - SC_AVG(I,K)
      ! ADJUSMENT = MAX_WEIGHT * (TRUTH-CURRENT) * (WEIGHT_BY_TIME)
      ADJUSTMENT = TSGRD_WEIGHT_MAX*(TRUTH-S1(I,K))*T_WEIGHT
      ! RESULT = CURRENT + DTI*TIMESCALE * ADJUSTMENT 
      S1(I,K)=S1(I,K)+DTI*TSGRD_TIMESCALE*ADJUSTMENT
      END DO
   ENDDO    

!   DO I=1,M
!      DO K=1,KBM1
!      !TRUTH = MODEL_SAVED@INTERVAL + OBSERVED_AVG  - MODEL_AVG
!      TRUTH = SC_SAVED(I,K,TSC_SAVE_INDEX) + SC_OBS(I,K) - SC_AVG(I,K)
!      ! ADJUSMENT = MAX_WEIGHT * (TRUTH-CURRENT) * (WEIGHT_BY_TIME)
!      ADJUSTMENT = TSGRD_WEIGHT_MAX*(TRUTH-S1(i,k))*T_WEIGHT
!      ! RESULT = CURRENT + DTI*TIMESCALE * ADJUSTMENT 
!      S1(I,k)=S1(I,k)+DTI*TSGRD_TIMESCALE*ADJUSTMENT
!      END DO
!   ENDDO      
   
!    endif !! change to the new methon

!!  Average the simulation TS over the assimulation perion
  
!------------------------------------------------------------------------------!
!  Calculate Temporal Weight of Measurement (I) at Time(TIME)                  ! 
!------------------------------------------------------------------------------!


   ! GET TIME DIFFERENCE IN SECONDS
!   TDIFF = SECONDS(IntTime - TSC_SAVE_TIME)
!   TDIFF = ABS(TDIFF)
!   !TDIFF = ABS(TDIFF)/(10.0_SP*144.*dti)  !!  5 days windows 5.0*
!   TDIFF = ABS(TDIFF)/(10.0_SP*86400.)  !! 20 days windows 5.0*

!   !T_WEIGHT =DTI * ISQPI2*EXP(-(TDIFF*TDIFF))
!   T_WEIGHT = ISQPI2*EXP(-(TDIFF*TDIFF)/2.0_SP)
!   !T_WEIGHT = T_WEIGHT/(10.0_SP*144.)
!   T_WEIGHT = T_WEIGHT/(10.0_SP*86400./dti)
   
!   DO I=1,M
!      DO K=1,KBM1
!      TRUTH = TC_OBS(I,K) - TC0_AVG(I,K)
!      ADJUSTMENT = TRUTH*T_WEIGHT
!      T1(I,k)=T1(I,k)+ADJUSTMENT
      
!      TRUTH = SC_OBS(I,K) - SC0_AVG(I,K)
!      ADJUSTMENT = TRUTH*T_WEIGHT
!      S1(I,k)=S1(I,k)+ADJUSTMENT
!      END DO
!   ENDDO    
!!  ggao 2009
!     WHERE(S1 < 0.0_SP)S1=0.0_SP

   
#  if defined (MULTIPROCESSOR)
   IF(PAR)CALL AEXCHANGE(NC,MYID,NPROCS,T1) !Interprocessor Exchange   !
   IF(PAR)CALL AEXCHANGE(NC,MYID,NPROCS,S1) !Interprocessor Exchange   !
#  endif

   
   CALL N2E3D(T1,T)
   CALL N2E3D(S1,S)
   

   RETURN
   END SUBROUTINE TSGRD_NUDGE
!==============================================================================|
  SUBROUTINE SET_SST_SAVE_TIME_INDEX(FLAG)
   IMPLICIT NONE
   INTEGER I,FLAG
    TYPE(TIME) :: TEMP_TIME
  IF (FLAG==0) THEN
    TEMP_TIME%MJD=Inttime%mjd
    TEMP_TIME%musod=0.0
   DO I=1,SSTGRD_N_PER_INTERVAL
      IF  (inttime<SST_SAVE_INTERVAL*I+TEMP_TIME) THEN
           SST_SAVE_TIME=SST_SAVE_INTERVAL*I+TEMP_TIME
           SST_SAVE_INDEX=I
	   RETURN     
      END IF
   END DO 
   PRINT *, "FAILED TO FIND THE RIGHT SST SAVE TIME INDEX , STOP"
   PRINT *, 'CURRERNT INTTIME IS: ', INTTIME
   CALL PSTOP
   RETURN     
  ELSEIF (FLAG==1) THEN
    TEMP_TIME%MJD=Inttime%mjd
    TEMP_TIME%musod=0.0
    DO I=1,SSTGRD_N_PER_INTERVAL
      IF  (inttime<=SST_SAVE_INTERVAL*I+TEMP_TIME+SST_SAVE_INTERVAL/2.0) THEN
           SST_SAVE_TIME=SST_SAVE_INTERVAL*I+TEMP_TIME
           SST_SAVE_INDEX=I
	   RETURN     
      END IF
   END DO
   PRINT *, "FAILED TO FIND THE RIGHT SST SAVE TIME INDEX , STOP"
   PRINT *, 'CURRERNT INTTIME IS: ', INTTIME
   CALL PSTOP
   RETURN     
  ELSE
     PRINT *, 'FLAG IN SET_SST_SAVE_TIME_INDEX CANNOT BE :',FLAG
     CALL PSTOP
  END IF
  
  END SUBROUTINE SET_SST_SAVE_TIME_INDEX


!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|
   SUBROUTINE SST_SAVE     
!==============================================================================|
!  SAVE INTERVAL-AVERAGAED SST DATA ON GRID TO USE AS OBSERVATION              | 
!==============================================================================|
! lwang added for SST mld assimilation
USE EQS_OF_STATE
! lwang
   IMPLICIT NONE
   INTEGER I
! lwang added for SST mld assimilation
   INTEGER :: K
   REAL(SP),PARAMETER :: PR = 0.0_SP
   REAL(SP),ALLOCATABLE, DIMENSION(:,:)  :: RZU
! lwang    
!==============================================================================|

   IF(IntTime >= SST_SAVE_TIME) THEN
   
      SST_SAVE_INDEX = SST_SAVE_INDEX + 1
      
      IF(DBG_SET(DBG_LOG)) THEN
         WRITE(IPT,*) "Saving sst state # ",SST_SAVE_INDEX
      END IF
!------------------------------------------------------------------------------!
!  Save Hourly SST on grid in Simulation running                               ! 
!------------------------------------------------------------------------------!
      SST_SAVED(1:M,SST_SAVE_INDEX) = T1(1:M,1)
! lwang added for SST mld assimilation
      IF(SSTGRD_MLD)THEN
         T_SAVED(1:M,1:KBM1,SST_SAVE_INDEX) = T1(1:M,1:KBM1)
         S_SAVED(1:M,1:KBM1,SST_SAVE_INDEX) = S1(1:M,1:KBM1)
      END IF
! lwang
# if defined (ENKF)
     SST_SAVED_ENKF(1:M,SST_SAVE_INDEX,ENKF_memberCONTR)=SST_SAVED(1:M,SST_SAVE_INDEX)
# endif
      ! INCRIMENT THE SAVE_TIME
      SST_SAVE_TIME = SST_SAVE_TIME + SST_SAVE_INTERVAL

!------------------------------------------------------------------------------!
!  Average Hourly Data Over Integration Period                                 ! 
!------------------------------------------------------------------------------!

      IF(SST_SAVE_INDEX == SSTGRD_N_PER_INTERVAL )THEN
      
         DO I=1,M
            SST_AVG(I) = SUM(SST_SAVED(I,1:SSTGRD_N_PER_INTERVAL))&
                 &/real(SSTGRD_N_PER_INTERVAL,SP)
! lwang added for SST mld assimilation
            IF(SSTGRD_MLD)THEN
               TT_AVG(I,1:KBM1) = SUM(T_SAVED(I,1:KBM1,1:SSTGRD_N_PER_INTERVAL),2)&
                    &/real(SSTGRD_N_PER_INTERVAL,SP)
               SS_AVG(I,1:KBM1) = SUM(S_SAVED(I,1:KBM1,1:SSTGRD_N_PER_INTERVAL),2)&
                    &/real(SSTGRD_N_PER_INTERVAL,SP)
            END IF
! lwang
# if defined (ENKF)          
            SST_AVG_ENKF(I,ENKF_memberCONTR)=SST_AVG(I)
# endif

         END DO
! lwang added for SST mld assimilation
         IF(SSTGRD_MLD)THEN
            SELECT CASE(SEA_WATER_DENSITY_FUNCTION)
            CASE(SW_DENS1)

              ALLOCATE(RZU(M,KBM1))        ; RZU = -999.0_SP
              DO I=1,M
                DO K=1,KBM1
                  RZU(I,K) = GRAV_N(I)*1.025_SP*(-ZZ(I,K)*D(I))*0.1_SP
                END DO
              END DO

              CALL FOFONOFF_MILLARD(SS_AVG,TT_AVG,RZU,PR,RHO_AVG)
              DEALLOCATE(RZU)

            CASE(SW_DENS2)

              CALL DENS2G(SS_AVG,TT_AVG,RHO_AVG)

            CASE(SW_DENS3)

              ALLOCATE(RZU(M,KBM1))        ; RZU = -999.0_SP
              DO I=1,M
                DO K=1,KBM1
                  RZU(I,K) = GRAV_N(I)*1.025_SP*(-ZZ(I,K)*D(I))*0.01_SP
                END DO
              END DO

              CALL JACKET_MCDOUGALL(SS_AVG,TT_AVG,RZU,RHO_AVG)
              DEALLOCATE(RZU)
            CASE DEFAULT
              CALL FATAL_ERROR("INVALID DENSITY FUNCTION SELECTED:",&
                   & "   "//TRIM(SEA_WATER_DENSITY_FUNCTION) )
            END SELECT
            ! Convert the rho into the unit kg/m3
!            RHO_AVG=RHO_AVG*1000.+1000.

         END IF
! lwang         
      END IF

   END IF
   
   RETURN
   END SUBROUTINE SST_SAVE

!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|
   SUBROUTINE SSS_SAVE     
!==============================================================================|
!  SAVE INTERVAL-AVERAGAED SSS DATA ON GRID TO USE AS OBSERVATION              | 
!==============================================================================|

   IMPLICIT NONE
   INTEGER I
!==============================================================================|

   IF(IntTime >= SSS_SAVE_TIME) THEN
   
      SSS_SAVE_INDEX = SSS_SAVE_INDEX + 1
      
      IF(DBG_SET(DBG_LOG)) THEN
         WRITE(IPT,*) "Saving sss state # ",SSS_SAVE_INDEX
      END IF
!------------------------------------------------------------------------------!
!  Save Hourly SSS on grid in Simulation running                               ! 
!------------------------------------------------------------------------------!
      SSS_SAVED(1:M,SSS_SAVE_INDEX) = S1(1:M,1)

# if defined (ENKF)
     SSS_SAVED_ENKF(1:M,SSS_SAVE_INDEX,ENKF_memberCONTR)=SSS_SAVED(1:M,SSS_SAVE_INDEX)
# endif
      ! INCRIMENT THE SAVE_TIME
      SSS_SAVE_TIME = SSS_SAVE_TIME + SSS_SAVE_INTERVAL

!------------------------------------------------------------------------------!
!  Average Hourly Data Over Integration Period                                 ! 
!------------------------------------------------------------------------------!

      IF(SSS_SAVE_INDEX == SSSGRD_N_PER_INTERVAL )THEN
      
         DO I=1,M
            SSS_AVG(I) = SUM(SSS_SAVED(I,1:SSSGRD_N_PER_INTERVAL))&
                 &/real(SSSGRD_N_PER_INTERVAL,SP)
# if defined (ENKF)          
            SSS_AVG_ENKF(I,ENKF_memberCONTR)=SSS_AVG(I)
# endif

         END DO
      END IF

   END IF
   
   RETURN
   END SUBROUTINE SSS_SAVE

!==============================================================================|
  SUBROUTINE SET_SSH_SAVE_TIME_INDEX(FLAG)
   IMPLICIT NONE
   INTEGER I,FLAG
    TYPE(TIME) :: TEMP_TIME
  IF (FLAG==0) THEN
    TEMP_TIME%MJD=Inttime%mjd
    TEMP_TIME%musod=0.0
   DO I=1,SSHGRD_N_PER_INTERVAL
      IF  (inttime<SSH_SAVE_INTERVAL*I+TEMP_TIME) THEN
           SSH_SAVE_TIME=SSH_SAVE_INTERVAL*I+TEMP_TIME
           SSH_SAVE_INDEX=I
           RETURN   
      END IF
   END DO
   PRINT *, "FAILED TO FIND THE RIGHT SSH SAVE TIME INDEX , STOP"
   PRINT *, 'CURRERNT INTTIME IS: ', INTTIME
   CALL PSTOP
   RETURN   
  ELSEIF (FLAG==1) THEN
        TEMP_TIME%MJD=Inttime%mjd
    TEMP_TIME%musod=0.0
   DO I=1,SSHGRD_N_PER_INTERVAL
!qxu{for SSH assimilation by 04/01/2022
      !IF  (inttime<=SSH_SAVE_INTERVAL*I+TEMP_TIME+SSH_SAVE_INTERVAL/2.0) THEN
       IF  (inttime<=SSH_SAVE_INTERVAL*I+TEMP_TIME) then
!qxu}

           SSH_SAVE_TIME=SSH_SAVE_INTERVAL*I+TEMP_TIME
           SSH_SAVE_INDEX=I
           RETURN   
      END IF
   END DO
   PRINT *, "FAILED TO FIND THE RIGHT SSH SAVE TIME INDEX , STOP"
   PRINT *, 'CURRERNT INTTIME IS: ', INTTIME
   CALL PSTOP
   RETURN   
  ELSE
    PRINT *, 'FLAG IN SET_SSH_SAVE_TIME_INDEX CANNOT BE: ',FLAG
    CALL PSTOP
  END IF
  END SUBROUTINE SET_SSH_SAVE_TIME_INDEX

   SUBROUTINE SSH_SAVE     
!==============================================================================|
!  SAVE INTERVAL-AVERAGAED SSH DATA ON GRID TO USE AS OBSERVATION              | 
!==============================================================================|
   IMPLICIT NONE
   INTEGER I
   
!==============================================================================|

   IF(IntTime >= SSH_SAVE_TIME) THEN
   
      SSH_SAVE_INDEX = SSH_SAVE_INDEX + 1
      
      IF(DBG_SET(DBG_LOG)) THEN
         WRITE(IPT,*) "Saving ssh state # ",SSH_SAVE_INDEX
      END IF
!------------------------------------------------------------------------------!
!  Save Hourly SSH on grid in Simulation running                               ! 
!------------------------------------------------------------------------------!
      SSH_SAVED(1:M,SSH_SAVE_INDEX) = EL(1:M)
!qxu{for SSH assimilation by 04/01/2022
      if (SSH_SAVE_INDEX.eq.1) then
         if(FIRST_DAY) then
           SSH_SAVED(1:M,0) = EL_INITIAL(1:M)
           !SSH_SAVED(1:M,SSH_SAVE_INDEX) = EL_INITIAL(1:M)
           FIRST_DAY = .FALSE.
           IF(DBG_SET(DBG_LOG)) THEN
              WRITE(IPT,*) "Saving first_day ssh state # ",0
           END IF
         else
           SSH_SAVED(1:M,0) = SSH_SAVED(1:M,24)
           IF(DBG_SET(DBG_LOG)) THEN
              WRITE(IPT,*) "Saving after 1 day ssh state # ",0
           END IF
         endif
         !if(MSR) write(600,'(i5,f15.2,5f12.4)') 0,SECONDS(IntTime)-3600,
         !SSH_SAVED(1:5,0)

      endif
      if (FIRST_DAY.and.SSH_SAVE_INDEX.eq.2) then
         SSH_SAVED(1:M,1) = (SSH_SAVED(1:M,0) + SSH_SAVED(1:M,2))/2.0
      endif
      !if(MSR) write(600,'(i5,f15.2,5f12.4)') SSH_SAVE_INDEX,SECONDS(IntTime),SSH_SAVED(1:5,SSH_SAVE_INDEX)
!qxu}

# if defined (ENKF)
     SSH_SAVED_ENKF(1:M,SSH_SAVE_INDEX,ENKF_memberCONTR)=SSH_SAVED(1:M,SSH_SAVE_INDEX)
# endif
      
      ! INCRIMENT THE SAVE_TIME
      SSH_SAVE_TIME = SSH_SAVE_TIME + SSH_SAVE_INTERVAL

!------------------------------------------------------------------------------!
!  Average Hourly Data Over Integration Period                                 ! 
!------------------------------------------------------------------------------!

      IF(SSH_SAVE_INDEX == SSHGRD_N_PER_INTERVAL )THEN
      
         DO I=1,M
            SSH_AVG(I) = SUM(SSH_SAVED(I,1:SSHGRD_N_PER_INTERVAL))&
                 &/real(SSHGRD_N_PER_INTERVAL,SP)
# if defined (ENKF)
            SSH_AVG_ENKF(I,ENKF_memberCONTR)=SSH_AVG(I)
# endif

         END DO
         
      END IF

   END IF
   
   RETURN
 END SUBROUTINE SSH_SAVE

!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|
   SUBROUTINE TSGRD_SAVE     
!==============================================================================|
!  SAVE INTERVAL-AVERAGAED TS DATA ON GRID TO USE AS OBSERVATION              | 
!==============================================================================|
!   USE MOD_PREC
!   USE ALL_VARS
!   USE MOD_PAR
!   IMPLICIT NONE
!   INTEGER I,K
   
!==============================================================================|

!   IF(IntTime >= TSC_SAVE_TIME) THEN
   
!      TSC_SAVE_INDEX = TSC_SAVE_INDEX + 1
      
!      IF(DBG_SET(DBG_LOG)) THEN
!         WRITE(IPT,*) "Saving ts state # ",TSC_SAVE_INDEX
!      END IF
!------------------------------------------------------------------------------!
!  Save Hourly TC on grid in Simulation running                               ! 
!------------------------------------------------------------------------------!
!      TC_SAVED(1:M,1:KBM1,TSC_SAVE_INDEX) = T1(1:M,1:KBM1)
!      SC_SAVED(1:M,1:KBM1,TSC_SAVE_INDEX) = S1(1:M,1:KBM1)

      ! INCRIMENT THE SAVE_TIME
!!      TSC_SAVE_TIME = TSC_SAVE_TIME + TSC_SAVE_INTERVAL

!------------------------------------------------------------------------------!
!  Average Hourly Data Over Integration Period                                 ! 
!------------------------------------------------------------------------------!

!      IF(TSC_SAVE_INDEX == TSGRD_N_PER_INTERVAL )THEN
      
!         DO I=1,M
!            DO K=1,KBM1
!            TC_AVG(I,K) = SUM(TC_SAVED(I,K,1:TSGRD_N_PER_INTERVAL))&
!                 &/real(TSGRD_N_PER_INTERVAL,SP)
!            SC_AVG(I,K) = SUM(SC_SAVED(I,K,1:TSGRD_N_PER_INTERVAL))&
!                 &/real(TSGRD_N_PER_INTERVAL,SP)
!            END DO
!         END DO
         
!      END IF

!   END IF

   IMPLICIT NONE
   INTEGER I,K
   
!==============================================================================|

   IF(ASSIM_FLAG==0) THEN

     IF(IntTime >= TSC_SAVE_TIME) THEN

       TSC_SAVE_INDEX = TSC_SAVE_INDEX + 1
      
       IF(DBG_SET(DBG_LOG)) WRITE(IPT,*) "Saving T/S hourly state # ",TSC_SAVE_INDEX
!------------------------------------------------------------------------------!
!  Save Hourly TC on grid in Simulation running                               ! 
!------------------------------------------------------------------------------!
       TC_SAVED(1:M,1:KBM1,TSC_SAVE_INDEX) = T1(1:M,1:KBM1)
       SC_SAVED(1:M,1:KBM1,TSC_SAVE_INDEX) = S1(1:M,1:KBM1)

       ! INCRIMENT THE SAVE_TIME
       TSC_SAVE_TIME = TSC_SAVE_TIME + TSC_SAVE_INTERVAL

!------------------------------------------------------------------------------!
!  Average Hourly Data Over Integration Period                                 ! 
!------------------------------------------------------------------------------!
   
       IF(TSC_SAVE_INDEX == TSGRD_N_PER_INTERVAL )THEN
      
         DO I=1,M
           DO K=1,KBM1
             TC_AVG(I,K) = SUM(TC_SAVED(I,K,1:TSGRD_N_PER_INTERVAL))&
                         &/real(TSGRD_N_PER_INTERVAL,SP)
             SC_AVG(I,K) = SUM(SC_SAVED(I,K,1:TSGRD_N_PER_INTERVAL))&
                         &/real(TSGRD_N_PER_INTERVAL,SP)
           END DO
         END DO
         
       END IF

     END IF

   ENDIF

!------------------------------------------------------------------------------!
!  Save Monthly averaged T/S on grid in Assimilation run                       !
!------------------------------------------------------------------------------!
   IF(ASSIM_FLAG==1) THEN

     DO I=1,M
       DO K=1,KBM1
         TC0_AVG(I,K) = TC0_AVG(I,K)+T1(I,K)
         SC0_AVG(I,K) = SC0_AVG(I,K)+S1(I,K)
       END DO
     END DO

!------------------------------------------------------------------------------!
!  Average Hourly Data Over Integration Period                                 !
!------------------------------------------------------------------------------!
     IF(IntTime >= TSC_SAVE_TIME2 )THEN
       IF(DBG_SET(DBG_LOG)) WRITE(IPT,*) "Save averaged T/S state "
       DO I=1,M
         DO K=1,KBM1
           TC0_AVG(I,K) = TC0_AVG(I,K)/(real(Pmdays,kind=DP)*24.*3600./DTI)
           SC0_AVG(I,K) = SC0_AVG(I,K)/(real(Pmdays,kind=DP)*24.*3600./DTI)
         END DO
       END DO
     END IF

   ENDIF
   
   RETURN
   END SUBROUTINE TSGRD_SAVE


!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%|
!==============================================================================|
!   READ IN DATA FROM SIMULATION STAGE AND FOR ASSIMILATION STAGE STARTUP      |
!==============================================================================|

   SUBROUTINE RESTORE_STATE

    !------------------------------------------------------------------------------|
    USE EQS_OF_STATE
# if defined (ICE)
    USE mod_ICE
    USE mod_ICE2D, only: sig1, sig2, sig12
# endif

    IMPLICIT NONE

    INTEGER :: I

    if(dbg_set(dbg_sbr)) WRITE(IPT,*) "start RESTORE_STATE"

    IINT   = IINT_BUF
    ExtTime=ExtTime_BUF
    IntTime=IntTime_BUF

    IF(RECALCULATE_RHO_MEAN) THEN
       RECALC_RHO_MEAN =IntTime_BUF
    END IF

    U      = U_BUF
    V      = V_BUF
    WTS    = WTS_BUF
    S1     = S1_BUF
    T1     = T1_BUF

    KM     = KM_BUF
    KH     = KH_BUF
    KQ     = KQ_BUF

    UA     = UA_BUF
    VA     = VA_BUF

    EL     = EL_BUF
    ET     = ET_BUF
    H      = H_BUF

#  if defined (SEDIMENT)
   DO I=1,NSED
     sed(i)%conc = conc_buf(i,:,:)
   END DO
#  endif

#  if defined (EQUI_TIDE)
    EL_EQI = EL_EQI_BUF
#  endif

#  if defined (ATMO_TIDE)
    EL_ATMO= EL_ATMO_BUF
#  endif

# if defined(GOTM)
    TEPS   = TEPS_BUF
    TKE    = TKE_BUF
# else
    Q2     = Q2_BUF
    Q2L    = Q2L_BUF
    L      = L_BUF
# endif

#  if defined (DYE_RELEASE)
    DYE    = DYE_BUF
    DYEF   = DYEF_BUF
!    DYEMEAN = DYEMEAN_BUF
#  endif

    ! TO SAVE MEMEORY WE SAVED ONLY THE INTERNAL VALUES: CALL EXCHANGE
    ! TO SET THE HALO ELEMENTS
    IF(PAR) CALL EXCHANGE_ALL

    ! SET DEPTH AN INTERPOLATE VALUES TO CELL CENTERS
#   if defined (ICE_EMBEDDING)
    D   = H + EL - QTHICE     !!yding
    D   = H + ET - QTHICERK   !!yding
#   else
    D  = H + EL
    DT = H + ET
#   endif


    CALL N2E2D(H,H1)
    CALL N2E2D(EL,EL1)
    CALL N2E2D(D,D1)
    CALL N2E2D(DT,DT1)

    ! SET THE DENSITY
    SELECT CASE(SEA_WATER_DENSITY_FUNCTION)
    CASE(SW_DENS1)
       CALL DENS1
    CASE(SW_DENS2)
       CALL DENS2
    CASE(SW_DENS3)
       CALL DENS3
    CASE DEFAULT
       CALL FATAL_ERROR("INVALID DENSITY FUNCTION SELECTED:",&
            & "   "//TRIM(SEA_WATER_DENSITY_FUNCTION) )
    END SELECT

    CALL N2E3D(T1,T)
    CALL N2E3D(S1,S)
    !DENSITY IS ALREADY INTERPOLATED TO ELEMENT IN DENSX

    ! SET THE VERTICAL SIGMA VELOCITY
    CALL N2E3D(WTS,W)

    ! SET THE TURBULENT QUANTITIES
#    if defined (GOTM)
    L = .001
    L(1:MT,2:KBM1) = (.5544**3)*TKE(1:MT,2:KBM1)**1.5/TEPS(1:MT,2:KBM1)
# endif

    CALL N2E3D(KM,KM1)


#   if defined(ICE)
    aicen=aicen_buf
    vicen=vicen_buf
    vsnon=vsnon_buf
    tsfcn=tsfcn_buf
    esnon=esnon_buf
    eicen=eicen_buf
    uice2=uice2_buf
    vice2=vice2_buf
    fresh=fresh_buf
    fsalt=fsalt_buf
    fhnet=fhnet_buf
    strength=strength_buf
    isicec=isicec_buf
    sig1=sig1_buf
    sig2=sig2_buf
    sig12=sig12_buf
    CALL  AGGREGATE
# endif

   if(dbg_set(dbg_sbr)) WRITE(IPT,*) "END RESTORE_STATE"

   RETURN
   END SUBROUTINE RESTORE_STATE
!==============================================================================|

!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
!==============================================================================|
!   EXCHANGE HALO'S BECAUSE WE ONLY SAVED INTERNAL VALUES TO SAVE MEMORY       |
!==============================================================================|
   SUBROUTINE EXCHANGE_ALL

!------------------------------------------------------------------------------|
!!$# if defined (WATER_QUALITY)
!!$     USE MOD_WQM
!!$# endif

#  if defined (DYE_RELEASE)
     USE MOD_DYE
#  endif

     IMPLICIT NONE

!==============================================================================|

   if(dbg_set(dbg_sbr)) WRITE(IPT,*) "001 EXCHANGE_ALL"
#  if defined (MULTIPROCESSOR)

#  if defined (GOTM)
   CALL AEXCHANGE(NC,MYID,NPROCS,TKE,TEPS)
#  else
   CALL AEXCHANGE(NC,MYID,NPROCS,Q2,Q2L,L)
#  endif

   if(dbg_set(dbg_sbr)) WRITE(IPT,*) "002 EXCHANGE_ALL"
   !CALL AEXCHANGE(NC,MYID,NPROCS,KM,KQ,KH)

   CALL AEXCHANGE(NC,MYID,NPROCS,KM)
   if(dbg_set(dbg_sbr)) WRITE(IPT,*) "0021 EXCHANGE_ALL"
   CALL AEXCHANGE(NC,MYID,NPROCS,KQ)
   if(dbg_set(dbg_sbr)) WRITE(IPT,*) "0022 EXCHANGE_ALL"
   CALL AEXCHANGE(NC,MYID,NPROCS,KH)
   if(dbg_set(dbg_sbr)) WRITE(IPT,*) "002a EXCHANGE_ALL"
   CALL AEXCHANGE(EC,MYID,NPROCS,U,V)
   if(dbg_set(dbg_sbr)) WRITE(IPT,*) "002b EXCHANGE_ALL"
   CALL AEXCHANGE(EC,MYID,NPROCS,UA,VA)
   if(dbg_set(dbg_sbr)) WRITE(IPT,*) "002c EXCHANGE_ALL"

   CALL AEXCHANGE(NC,MYID,NPROCS,S1,T1,WTS)
   if(dbg_set(dbg_sbr)) WRITE(IPT,*) "002d EXCHANGE_ALL"
   CALL AEXCHANGE(NC,MYID,NPROCS,EL,H,ET)
   if(dbg_set(dbg_sbr)) WRITE(IPT,*) "002e EXCHANGE_ALL"

   if(dbg_set(dbg_sbr)) WRITE(IPT,*) "003 EXCHANGE_ALL"
#  if defined (EQUI_TIDE)
   CALL AEXCHANGE(NC,MYID,NPROCS,EL_EQI)
#  endif

#  if defined (ATMO_TIDE)
   CALL AEXCHANGE(NC,MYID,NPROCS,EL_ATMO)
#  endif

#  if defined (WATER_QUALITY)
   CALL FATAL_ERROR("SST ASSIMILATION IS NOT SET UP FOR WATER QUALITY MODULE")
#  endif

#  if defined (DYE_RELEASE)
!   CALL AEXCHANGE(NC,MYID,NPROCS,DYEMEAN)
   CALL AEXCHANGE(NC,MYID,NPROCS,DYE)
#  endif

   if(dbg_set(dbg_sbr)) WRITE(IPT,*) "555 EXCHANGE_ALL"
#  endif

   RETURN
   END SUBROUTINE EXCHANGE_ALL

!==============================================================================|

!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
!==============================================================================|
!   DUMP DATA FILE FOR ASSIMILATION RESTART                                    |
!==============================================================================|

   SUBROUTINE SAVE_STATE

!------------------------------------------------------------------------------|

# if defined (ICE)
   USE mod_ICE
   USE mod_ICE2D, only: sig1, sig2, sig12
# endif

   IMPLICIT NONE

   INTEGER :: I

   ExtTime_BUF = ExtTime
   IntTime_BUF = IntTime
   IINT_BUF   = IINT

   U_BUF      = U
   V_BUF      = V
   WTS_BUF    = WTS
   S1_BUF     = S1
   T1_BUF     = T1

   KM_BUF     = KM
   KH_BUF     = KH
   KQ_BUF     = KQ

# if defined (GOTM)
   TKE_BUF    = TKE
   TEPS_BUF   = TEPS
# else
   Q2_BUF     = Q2
   Q2L_BUF    = Q2L
   L_BUF      = L
# endif

   UA_BUF     = UA
   VA_BUF     = VA

   EL_BUF     = EL
   ET_BUF     = ET
   H_BUF      = H

#  if defined (SEDIMENT)
   do i=1,nsed
      CONC_BUF(i,:,:) = sed(i)%conc
   end do 
#  endif

#  if defined (DYE_RELEASE)
   DYE_BUF    = DYE
   DYEF_BUF   = DYEF
!   DYEMEAN_BUF = DYEMEAN
#  endif

#  if defined (equi_tide)
   EL_EQI_BUF = EL_EQI
#  endif

#  if defined (atmo_tide)
   EL_ATMO_BUF = EL_ATMO
#  endif

#   if defined(ICE)
    aicen_buf=aicen
    vicen_buf=vicen
    vsnon_buf=vsnon
    tsfcn_buf=tsfcn
    esnon_buf=esnon
    eicen_buf=eicen
    uice2_buf=uice2
    vice2_buf=vice2
    fresh_buf=fresh
    fsalt_buf=fsalt
    fhnet_buf=fhnet
    strength_buf=strength
    isicec_buf=isicec
    sig1_buf=sig1
    sig2_buf=sig2
    sig12_buf=sig12
# endif

   IF (TSGRD_ASSIM) THEN
   IF(TSC_SAVE_INDEX2 == 1) THEN

     IF(DBG_SET(DBG_LOG)) WRITE(IPT,*) "DUMPING MONTHLY RSTFILE"
     CALL DUMP_DATA_ASSIM(NC_RST_ASSIM)

     IF(DBG_SET(DBG_LOG)) WRITE(IPT,*) "DUMPING MONTHLY T/S MEAN"
     CALL DUMP_TSAVG_ASSIM(NC_TSAVG_ASSIM)

     TC0_AVG = 0.0_SP
     SC0_AVG = 0.0_SP

   ENDIF
   ENDIF

   IF(DBG_SET(DBG_SBR)) WRITE(IPT,*) "END SAVE_STATE"

   RETURN
   END SUBROUTINE SAVE_STATE
!==============================================================================|


!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   SUBROUTINE ALLOC_BUFFER
!------------------------------------------------------------------------------|
#  if defined (ICE)
   USE ice_model_size
   USE mod_ICE2D, only :sig1,sig2,sig12
#  endif

   IMPLICIT NONE

   IF(DBG_SET(DBG_SBR)) WRITE(IPT,*) "START SAVE_STATE"

   ALLOCATE(U_BUF(0:NT,KB));   U_BUF = 0.0_SP
   ALLOCATE(V_BUF(0:NT,KB));   V_BUF = 0.0_SP
   ALLOCATE(WTS_BUF(0:MT,KB)); WTS_BUF = 0.0_SP

   ALLOCATE(S1_BUF(0:MT,KB));  S1_BUF = 0.0_SP
   ALLOCATE(T1_BUF(0:MT,KB));  T1_BUF = 0.0_SP

   ALLOCATE(KM_BUF(0:MT,KB));  KM_BUF = 0.0_SP
   ALLOCATE(KH_BUF(0:MT,KB));  KH_BUF = 0.0_SP
   ALLOCATE(KQ_BUF(0:MT,KB));  KQ_BUF = 0.0_SP

   ALLOCATE(UA_BUF(0:NT));     UA_BUF = 0.0_SP
   ALLOCATE(VA_BUF(0:NT));     VA_BUF = 0.0_SP

   ALLOCATE(EL_BUF(0:MT));     EL_BUF = 0.0_SP
   ALLOCATE(ET_BUF(0:MT));     ET_BUF = 0.0_SP
   ALLOCATE(H_BUF(0:MT));      H_BUF = 0.0_SP

#  if defined (SEDIMENT)
   ALLOCATE(CONC_BUF(NSED,0:MT,KB));  CONC_BUF = 0.0_SP
#  endif

#  if defined (EQUI_TIDE)
   ALLOCATE(EL_EQI_BUF(0:MT)); EL_EQI_BUF = 0.0_SP
#  endif

#  if defined (ATMO_TIDE)
   ALLOCATE(EL_ATMO_BUF(0:MT)); EL_ATMO_BUF = 0.0_SP
#  endif

#  if defined (GOTM)
   ALLOCATE(TKE_BUF(0:MT,KB)); TKE_BUF = 0.0_SP
   ALLOCATE(TEPS_BUF(0:MT,KB));TEPS_BUF = 0.0_SP
#  else
   ALLOCATE(Q2_BUF(0:MT,KB));  Q2_BUF = 0.0_SP
   ALLOCATE(Q2L_BUF(0:MT,KB)); Q2L_BUF = 0.0_SP
   ALLOCATE(L_BUF(0:MT,KB));   L_BUF = 0.0_SP
#  endif

#  if defined (DYE_RELEASE)
   ALLOCATE(DYE_BUF(0:MT,KB)); DYE_BUF = 0.0_SP
   ALLOCATE(DYEF_BUF(0:MT,KB)); DYEF_BUF = 0.0_SP
!   ALLOCATE(DYEMEAN_BUF(0:M,KB)); DYEMEAN_BUF = 0.0_SP
#  endif   

#  if defined(ICE)
   ALLOCATE(aicen_buf(m,1,ncat));aicen_buf=0.0_SP
   ALLOCATE(vicen_buf(m,1,ncat));vicen_buf=0.0_SP
   ALLOCATE(vsnon_buf(m,1,ncat));vsnon_buf=0.0_SP
   ALLOCATE(tsfcn_buf(m,1,ncat));tsfcn_buf=0.0_SP
   ALLOCATE(esnon_buf(m,1,ncat));esnon_buf=0.0_SP
   ALLOCATE(eicen_buf(m,1,ntilay));eicen_buf=0.0_SP
   ALLOCATE(uice2_buf(0:NT))    ;uice2_buf=0.0_SP
   ALLOCATE(vice2_buf(0:NT))    ;vice2_buf=0.0_SP
   ALLOCATE(fresh_buf(m,1))     ;fresh_buf=0.0_SP
   ALLOCATE(fsalt_buf(m,1))     ;fsalt_buf=0.0_SP
   ALLOCATE(fhnet_buf(m,1))     ;fhnet_buf=0.0_SP
   ALLOCATE(strength_buf(m,1))  ;strength_buf=0.0_SP
   ALLOCATE(isicec_buf(0:NT))   ;isicec_buf=0.0_SP
   ALLOCATE(sig1_buf(0:mt))     ;sig1_buf=0.0_SP
   ALLOCATE(sig2_buf(0:mt))     ;sig2_buf=0.0_SP
   ALLOCATE(sig12_buf(0:mt))    ;sig12_buf=0.0_SP
#  endif


   RETURN
   END SUBROUTINE ALLOC_BUFFER

!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
!==============================================================================|
!   DUMP  DATA FILE FOR ASSIMILATION RESTART                                    |
!==============================================================================|

!   SUBROUTINE TS_SAVE_STATE
!------------------------------------------------------------------------------|
!=============================================================
!# if defined (ICE)
!   use mod_ice2d, only :sig1,sig2,sig12
!# endif


!    IMPLICIT NONE
!    INTEGER :: ERROR

!   ExtTime_BUF = ExtTime
!   IntTime_BUF = IntTime
!   IINT_BUF   = IINT

!!# if defined (ICE)
!!   DEALLOCATE(SIG1_BUF,STAT=ERROR)
!!   DEALLOCATE(SIG2_BUF,STAT=ERROR)
!!   DEALLOCATE(SIG12_BUF,STAT=ERROR)
!!   ALLOCATE(SIG1_BUF(0:MT))
!!   ALLOCATE(SIG2_BUF(0:MT))
!!   ALLOCATE(SIG12_BUF(0:MT))
!!   SIG1_BUF=SIG1
!!   SIG2_BUF=SIG2
!!   SIG12_BUF=SIG12
!!# endif

!    !NULLIFY(NC_RST_ASSIM)

!    IF(DBG_SET(DBG_SBR)) WRITE(IPT,*) "START TS_SAVE_STATE"

!!    IF(DBG_SET(DBG_LOG)) WRITE(IPT,*) "SETUP ASSIMULTION RSTFILE"
!!      CALL SETUP_RSTFILE_ASSIM

!    IF(DBG_SET(DBG_LOG)) WRITE(IPT,*) "DUMPING ASSIMULTION RSTFILE"

!      CALL DUMP_DATA_ASSIM(NC_RST_ASSIM)

!    IF(DBG_SET(DBG_SBR)) WRITE(IPT,*) "END TS_SAVE_STATE"

!   END SUBROUTINE TS_SAVE_STATE
!------------------------------------------------------------------------------|

!    SUBROUTINE TS_RESTORE_STATE
!    use MOD_SET_TIME
!    use MOD_STARTUP
!#  if defined (ICE)
!    use mod_ice2d,only : sig1,sig2,sig12
!#  endif
!    USE CONTROL
!    IMPLICIT NONE
!    TYPE(NCFILE), POINTER :: NCF
!    integer :: ncfileind, datfileind,ios,charnum, i
!    logical :: fexist,back,connected
!    character(len=100) :: testchar
!    character(len=160) :: pathnfile
!    character(len=2) :: cios
!    ! CHECK FOR INPUT AND OUTPUT DIRECTORIES
!!  OPEN THE RESTARTE  FILE
!    back = .true.

!    IINT   = IINT_BUF
!    ExtTime=ExtTime_BUF
!    IntTime=IntTime_BUF

!!# if defined (ICE)
!!    SIG1=SIG1_BUF
!!    SIG2=SIG2_BUF
!!    SIG12=SIG12_BUF
!!    deallocate(sig1_buf,sig2_buf,sig12_buf)
!!# endif

!    ! INITIALIZE TYPE TO HOLD FILE METADATA
!    !pathnfile= trim(OUTPUT_DIR)//'TS_assim_state.nc'
!    !pathnfile= trim(INPUT_DIR)//'TS_assim_state.nc'

!    !   IF(.NOT. ASSOCIATED(NC_START)) CALL FATAL_ERROR&
!    !        & ('STARUP FILE IS NOT ASSOCIATED IN SETUP_TIME!')

!    Nullify(NCF)
!    NULLIFY(NC_START)

!    NCF  => NEW_FILE()
!    NCF%FNAME=NC_RST_ASSIM%FNAME !trim(pathnfile)

!    Call NC_OPEN(NCF)
!    CALL NC_LOAD(NCF)
!    NC_START => NCF

!    NCF%FTIME%PREV_STKCNT=1
!    CALL  SET_LAST_FILE_TIME(NC_START,IntTime, IINT)

!!=============================================================
!!  restore the date for the temp restart file
!! =================================================
!#    if defined (DATA_ASSIM)
!     CALL STARTUP_ASSIM
!#    endif

!    RETURN

!    END SUBROUTINE TS_RESTORE_STATE

!------------------------------------------------------------------------------|
!=============================================================
    SUBROUTINE SETUP_RSTFILE_ASSIM
    USE MOD_NCDIO
    IMPLICIT NONE
    TYPE(NCFILE), POINTER :: NCF1, NCF2

    character(len=4) :: cyear

    TYPE(GRID), SAVE :: MYGRID

    NULLIFY(NCF1)

    IF(DBG_SET(DBG_LOG)) WRITE(IPT,*) "START SETUP_ASSIMULTION RSTFILE"

    CALL SET_FVCOM_GRID(MYGRID)

    CALL DEFINE_DIMENSIONS(MYGRID)

    ! ALLOCATE THE NEW FILE OBJECT
    NC_RST_ASSIM => NEW_FILE()

    NC_RST_ASSIM%FTIME => new_ftime()

    !NC_RST_ASSIM%FNAME=trim(OUTPUT_DIR)//'TS_assim_state.nc'
    write(cyear,'(I4.4)')PYear
    NC_RST_ASSIM%FNAME=trim(OUTPUT_DIR)//'TS_assim_state_'//cyear//'.nc'

    IF(DBG_SET(DBG_LOG)) WRITE(IPT,*) "START_ASSIMULTION RSTFILE",trim(OUTPUT_DIR)//'TS_assim_state_'//cyear//'.nc'

    NCF2 => GRID_FILE_OBJECT(MYGRID)
    NC_RST_ASSIM => ADD(NC_RST_ASSIM,NCF2)
!!$    NC_RST_ASSIM => ADD(NC_RST_ASSIM,GRID_FILE_OBJECT(MYGRID) )

    NCF2 => TIME_FILE_OBJECT()
    NC_RST_ASSIM => ADD(NC_RST_ASSIM,NCF2)
!!$    NC_RST_ASSIM => ADD(NC_RST_ASSIM,TIME_FILE_OBJECT() )

    NCF2 => ZETA_FILE_OBJECT()
    NC_RST_ASSIM => ADD(NC_RST_ASSIM,NCF2)
!!$    NC_RST_ASSIM => ADD(NC_RST_ASSIM,ZETA_FILE_OBJECT() )

    NCF2 => FILE_DATE_OBJECT()
    NC_RST_ASSIM => ADD(NC_RST_ASSIM,NCF2)
!!$    NC_RST_ASSIM => ADD(NC_RST_ASSIM,FILE_DATE_OBJECT() )

    NCF2 => VELOCITY_FILE_OBJECT()
    NC_RST_ASSIM => ADD(NC_RST_ASSIM,NCF2)
!!$    NC_RST_ASSIM => ADD(NC_RST_ASSIM,VELOCITY_FILE_OBJECT() )

    NCF2 => AVERAGE_VEL_FILE_OBJECT()
    NC_RST_ASSIM => ADD(NC_RST_ASSIM,NCF2)
!!$    NC_RST_ASSIM => ADD(NC_RST_ASSIM,AVERAGE_VEL_FILE_OBJECT() )

    NCF2 => VERTICAL_VEL_FILE_OBJECT()
    NC_RST_ASSIM => ADD(NC_RST_ASSIM,NCF2)
!!$    NC_RST_ASSIM => ADD(NC_RST_ASSIM,VERTICAL_VEL_FILE_OBJECT() )

    NCF2 => TURBULENCE_FILE_OBJECT()
    NC_RST_ASSIM => ADD(NC_RST_ASSIM,NCF2)
!!$    NC_RST_ASSIM => ADD(NC_RST_ASSIM,TURBULENCE_FILE_OBJECT() )

    NCF2 => SALT_TEMP_FILE_OBJECT()
    NC_RST_ASSIM => ADD(NC_RST_ASSIM,NCF2)
!!$    NC_RST_ASSIM => ADD(NC_RST_ASSIM,SALT_TEMP_FILE_OBJECT() )

    NCF2 => RESTART_EXTRAS_FILE_OBJECT()
    NC_RST_ASSIM => ADD(NC_RST_ASSIM,NCF2)
!!$    NC_RST_ASSIM => ADD(NC_RST_ASSIM,RESTART_EXTRAS_FILE_OBJECT() )

    NCF2 => DENSITY_FILE_OBJECT()
    NC_RST_ASSIM => ADD(NC_RST_ASSIM,NCF2)
!!$    NC_RST_ASSIM => ADD(NC_RST_ASSIM,DENSITY_FILE_OBJECT() )

    IF(WETTING_DRYING_ON) THEN
       NCF2 => WET_DRY_FILE_OBJECT()
       NC_RST_ASSIM => ADD(NC_RST_ASSIM, NCF2)
!!$       NC_RST_ASSIM => ADD(NC_RST_ASSIM, WET_DRY_FILE_OBJECT() )
    END IF

#   if defined (BioGen)
    NCF2 => BIO_FILE_OBJECT()
    NC_RST_ASSIM => ADD(NC_RST_ASSIM,NCF2)
!!$    NC_RST_ASSIM => ADD(NC_RST_ASSIM,BIO_FILE_OBJECT() )
#   endif

#   if defined (WATER_QUALITY)
    NCF2 => WQM_FILE_OBJECT()
    NC_RST_ASSIM => ADD(NC_RST_ASSIM,NCF2)
!!$    NC_RST_ASSIM => ADD(NC_RST_ASSIM,WQM_FILE_OBJECT() )
#   endif
#   if defined (SEDIMENT)
    IF(SEDIMENT_MODEL)THEN
      NCF2 => SED_FILE_OBJECT()
      NC_RST_ASSIM => ADD(NC_RST_ASSIM,NCF2)
!!$      NC_RST_ASSIM => ADD(NC_RST_ASSIM,SED_FILE_OBJECT() )
    ENDIF
#   endif

#   if defined (NH)
    NCF2 => NH_RST_FILE_OBJECT()
    NC_RST_ASSIM => ADD(NC_RST_ASSIM,NCF2)
!!$    NC_RST_ASSIM => ADD(NC_RST_ASSIM,NH_RST_FILE_OBJECT() )
#   endif

# if defined (ICE)
      !-----------------------------------------------------------------
      ! state variables
    NCF2 => ICE_RESTART_STATE_FILE_OBJECT()
    NC_RST_ASSIM => ADD(NC_RST_ASSIM,NCF2)
!!$    NC_RST_ASSIM => ADD(NC_RST_ASSIM,ICE_RESTART_STATE_FILE_OBJECT() )
      !-----------------------------------------------------------------
      ! velocity
      !-----------------------------------------------------------------
    NCF2 => ICE_VEL_FILE_OBJECT()
    NC_RST_ASSIM => ADD(NC_RST_ASSIM,NCF2)
!!$    NC_RST_ASSIM => ADD(NC_RST_ASSIM,ICE_VEL_FILE_OBJECT() )
      !-----------------------------------------------------------------
      ! fresh water, salt, and heat flux
      !-----------------------------------------------------------------
    NCF2 => ICE_EXTRA_FILE_OBJECT()
    NC_RST_ASSIM => ADD(NC_RST_ASSIM,NCF2)
!!$    NC_RST_ASSIM => ADD(NC_RST_ASSIM,ICE_EXTRA_FILE_OBJECT() )
# endif

       CALL NC_WRITE_FILE(NC_RST_ASSIM)
       NC_RST_ASSIM%FTIME%NEXT_STKCNT = 1 !NC_RST_ASSIM%FTIME%NEXT_STKCNT+1

     NC_RST_ASSIM%CONNECTED = .TRUE.

    CALL KILL_DIMENSIONS

    IF(DBG_SET(DBG_SBR)) WRITE(IPT,*) "END ASSIMULATION RSTFILE SETUP"


    END SUBROUTINE SETUP_RSTFILE_ASSIM

!------------------------------------------------------------------------------|
!=============================================================
    SUBROUTINE DUMP_DATA_ASSIM(NCF)
    USE MOD_NCDIO
    IMPLICIT NONE
    TYPE(NCFILE), POINTER ::NCF
    TYPE(NCFTIME), POINTER :: FTM

    IF(DBG_SET(DBG_SBR)) WRITE(IPT,*) "START DUMP_DATA_ASSIM"


    FTM => NCF%FTIME


    ! IF UPDATE IODATA BECOMES SPECIFIC TO DIFFERENT DATA SETS IT
    ! WILL HAVE TO BE MOVED INSIDE OF THE PARTICULAR OUTPUT STATEMENTS

    IF (FTM%MAX_STKCNT .NE. 0 .AND. &
         & Pmonth==1) THEN   !!! new year first month
         !& FTM%NEXT_STKCNT > FTM%MAX_STKCNT) THEN

       FTM%NEXT_STKCNT=0
       CALL INCRIMENT_FNAME(NCF%FNAME)
       NCF%CONNECTED=.FALSE.


       ! WRITE NEW FILE'S CONSTANT DATA (GRID ETC)
       CALL NC_WRITE_FILE(NCF)

       ! INCRIMENT THE STACK COUNT
       FTM%NEXT_STKCNT = 1

    END IF


    ! IF UPDATE IODATA BECOMES SPECIFIC TO DIFFERENT DATA SETS IT
    ! WILL HAVE TO BE MOVED INSIDE OF THE PARTICULAR OUTPUT STATEMENTS
    CALL UPDATE_IODATA(NCF,IntTime)

    CALL NC_WRITE_FILE(NCF)

    ! ONCE THE FILE IS WRITEN INCRIMENT THE FILE OBJECT TIME
    FTM%PREV_IO = IntTime
    FTM%NEXT_IO = FTM%NEXT_IO + FTM%INTERVAL

    ! INCRIMENT THE STACK COUNT
    FTM%PREV_STKCNT = FTM%NEXT_STKCNT
    FTM%NEXT_STKCNT = FTM%NEXT_STKCNT + 1

    IF(DBG_SET(DBG_SBR)) WRITE(IPT,*) "END DUMP_DATA"


    END SUBROUTINE DUMP_DATA_ASSIM
!============================================================= 

!!=============================================================================
!!-----------------------------------------------------------------------------
!!  Setup the netcdf file for output

!    SUBROUTINE MAKE_TSAVG_SAVE
!    USE MOD_NCDIO
!    !USE MOD_FORCE, only : fvcom_cap_grid_source
!    IMPLICIT NONE
!    TYPE(GRID), SAVE :: MYGRID

!    TYPE(NCFILE), POINTER :: NCF
!    TYPE(NCVAR),  POINTER :: VAR
!    TYPE(NCATT),  POINTER :: ATT
!    LOGICAL :: FOUND

!    Call SET_FVCOM_GRID(MYGRID)

!    CALL DEFINE_DIMENSIONS(MYGRID)

!    ! ALLOCATE THE NEW FILE OBJECT
!    NCF => NEW_FILE()


!    NCF%FTIME => new_ftime()

!    !NCF%FNAME = trim(INPUT_DIR)//'TS_save_state.nc'
!    NCF%FNAME = trim(OUTPUT_DIR)//'TS_save_state.nc'

!    NCF => ADD(NCF,GRID_FILE_OBJECT(MYGRID) )

!    NCF => ADD(NCF,TIME_FILE_OBJECT() )

!    NCF => ADD(NCF,ZETA_FILE_OBJECT() )

!    ATT => FIND_ATT(NCF,'source',FOUND)
!    IF(.NOT.FOUND) CALL FATAL_ERROR("LOOKING FOR 'source' ATTRIBUTE: NOT FOUND")

!!    ATT%CHR = fvcom_cap_grid_source

!!    NCF => ADD(NCF,FILE_DATE_OBJECT() )

    ! T_save

!    VAR  => NC_MAKE_AVAR(name='temp_save',&
!    !VAR  => NC_MAKE_AVAR(name='temp',&
!         & values= TC_AVG, DIM1= DIM_node, DIM2= DIM_siglay, DIM3 = DIM_time)

!    ATT  => NC_MAKE_ATT(name='long_name',values='temperature')
!    VAR  => ADD(VAR,ATT)

!    ATT  => NC_MAKE_ATT(name='standard_name',values='sea_water_temperature')
!    VAR  => ADD(VAR,ATT)

!    ATT  => NC_MAKE_ATT(name='units',values='degrees_C')
!    VAR  => ADD(VAR,ATT)

!    ATT  => NC_MAKE_ATT(name='grid',values='fvcom_grid')
!    VAR  => ADD(VAR,ATT)

!    ATT  => NC_MAKE_ATT(name='coordinates',values=CoordVar)
!    VAR  => ADD(VAR,ATT)

!    ATT  => NC_MAKE_ATT(name='type',values='data')

!    VAR  => ADD(VAR,ATT)

!    NCF  => ADD(NCF,VAR)
    ! S_save
!    VAR  => NC_MAKE_AVAR(name='salinity_save',&
!    !VAR  => NC_MAKE_AVAR(name='salinity',&
!         & values= SC_AVG, DIM1= DIM_node, DIM2= DIM_siglay, DIM3 = DIM_time)

!    ATT  => NC_MAKE_ATT(name='long_name',values='salinity')
!    VAR  => ADD(VAR,ATT)

!    ATT  => NC_MAKE_ATT(name='standard_name',values='sea_water_salinity')
!    VAR  => ADD(VAR,ATT)

!    ATT  => NC_MAKE_ATT(name='units',values='1e-3')
!    VAR  => ADD(VAR,ATT)

!    ATT  => NC_MAKE_ATT(name='grid',values='fvcom_grid')
!    VAR  => ADD(VAR,ATT)

!    ATT  => NC_MAKE_ATT(name='coordinates',values=CoordVar)
!    VAR  => ADD(VAR,ATT)

!    ATT  => NC_MAKE_ATT(name='type',values='data')
!    VAR  => ADD(VAR,ATT)
!    NCF  => ADD(NCF,VAR)

!    CALL NC_WRITE_FILE(NCF)
!    NCF%FTIME%NEXT_STKCNT = 1

!    NCF%FTIME%NEXT_STKCNT = 1

!    CALL UPDATE_IODATA(NCF,IntTime)

!    CALL NC_WRITE_FILE(NCF)

!    END SUBROUTINE MAKE_TSAVG_SAVE

!!=============================================================
!!=============================================================


    SUBROUTINE SET_MONTHLY_TS_MEAN(NCF) 
    USE MOD_NCDIO
    !USE MOD_FORCE, only : fvcom_cap_grid_source
    IMPLICIT NONE
    TYPE(GRID), SAVE :: MYGRID

    TYPE(NCFILE), POINTER :: NCF
    TYPE(NCFILE), POINTER :: NCF1
    TYPE(NCFILE), POINTER :: NCF2
    TYPE(NCVAR),  POINTER :: VAR
    TYPE(NCATT),  POINTER :: ATT
    LOGICAL :: FOUND

    NULLIFY(NCF)
    NULLIFY(NCF1)

    Call SET_FVCOM_GRID(MYGRID)    

    CALL DEFINE_DIMENSIONS(MYGRID)

    ! ALLOCATE THE NEW FILE OBJECT
    NCF => NEW_FILE()


    NCF%FTIME => new_ftime()

    NCF%FNAME = trim(OUTPUT_DIR)//'TSAVG_assim_save.nc'

    NCF2 => GRID_FILE_OBJECT(MYGRID)
    NCF => ADD(NCF,NCF2)
!!$    NCF => ADD(NCF,GRID_FILE_OBJECT(MYGRID) )

    NCF2 => TIME_FILE_OBJECT()
    NCF => ADD(NCF,NCF2)
!!$    NCF => ADD(NCF,TIME_FILE_OBJECT() )
    
    NCF2 => ZETA_FILE_OBJECT()
    NCF => ADD(NCF,NCF2)
!!$    NCF => ADD(NCF,ZETA_FILE_OBJECT() )

    ATT => FIND_ATT(NCF,'source',FOUND)
    IF(.NOT.FOUND) CALL FATAL_ERROR("LOOKING FOR 'source' ATTRIBUTE: NOT FOUND")
    
!    ATT%CHR = fvcom_cap_grid_source

!    NCF => ADD(NCF,FILE_DATE_OBJECT() )

    ! T_save
       
    VAR  => NC_MAKE_AVAR(name='temp_save',&
    !VAR  => NC_MAKE_AVAR(name='temp',&
         & values= TC0_AVG, DIM1= DIM_node, DIM2= DIM_siglay, DIM3 = DIM_time)

    ATT  => NC_MAKE_ATT(name='long_name',values='temperature')
    VAR  => ADD(VAR,ATT)
    
    ATT  => NC_MAKE_ATT(name='standard_name',values='sea_water_temperature')
    VAR  => ADD(VAR,ATT)

    ATT  => NC_MAKE_ATT(name='units',values='degrees_C')
    VAR  => ADD(VAR,ATT)

    ATT  => NC_MAKE_ATT(name='grid',values='fvcom_grid')
    VAR  => ADD(VAR,ATT)

    ATT  => NC_MAKE_ATT(name='coordinates',values=CoordVar)
    VAR  => ADD(VAR,ATT)

    ATT  => NC_MAKE_ATT(name='type',values='data')

    VAR  => ADD(VAR,ATT)

    NCF  => ADD(NCF,VAR)
    ! S_save
    VAR  => NC_MAKE_AVAR(name='salinity_save',&
    !VAR  => NC_MAKE_AVAR(name='salinity',&
         & values= SC0_AVG, DIM1= DIM_node, DIM2= DIM_siglay, DIM3 = DIM_time)

    ATT  => NC_MAKE_ATT(name='long_name',values='salinity')
    VAR  => ADD(VAR,ATT)

    ATT  => NC_MAKE_ATT(name='standard_name',values='sea_water_salinity')
    VAR  => ADD(VAR,ATT)

    ATT  => NC_MAKE_ATT(name='units',values='1e-3')
    VAR  => ADD(VAR,ATT)

    ATT  => NC_MAKE_ATT(name='grid',values='fvcom_grid')
    VAR  => ADD(VAR,ATT)

    ATT  => NC_MAKE_ATT(name='coordinates',values=CoordVar)
    VAR  => ADD(VAR,ATT)

    ATT  => NC_MAKE_ATT(name='type',values='data')
    VAR  => ADD(VAR,ATT)
    NCF  => ADD(NCF,VAR)

    NCF%FTIME%NEXT_STKCNT = 0
    CALL NC_WRITE_FILE(NCF)
 
    END SUBROUTINE SET_MONTHLY_TS_MEAN

!=============================================================  
    SUBROUTINE DUMP_TSAVG_ASSIM(NCF)
    USE MOD_NCDIO
    IMPLICIT NONE  
    TYPE(NCFILE), POINTER ::NCF
    TYPE(NCFTIME), POINTER :: FTM

    IF(DBG_SET(DBG_SBR)) WRITE(IPT,*) "START DUMP_TSAVG_ASSIM"

    FTM => NCF%FTIME
    FTM%NEXT_STKCNT = FTM%NEXT_STKCNT + 1

    ! IF UPDATE IODATA BECOMES SPECIFIC TO DIFFERENT DATA SETS IT
    ! WILL HAVE TO BE MOVED INSIDE OF THE PARTICULAR OUTPUT STATEMENTS
    CALL UPDATE_IODATA(NCF,IntTime)
    CALL NC_WRITE_FILE(NCF)

    ! ONCE THE FILE IS WRITEN INCRIMENT THE FILE OBJECT TIME
    
    IF(DBG_SET(DBG_SBR)) WRITE(IPT,*) "END DUMP_TSAVG_ASSIM"
    
    END SUBROUTINE DUMP_TSAVG_ASSIM
!=============================================================
!==============================================================================|
   LOGICAL FUNCTION ISINTRIANGLE1(XT,YT,X0,Y0) 
!==============================================================================|
!  determine if point (x0,y0) is in triangle defined by nodes (xt(3),yt(3))    |
!  using algorithm used for scene rendering in computer graphics               |
!  algorithm works well unless particle happens to lie in a line parallel      |
!  to the edge of a triangle.                                                  |
!  This can cause problems if you use a regular grid, say for idealized        |
!  modelling and you happen to see particles right on edges or parallel to     |
!  edges.                                                                      |
!==============================================================================|

   USE MOD_PREC
   IMPLICIT NONE
   REAL(SP), INTENT(IN) :: X0,Y0
   REAL(SP), INTENT(IN) :: XT(3),YT(3)
   REAL(SP) :: F1,F2,F3
   REAL(SP) :: X1(2)
   REAL(SP) :: X2(2)
   REAL(SP) :: X3(2)
   REAL(SP) :: P(2)

!------------------------------------------------------------------------------|
   IF (DBG_SET(DBG_SBR)) WRITE(IPT,*) "START: ISINTRIANGLE1" 

   ISINTRIANGLE1 = .FALSE.  

   IF(Y0 < MINVAL(YT) .OR. Y0 > MAXVAL(YT))THEN
     ISINTRIANGLE1 = .FALSE.
     RETURN
   END IF
   IF(X0 < MINVAL(XT) .OR. X0 > MAXVAL(XT))THEN
     ISINTRIANGLE1 = .FALSE.
     RETURN
   END IF

   F1 = (Y0-YT(1))*(XT(2)-XT(1)) - (X0-XT(1))*(YT(2)-YT(1))
   F2 = (Y0-YT(3))*(XT(1)-XT(3)) - (X0-XT(3))*(YT(1)-YT(3))
   F3 = (Y0-YT(2))*(XT(3)-XT(2)) - (X0-XT(2))*(YT(3)-YT(2))
   IF(F1*F3 >= 0.0_SP .AND. F3*F2 >= 0.0_SP) ISINTRIANGLE1 = .TRUE.

   IF (DBG_SET(DBG_SBR)) WRITE(IPT,*) "END: ISINTRIANGLE1" 
   RETURN
   END FUNCTION ISINTRIANGLE1
!==============================================================================|
!
!==============================================================================|
  SUBROUTINE NAME_LIST_PRINT_ASSIM
    USE CONTROL

    IMPLICIT NONE

    write(UNIT=IPT,NML=NML_SST_ASSIMILATION)
    write(UNIT=IPT,NML=NML_SSTGRD_ASSIMILATION)
    write(UNIT=IPT,NML=NML_SSHGRD_ASSIMILATION)
    write(UNIT=IPT,NML=NML_TSGRD_ASSIMILATION)
    write(UNIT=IPT,NML=NML_CUR_NGASSIMILATION)
    write(UNIT=IPT,NML=NML_CUR_OIASSIMILATION)
    write(UNIT=IPT,NML=NML_TS_NGASSIMILATION)
    write(UNIT=IPT,NML=NML_TS_OIASSIMILATION)

  RETURN
  END SUBROUTINE NAME_LIST_PRINT_ASSIM

# endif
END MODULE MOD_ASSIM