Index: NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/cfgs/SHARED/namelist_ref
===================================================================
--- NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/cfgs/SHARED/namelist_ref	(revision 15731)
+++ NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/cfgs/SHARED/namelist_ref	(revision 15799)
@@ -1242,63 +1242,56 @@
 !!                                                                    !!
 !!   namobs       observation and model comparison                      (default: OFF)
+!!   namobs_dta   observation and model comparison - external data      (see: namobs)
 !!   nam_asminc   assimilation increments                               ('key_asminc')
 !!======================================================================
 !
 !-----------------------------------------------------------------------
-&namobs        !  observation usage switch                              (default: OFF)
-!-----------------------------------------------------------------------
-   ln_diaobs   = .false.             ! Logical switch for the observation operator
-   !
-   ln_t3d      = .false.             ! Logical switch for T profile observations
-   ln_s3d      = .false.             ! Logical switch for S profile observations
-   ln_sla      = .false.             ! Logical switch for SLA observations
-   ln_sst      = .false.             ! Logical switch for SST observations
-   ln_sss      = .false.             ! Logical swithc for SSS observations
-   ln_sic      = .false.             ! Logical switch for Sea Ice observations
-   ln_vel3d    = .false.             ! Logical switch for velocity observations
-   ln_altbias  = .false.             ! Logical switch for altimeter bias correction
-   ln_sstbias  = .false.             ! Logical switch for SST bias correction
-   ln_nea      = .false.             ! Logical switch for rejection of observations near land
-   ln_grid_global = .true.           ! Logical switch for global distribution of observations
-   ln_grid_search_lookup = .false.   ! Logical switch for obs grid search w/lookup table
-   ln_ignmis   = .true.              ! Logical switch for ignoring missing files
-   ln_s_at_t   = .false.             ! Logical switch for computing model S at T obs if not there
-   ln_sstnight = .false.             ! Logical switch for calculating night-time average for SST obs
-   ln_bound_reject  = .false.        ! Logical to remove obs near boundaries in LAMs.
-   ln_sla_fp_indegs = .true.         ! Logical for SLA: T=> averaging footprint is in degrees, F=> in metres
-   ln_sst_fp_indegs = .true.         ! Logical for SST: T=> averaging footprint is in degrees, F=> in metres
-   ln_sss_fp_indegs = .true.         ! Logical for SSS: T=> averaging footprint is in degrees, F=> in metres
-   ln_sic_fp_indegs = .true.         ! Logical for SIC: T=> averaging footprint is in degrees, F=> in metres
-! All of the *files* variables below are arrays. Use namelist_cfg to add more files
-   cn_profbfiles = 'profiles_01.nc'  ! Profile feedback input observation file names
-   cn_slafbfiles = 'sla_01.nc'       ! SLA feedback input observation file names
-   cn_sstfbfiles = 'sst_01.nc'       ! SST feedback input observation file names
-   cn_sssfbfiles = 'sss_01.nc'       ! SSS feedback input observation file names
-   cn_sicfbfiles = 'sic_01.nc'       ! SIC feedback input observation file names
-   cn_velfbfiles = 'vel_01.nc'       ! Velocity feedback input observation file names
-   cn_altbiasfile = 'altbias.nc'     ! Altimeter bias input file name
-   cn_sstbiasfiles = 'sstbias.nc'    ! SST bias input file name
-   cn_gridsearchfile ='gridsearch.nc' ! Grid search file name
-   rn_gridsearchres = 0.5            ! Grid search resolution
-   rn_mdtcorr  = 1.61                ! MDT  correction
-   rn_mdtcutoff = 65.0               ! MDT cutoff for computed correction
-   rn_dobsini  = 00010101.000000     ! Initial date in window YYYYMMDD.HHMMSS
-   rn_dobsend  = 00010102.000000     ! Final date in window YYYYMMDD.HHMMSS
-   rn_sla_avglamscl = 0.             ! E/W diameter of SLA observation footprint (metres/degrees)
-   rn_sla_avgphiscl = 0.             ! N/S diameter of SLA observation footprint (metres/degrees)
-   rn_sst_avglamscl = 0.             ! E/W diameter of SST observation footprint (metres/degrees)
-   rn_sst_avgphiscl = 0.             ! N/S diameter of SST observation footprint (metres/degrees)
-   rn_sss_avglamscl = 0.             ! E/W diameter of SSS observation footprint (metres/degrees)
-   rn_sss_avgphiscl = 0.             ! N/S diameter of SSS observation footprint (metres/degrees)
-   rn_sic_avglamscl = 0.             ! E/W diameter of SIC observation footprint (metres/degrees)
-   rn_sic_avgphiscl = 0.             ! N/S diameter of SIC observation footprint (metres/degrees)
-   nn_1dint = 0                      ! Type of vertical interpolation method
-   nn_2dint = 0                      ! Default horizontal interpolation method
-   nn_2dint_sla = 0                  ! Horizontal interpolation method for SLA
-   nn_2dint_sst = 0                  ! Horizontal interpolation method for SST
-   nn_2dint_sss = 0                  ! Horizontal interpolation method for SSS
-   nn_2dint_sic = 0                  ! Horizontal interpolation method for SIC
-   nn_msshc     = 0                  ! MSSH correction scheme
-   nn_profdavtypes = -1              ! Profile daily average types - array
+&namobs       !  observation and model comparison                       (default: OFF)
+!-----------------------------------------------------------------------
+   ln_diaobs             = .false.         ! Logical switch for the observation operator
+   nn_obsgroups          = 0               ! Number of observation group namelists (namobs_dta) to read in
+   ln_grid_global        = .true.          ! Logical switch for global distribution of observations
+   ln_grid_search_lookup = .false.         ! Logical switch for obs grid search w/lookup table
+   cn_gridsearchfile     = 'grid_search'   ! Grid search file name header
+   rn_gridsearchres      = 0.5             ! Grid search resolution
+   rn_dobsini            = 00010101.000000 ! Initial date in window YYYYMMDD.HHMMSS
+   rn_dobsend            = 00010102.000000 ! Final date in window YYYYMMDD.HHMMSS
+/
+!-----------------------------------------------------------------------
+&namobs_dta    !  observation and model comparison - external data      (see: namobs)
+!-----------------------------------------------------------------------
+   cn_groupname           = ''             ! Name of obs group (output file will be cn_groupname//'fb_????.nc')
+   ln_enabled             = .true.         ! Logical switch for group being processed not ignored
+   ln_prof                = .false.        ! Logical switch for profile data
+   ln_surf                = .false.        ! Logical switch for surface data
+   cn_obsfiles            = ''             ! Observation file names
+   cn_obstypes            = ''             ! Observation types to read from files
+   ln_nea                 = .false.        ! Logical switch for rejecting observations near land
+   ln_bound_reject        = .false.        ! Logical switch for rejecting obs near the boundary
+   ln_ignmis              = .true.         ! Logical switch for ignoring missing files
+   nn_2dint               = 0              ! Type of horizontal interpolation method
+                                           ! Relevant if ln_prof = .true.:
+   nn_1dint               = 0              !    Type of vertical interpolation method
+   nn_profdavtypes        = -1             !    Profile data types representing a daily average
+   ln_all_at_all          = .false.        !    Logical switch for computing all model variables at all obs points
+                                           ! Relevant if ln_surf = .true.:
+   ln_fp_indegs           = .true.         !    Logical: T=> averaging footprint is in degrees, F=> in metres
+   rn_avglamscl           = 0.             !    E/W diameter of observation footprint (metres/degrees)
+   rn_avgphiscl           = 0.             !    N/S diameter of observation footprint (metres/degrees)
+   ln_night               = .false.        !    Logical switch for calculating night-time average for obs
+   ln_time_mean_bkg       = .false.        !    Logical switch for applying time mean of background (e.g. to remove tidal signal)
+   rn_time_mean_period    = 24.8333        !    Meaning period in hours if ln_time_mean_bkg (default is AMM tidal period)
+   ln_obsbias             = .false.        !    Logical switch for bias correction
+   cn_obsbiasfiles        = ''             !    Bias input file names
+   cn_type_to_biascorrect = ''             !    Observation type to bias correct
+   cn_obsbiasfile_varname = ''             !    Bias variable name in input file
+                                           ! Relevant if 'SLA' in cn_obstypes:
+   ln_altbias             = .false.        !    Logical switch for altimeter bias correction
+   cn_altbiasfile         = ''             !    Altimeter bias input file name
+   nn_msshc               = 0              !    MSSH correction scheme
+   rn_mdtcorr             = 1.61           !    MDT correction
+   rn_mdtcutoff           = 65.0           !    MDT cutoff for computed correction
+                                           ! Relevant if 'POTM', 'PSAL', 'SST', or 'SSS' in cn_obstypes:
+   ln_output_clim         = .false.        !    Logical switch to output climatological temperature/salinity (if ln_tradmp)
 /
 !-----------------------------------------------------------------------
Index: NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/doc/namelists/namobs
===================================================================
--- NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/doc/namelists/namobs	(revision 15731)
+++ NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/doc/namelists/namobs	(revision 15799)
@@ -20,4 +20,5 @@
    ln_sstnight = .false.             ! Logical switch for calculating night-time average for SST obs
    ln_bound_reject  = .false.        ! Logical to remove obs near boundaries in LAMs.
+   ln_default_fp_indegs = .true.     ! Logical: T=> averaging footprint is in degrees, F=> in metres
    ln_sla_fp_indegs = .true.         ! Logical for SLA: T=> averaging footprint is in degrees, F=> in metres
    ln_sst_fp_indegs = .true.         ! Logical for SST: T=> averaging footprint is in degrees, F=> in metres
@@ -39,4 +40,6 @@
    rn_dobsini  = 00010101.000000     ! Initial date in window YYYYMMDD.HHMMSS
    rn_dobsend  = 00010102.000000     ! Final date in window YYYYMMDD.HHMMSS
+   rn_default_avglamscl = 0.         ! Default E/W diameter of observation footprint (metres/degrees)
+   rn_default_avgphiscl = 0.         ! Default N/S diameter of observation footprint (metres/degrees)
    rn_sla_avglamscl = 0.             ! E/W diameter of SLA observation footprint (metres/degrees)
    rn_sla_avgphiscl = 0.             ! N/S diameter of SLA observation footprint (metres/degrees)
@@ -48,5 +51,5 @@
    rn_sic_avgphiscl = 0.             ! N/S diameter of SIC observation footprint (metres/degrees)
    nn_1dint = 0                      ! Type of vertical interpolation method
-   nn_2dint = 0                      ! Default horizontal interpolation method
+   nn_2dint_default = 0              ! Default horizontal interpolation method
    nn_2dint_sla = 0                  ! Horizontal interpolation method for SLA
    nn_2dint_sst = 0                  ! Horizontal interpolation method for SST
Index: NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/diaobs.F90
===================================================================
--- NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/diaobs.F90	(revision 15731)
+++ NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/diaobs.F90	(revision 15799)
@@ -26,25 +26,28 @@
    !!   fin_date      : Compute the final date YYYYMMDD.HHMMSS
    !!----------------------------------------------------------------------
-   USE par_kind       ! Precision variables
-   USE in_out_manager ! I/O manager
-   USE par_oce        ! ocean parameter
-   USE dom_oce        ! Ocean space and time domain variables
-   USE sbc_oce        ! Sea-ice fraction
+   USE par_kind          ! Precision variables
+   USE in_out_manager    ! I/O manager
+   USE timing            ! Timing
+   USE par_oce           ! ocean parameter
+   USE dom_oce           ! Ocean space and time domain variables
+   USE sbc_oce           ! Sea-ice fraction
    !
-   USE obs_read_prof  ! Reading and allocation of profile obs
-   USE obs_read_surf  ! Reading and allocation of surface obs
-   USE obs_sstbias    ! Bias correction routine for SST 
-   USE obs_readmdt    ! Reading and allocation of MDT for SLA.
-   USE obs_prep       ! Preparation of obs. (grid search etc).
-   USE obs_oper       ! Observation operators
-   USE obs_write      ! Writing of observation related diagnostics
-   USE obs_grid       ! Grid searching
-   USE obs_read_altbias ! Bias treatment for altimeter
-   USE obs_profiles_def ! Profile data definitions
-   USE obs_surf_def   ! Surface data definitions
-   USE obs_types      ! Definitions for observation types
+   USE obs_read_prof     ! Reading and allocation of profile obs
+   USE obs_read_surf     ! Reading and allocation of surface obs
+   USE obs_bias          ! Bias correction routine
+   USE obs_readmdt       ! Reading and allocation of MDT for SLA.
+   USE obs_readsnowdepth ! Get model snow depth for conversion of freeboard to ice thickness
+   USE obs_prep          ! Preparation of obs. (grid search etc).
+   USE obs_oper          ! Observation operators
+   USE obs_write         ! Writing of observation related diagnostics
+   USE obs_grid          ! Grid searching
+   USE obs_read_altbias  ! Bias treatment for altimeter
+   USE obs_profiles_def  ! Profile data definitions
+   USE obs_surf_def      ! Surface data definitions
+   USE obs_types         ! Definitions for observation types
+   USE obs_group_def     ! Definitions for observation groups
    !
-   USE mpp_map        ! MPP mapping
-   USE lib_mpp        ! For ctl_warn/stop
+   USE mpp_map           ! MPP mapping
+   USE lib_mpp           ! For ctl_warn/stop
 
    IMPLICIT NONE
@@ -54,45 +57,11 @@
    PUBLIC dia_obs          ! Compute model equivalent to observations
    PUBLIC dia_obs_wri      ! Write model equivalent to observations
-   PUBLIC dia_obs_dealloc  ! Deallocate dia_obs data
    PUBLIC calc_date        ! Compute the date of a timestep
 
-   LOGICAL, PUBLIC :: ln_diaobs          !: Logical switch for the obs operator
-   LOGICAL         :: ln_sstnight        !  Logical switch for night mean SST obs
-   LOGICAL         :: ln_sla_fp_indegs   !  T=> SLA obs footprint size specified in degrees, F=> in metres
-   LOGICAL         :: ln_sst_fp_indegs   !  T=> SST obs footprint size specified in degrees, F=> in metres
-   LOGICAL         :: ln_sss_fp_indegs   !  T=> SSS obs footprint size specified in degrees, F=> in metres
-   LOGICAL         :: ln_sic_fp_indegs   !  T=> sea-ice obs footprint size specified in degrees, F=> in metres
-
-   REAL(wp) ::   rn_sla_avglamscl   ! E/W diameter of SLA observation footprint (metres)
-   REAL(wp) ::   rn_sla_avgphiscl   ! N/S diameter of SLA observation footprint (metres)
-   REAL(wp) ::   rn_sst_avglamscl   ! E/W diameter of SST observation footprint (metres)
-   REAL(wp) ::   rn_sst_avgphiscl   ! N/S diameter of SST observation footprint (metres)
-   REAL(wp) ::   rn_sss_avglamscl   ! E/W diameter of SSS observation footprint (metres)
-   REAL(wp) ::   rn_sss_avgphiscl   ! N/S diameter of SSS observation footprint (metres)
-   REAL(wp) ::   rn_sic_avglamscl   ! E/W diameter of sea-ice observation footprint (metres)
-   REAL(wp) ::   rn_sic_avgphiscl   ! N/S diameter of sea-ice observation footprint (metres)
-
-   INTEGER :: nn_1dint       ! Vertical interpolation method
-   INTEGER :: nn_2dint       ! Default horizontal interpolation method
-   INTEGER :: nn_2dint_sla   ! SLA horizontal interpolation method 
-   INTEGER :: nn_2dint_sst   ! SST horizontal interpolation method 
-   INTEGER :: nn_2dint_sss   ! SSS horizontal interpolation method 
-   INTEGER :: nn_2dint_sic   ! Seaice horizontal interpolation method 
-   INTEGER, DIMENSION(imaxavtypes) ::   nn_profdavtypes   ! Profile data types representing a daily average
-   INTEGER :: nproftypes     ! Number of profile obs types
-   INTEGER :: nsurftypes     ! Number of surface obs types
-   INTEGER , DIMENSION(:), ALLOCATABLE ::   nvarsprof, nvarssurf   ! Number of profile & surface variables
-   INTEGER , DIMENSION(:), ALLOCATABLE ::   nextrprof, nextrsurf   ! Number of profile & surface extra variables
-   INTEGER , DIMENSION(:), ALLOCATABLE ::   n2dintsurf             ! Interpolation option for surface variables
-   REAL(wp), DIMENSION(:), ALLOCATABLE ::   zavglamscl, zavgphiscl ! E/W & N/S diameter of averaging footprint for surface variables
-   LOGICAL , DIMENSION(:), ALLOCATABLE ::   lfpindegs              ! T=> surface obs footprint size specified in degrees, F=> in metres
-   LOGICAL , DIMENSION(:), ALLOCATABLE ::   llnightav              ! Logical for calculating night-time averages
-
-   TYPE(obs_surf), PUBLIC, POINTER, DIMENSION(:) ::   surfdata     !: Initial surface data
-   TYPE(obs_surf), PUBLIC, POINTER, DIMENSION(:) ::   surfdataqc   !: Surface data after quality control
-   TYPE(obs_prof), PUBLIC, POINTER, DIMENSION(:) ::   profdata     !: Initial profile data
-   TYPE(obs_prof), PUBLIC, POINTER, DIMENSION(:) ::   profdataqc   !: Profile data after quality control
-
-   CHARACTER(len=6), PUBLIC, DIMENSION(:), ALLOCATABLE ::   cobstypesprof, cobstypessurf   !: Profile & surface obs types
+   LOGICAL, PUBLIC :: ln_diaobs            !: Logical switch for the obs operator
+   
+   INTEGER :: nn_obsgroups
+
+   TYPE(obs_group), DIMENSION(:), ALLOCATABLE ::   sobsgroups   ! Obs groups
 
    !!----------------------------------------------------------------------
@@ -114,72 +83,33 @@
       !!
       !!----------------------------------------------------------------------
-      INTEGER, PARAMETER ::   jpmaxnfiles = 1000    ! Maximum number of files for each obs type
-      INTEGER, DIMENSION(:), ALLOCATABLE ::   ifilesprof, ifilessurf   ! Number of profile & surface files
+#if defined key_si3
+      USE ice, ONLY : &     ! Sea ice variables
+         & hm_s             ! Snow depth for freeboard conversion
+#elif defined key_cice
+      USE sbc_oce, ONLY : & ! Sea ice variables
+         & thick_s          ! Snow depth for freeboard conversion
+#endif
+      USE obs_fbm, ONLY : &
+         & fbrmdi           ! Real missing data indicator
+
+      IMPLICIT NONE
+
+      INTEGER, PARAMETER ::   jpmaxngroups = 1000    ! Maximum number of obs groups
       INTEGER :: ios             ! Local integer output status for namelist read
       INTEGER :: jtype           ! Counter for obs types
       INTEGER :: jvar            ! Counter for variables
       INTEGER :: jfile           ! Counter for files
-      INTEGER :: jnumsstbias
+      INTEGER :: jenabled
+      INTEGER :: jgroup
       !
-      CHARACTER(len=128), DIMENSION(jpmaxnfiles) :: &
-         & cn_profbfiles, &      ! T/S profile input filenames
-         & cn_sstfbfiles, &      ! Sea surface temperature input filenames
-         & cn_sssfbfiles, &      ! Sea surface salinity input filenames
-         & cn_slafbfiles, &      ! Sea level anomaly input filenames
-         & cn_sicfbfiles, &      ! Seaice concentration input filenames
-         & cn_velfbfiles, &      ! Velocity profile input filenames
-         & cn_sstbiasfiles      ! SST bias input filenames
-      CHARACTER(LEN=128) :: &
-         & cn_altbiasfile        ! Altimeter bias input filename
-      CHARACTER(len=128), DIMENSION(:,:), ALLOCATABLE :: &
-         & clproffiles, &        ! Profile filenames
-         & clsurffiles           ! Surface filenames
-         !
-      LOGICAL :: ln_t3d          ! Logical switch for temperature profiles
-      LOGICAL :: ln_s3d          ! Logical switch for salinity profiles
-      LOGICAL :: ln_sla          ! Logical switch for sea level anomalies 
-      LOGICAL :: ln_sst          ! Logical switch for sea surface temperature
-      LOGICAL :: ln_sss          ! Logical switch for sea surface salinity
-      LOGICAL :: ln_sic          ! Logical switch for sea ice concentration
-      LOGICAL :: ln_vel3d        ! Logical switch for velocity (u,v) obs
-      LOGICAL :: ln_nea          ! Logical switch to remove obs near land
-      LOGICAL :: ln_altbias      ! Logical switch for altimeter bias
-      LOGICAL :: ln_sstbias      ! Logical switch for bias corection of SST 
-      LOGICAL :: ln_ignmis       ! Logical switch for ignoring missing files
-      LOGICAL :: ln_s_at_t       ! Logical switch to compute model S at T obs
-      LOGICAL :: ln_bound_reject ! Logical to remove obs near boundaries in LAMs.
-      LOGICAL :: llvar1          ! Logical for profile variable 1
-      LOGICAL :: llvar2          ! Logical for profile variable 1
-      LOGICAL, DIMENSION(jpmaxnfiles) :: lmask ! Used for finding number of sstbias files
+      LOGICAL, DIMENSION(:), ALLOCATABLE :: llvar
       !
-      REAL(dp) :: rn_dobsini     ! Obs window start date YYYYMMDD.HHMMSS
-      REAL(dp) :: rn_dobsend     ! Obs window end date   YYYYMMDD.HHMMSS
-      REAL(wp), DIMENSION(jpi,jpj)     ::   zglam1, zglam2   ! Model longitudes for profile variable 1 & 2
-      REAL(wp), DIMENSION(jpi,jpj)     ::   zgphi1, zgphi2   ! Model latitudes  for profile variable 1 & 2
-      REAL(wp), DIMENSION(jpi,jpj,jpk) ::   zmask1, zmask2   ! Model land/sea mask associated with variable 1 & 2
-      !!
-      NAMELIST/namobs/ln_diaobs, ln_t3d, ln_s3d, ln_sla,              &
-         &            ln_sst, ln_sic, ln_sss, ln_vel3d,               &
-         &            ln_altbias, ln_sstbias, ln_nea,                 &
-         &            ln_grid_global, ln_grid_search_lookup,          &
-         &            ln_ignmis, ln_s_at_t, ln_bound_reject,          &
-         &            ln_sstnight,                                    &
-         &            ln_sla_fp_indegs, ln_sst_fp_indegs,             &
-         &            ln_sss_fp_indegs, ln_sic_fp_indegs,             &
-         &            cn_profbfiles, cn_slafbfiles,                   &
-         &            cn_sstfbfiles, cn_sicfbfiles,                   &
-         &            cn_velfbfiles, cn_sssfbfiles,                   &
-         &            cn_sstbiasfiles, cn_altbiasfile,                &
-         &            cn_gridsearchfile, rn_gridsearchres,            &
-         &            rn_dobsini, rn_dobsend,                         &
-         &            rn_sla_avglamscl, rn_sla_avgphiscl,             &
-         &            rn_sst_avglamscl, rn_sst_avgphiscl,             &
-         &            rn_sss_avglamscl, rn_sss_avgphiscl,             &
-         &            rn_sic_avglamscl, rn_sic_avgphiscl,             &
-         &            nn_1dint, nn_2dint,                             &
-         &            nn_2dint_sla, nn_2dint_sst,                     &
-         &            nn_2dint_sss, nn_2dint_sic,                     &
-         &            nn_msshc, rn_mdtcorr, rn_mdtcutoff,             &
-         &            nn_profdavtypes
+      REAL(dp) :: rn_dobsini      ! Obs window start date YYYYMMDD.HHMMSS
+      REAL(dp) :: rn_dobsend      ! Obs window end date   YYYYMMDD.HHMMSS
+      !!
+      NAMELIST/namobs/ln_diaobs, nn_obsgroups,               &
+         &            ln_grid_global, ln_grid_search_lookup, &
+         &            cn_gridsearchfile, rn_gridsearchres,   &
+         &            rn_dobsini, rn_dobsend
       !-----------------------------------------------------------------------
 
@@ -187,14 +117,5 @@
       ! Read namelist parameters
       !-----------------------------------------------------------------------
-      ! Some namelist arrays need initialising
-      cn_profbfiles  (:) = ''
-      cn_slafbfiles  (:) = ''
-      cn_sstfbfiles  (:) = ''
-      cn_sicfbfiles  (:) = ''
-      cn_velfbfiles  (:) = ''
-      cn_sssfbfiles  (:) = ''
-      cn_sstbiasfiles(:) = ''
-      nn_profdavtypes(:) = -1
-
+      ! Initialise time window
       CALL ini_date( rn_dobsini )
       CALL fin_date( rn_dobsend )
@@ -220,156 +141,50 @@
          WRITE(numout,*) 'dia_obs_init : Observation diagnostic initialization'
          WRITE(numout,*) '~~~~~~~~~~~~'
-         WRITE(numout,*) '   Namelist namobs : set observation diagnostic parameters' 
-         WRITE(numout,*) '      Logical switch for T profile observations                ln_t3d = ', ln_t3d
-         WRITE(numout,*) '      Logical switch for S profile observations                ln_s3d = ', ln_s3d
-         WRITE(numout,*) '      Logical switch for SLA observations                      ln_sla = ', ln_sla
-         WRITE(numout,*) '      Logical switch for SST observations                      ln_sst = ', ln_sst
-         WRITE(numout,*) '      Logical switch for Sea Ice observations                  ln_sic = ', ln_sic
-         WRITE(numout,*) '      Logical switch for velocity observations               ln_vel3d = ', ln_vel3d
-         WRITE(numout,*) '      Logical switch for SSS observations                      ln_sss = ', ln_sss
+         WRITE(numout,*) '   Namelist namobs : set observation diagnostic parameters'
+         WRITE(numout,*) '      Number of namobs_dta namelists to read             nn_obsgroups = ', nn_obsgroups
          WRITE(numout,*) '      Global distribution of observations              ln_grid_global = ', ln_grid_global
          WRITE(numout,*) '      Logical switch for obs grid search lookup ln_grid_search_lookup = ', ln_grid_search_lookup
-         IF (ln_grid_search_lookup) &
+         IF (ln_grid_search_lookup) THEN
             WRITE(numout,*) '      Grid search lookup file header                cn_gridsearchfile = ', cn_gridsearchfile
-         WRITE(numout,*) '      Initial date in window YYYYMMDD.HHMMSS               rn_dobsini = ', rn_dobsini
-         WRITE(numout,*) '      Final date in window YYYYMMDD.HHMMSS                 rn_dobsend = ', rn_dobsend
-         WRITE(numout,*) '      Type of vertical interpolation method                  nn_1dint = ', nn_1dint
-         WRITE(numout,*) '      Type of horizontal interpolation method                nn_2dint = ', nn_2dint
-         WRITE(numout,*) '      Rejection of observations near land switch               ln_nea = ', ln_nea
-         WRITE(numout,*) '      Rejection of obs near open bdys                 ln_bound_reject = ', ln_bound_reject
-         WRITE(numout,*) '      MSSH correction scheme                                 nn_msshc = ', nn_msshc
-         WRITE(numout,*) '      MDT  correction                                      rn_mdtcorr = ', rn_mdtcorr
-         WRITE(numout,*) '      MDT cutoff for computed correction                 rn_mdtcutoff = ', rn_mdtcutoff
-         WRITE(numout,*) '      Logical switch for alt bias                          ln_altbias = ', ln_altbias
-         WRITE(numout,*) '      Logical switch for sst bias                          ln_sstbias = ', ln_sstbias
-         WRITE(numout,*) '      Logical switch for ignoring missing files             ln_ignmis = ', ln_ignmis
-         WRITE(numout,*) '      Daily average types                             nn_profdavtypes = ', nn_profdavtypes
-         WRITE(numout,*) '      Logical switch for night-time SST obs               ln_sstnight = ', ln_sstnight
+            WRITE(numout,*) '      Grid search resolution                         rn_gridsearchres = ', rn_gridsearchres
+         ENDIF
       ENDIF
-      !-----------------------------------------------------------------------
-      ! Set up list of observation types to be used
-      ! and the files associated with each type
-      !-----------------------------------------------------------------------
-
-      nproftypes = COUNT( (/ln_t3d .OR. ln_s3d, ln_vel3d /) )
-      nsurftypes = COUNT( (/ln_sla, ln_sst, ln_sic, ln_sss /) )
-
-      IF( ln_sstbias ) THEN 
-         lmask(:) = .FALSE. 
-         WHERE( cn_sstbiasfiles(:) /= '' )   lmask(:) = .TRUE. 
-         jnumsstbias = COUNT(lmask) 
-         lmask(:) = .FALSE. 
-      ENDIF      
-
-      IF( nproftypes == 0 .AND. nsurftypes == 0 ) THEN
-         CALL ctl_warn( 'dia_obs_init: ln_diaobs is set to true, but all obs operator logical flags',   &
-            &           ' (ln_t3d, ln_s3d, ln_sla, ln_sst, ln_sic, ln_vel3d)',                          &
-            &           ' are set to .FALSE. so turning off calls to dia_obs'  )
+
+      IF( ln_grid_global ) THEN
+         CALL ctl_warn( 'dia_obs_init: ln_grid_global=T may cause memory issues when used with a large number of processors' )
+      ENDIF
+
+      !-----------------------------------------------------------------------
+      ! Read namobs_dta namelists and set up observation groups
+      !-----------------------------------------------------------------------
+
+      IF( nn_obsgroups == 0 ) THEN
+         CALL ctl_warn( 'dia_obs_init: ln_diaobs is set to true, but nn_obsgroups == 0',   &
+            &           ' so turning off calls to dia_obs'  )
          ln_diaobs = .FALSE.
          RETURN
       ENDIF
 
-      IF( nproftypes > 0 ) THEN
-         !
-         ALLOCATE( cobstypesprof(nproftypes)             )
-         ALLOCATE( ifilesprof   (nproftypes)             )
-         ALLOCATE( clproffiles  (nproftypes,jpmaxnfiles) )
-         !
-         jtype = 0
-         IF( ln_t3d .OR. ln_s3d ) THEN
-            jtype = jtype + 1
-            CALL obs_settypefiles( nproftypes, jpmaxnfiles, jtype, 'prof  ', &
-               &                   cn_profbfiles, ifilesprof, cobstypesprof, clproffiles )
+      ALLOCATE( sobsgroups(nn_obsgroups) )
+
+      jenabled = 0
+      DO jgroup = 1, nn_obsgroups
+         CALL obs_group_read_namelist( sobsgroups(jgroup) )
+         CALL obs_group_check( sobsgroups(jgroup), jgroup )
+         IF (sobsgroups(jgroup)%lenabled) THEN
+            jenabled = jenabled + 1
          ENDIF
-         IF( ln_vel3d ) THEN
-            jtype = jtype + 1
-            CALL obs_settypefiles( nproftypes, jpmaxnfiles, jtype, 'vel   ', &
-               &                   cn_velfbfiles, ifilesprof, cobstypesprof, clproffiles )
-         ENDIF
-         !
-      ENDIF
-
-      IF( nsurftypes > 0 ) THEN
-         !
-         ALLOCATE( cobstypessurf(nsurftypes)             )
-         ALLOCATE( ifilessurf   (nsurftypes)             )
-         ALLOCATE( clsurffiles  (nsurftypes,jpmaxnfiles) )
-         ALLOCATE( n2dintsurf   (nsurftypes)             )
-         ALLOCATE( zavglamscl   (nsurftypes)             )
-         ALLOCATE( zavgphiscl   (nsurftypes)             )
-         ALLOCATE( lfpindegs    (nsurftypes)             )
-         ALLOCATE( llnightav    (nsurftypes)             )
-         !
-         jtype = 0
-         IF( ln_sla ) THEN
-            jtype = jtype + 1
-            CALL obs_settypefiles( nsurftypes, jpmaxnfiles, jtype, 'sla   ', &
-               &                   cn_slafbfiles, ifilessurf, cobstypessurf, clsurffiles )
-            CALL obs_setinterpopts( nsurftypes, jtype, 'sla   ',      &
-               &                  nn_2dint, nn_2dint_sla,             &
-               &                  rn_sla_avglamscl, rn_sla_avgphiscl, &
-               &                  ln_sla_fp_indegs, .FALSE.,          &
-               &                  n2dintsurf, zavglamscl, zavgphiscl, &
-               &                  lfpindegs, llnightav )
-         ENDIF
-         IF( ln_sst ) THEN
-            jtype = jtype + 1
-            CALL obs_settypefiles( nsurftypes, jpmaxnfiles, jtype, 'sst   ', &
-               &                   cn_sstfbfiles, ifilessurf, cobstypessurf, clsurffiles )
-            CALL obs_setinterpopts( nsurftypes, jtype, 'sst   ',      &
-               &                  nn_2dint, nn_2dint_sst,             &
-               &                  rn_sst_avglamscl, rn_sst_avgphiscl, &
-               &                  ln_sst_fp_indegs, ln_sstnight,      &
-               &                  n2dintsurf, zavglamscl, zavgphiscl, &
-               &                  lfpindegs, llnightav )
-         ENDIF
-#if defined key_si3 || defined key_cice
-         IF( ln_sic ) THEN
-            jtype = jtype + 1
-            CALL obs_settypefiles( nsurftypes, jpmaxnfiles, jtype, 'sic   ', &
-               &                   cn_sicfbfiles, ifilessurf, cobstypessurf, clsurffiles )
-            CALL obs_setinterpopts( nsurftypes, jtype, 'sic   ',      &
-               &                  nn_2dint, nn_2dint_sic,             &
-               &                  rn_sic_avglamscl, rn_sic_avgphiscl, &
-               &                  ln_sic_fp_indegs, .FALSE.,          &
-               &                  n2dintsurf, zavglamscl, zavgphiscl, &
-               &                  lfpindegs, llnightav )
-         ENDIF
-#endif
-         IF( ln_sss ) THEN
-            jtype = jtype + 1
-            CALL obs_settypefiles( nsurftypes, jpmaxnfiles, jtype, 'sss   ', &
-               &                   cn_sssfbfiles, ifilessurf, cobstypessurf, clsurffiles )
-            CALL obs_setinterpopts( nsurftypes, jtype, 'sss   ',      &
-               &                  nn_2dint, nn_2dint_sss,             &
-               &                  rn_sss_avglamscl, rn_sss_avgphiscl, &
-               &                  ln_sss_fp_indegs, .FALSE.,          &
-               &                  n2dintsurf, zavglamscl, zavgphiscl, &
-               &                  lfpindegs, llnightav )
-         ENDIF
-         !
-      ENDIF
-
-
-      !-----------------------------------------------------------------------
-      ! Obs operator parameter checking and initialisations
-      !-----------------------------------------------------------------------
-      !
-      IF( ln_vel3d  .AND.  .NOT.ln_grid_global ) THEN
-         CALL ctl_stop( 'Velocity data only works with ln_grid_global=.true.' )
+      END DO
+
+      IF( jenabled == 0 ) THEN
+         CALL ctl_warn( 'dia_obs_init: ln_diaobs is set to true, and nn_obsgroups > 0',   &
+            &           ' but no groups are enabled so turning off calls to dia_obs'  )
+         ln_diaobs = .FALSE.
          RETURN
       ENDIF
-      !
-      IF( ln_grid_global ) THEN
-         CALL ctl_warn( 'dia_obs_init: ln_grid_global=T may cause memory issues when used with a large number of processors' )
-      ENDIF
-      !
-      IF( nn_1dint < 0  .OR.  nn_1dint > 1 ) THEN
-         CALL ctl_stop('dia_obs_init: Choice of vertical (1D) interpolation method is not available')
-      ENDIF
-      !
-      IF( nn_2dint < 0  .OR.  nn_2dint > 6  ) THEN
-         CALL ctl_stop('dia_obs_init: Choice of horizontal (2D) interpolation method is not available')
-      ENDIF
+
+      !-----------------------------------------------------------------------
+      ! Obs operator parameter checking and initialisations
+      !-----------------------------------------------------------------------
       !
       CALL obs_typ_init
@@ -382,101 +197,169 @@
       !-----------------------------------------------------------------------
       !
-      IF( nproftypes > 0 ) THEN
-         !
-         ALLOCATE( profdata  (nproftypes) , nvarsprof (nproftypes) )
-         ALLOCATE( profdataqc(nproftypes) , nextrprof (nproftypes) )
-         !
-         DO jtype = 1, nproftypes
-            !
-            nvarsprof(jtype) = 2
-            IF ( TRIM(cobstypesprof(jtype)) == 'prof' ) THEN
-               nextrprof(jtype) = 1
-               llvar1 = ln_t3d
-               llvar2 = ln_s3d
-               zglam1 = glamt
-               zgphi1 = gphit
-               zmask1 = tmask
-               zglam2 = glamt
-               zgphi2 = gphit
-               zmask2 = tmask
+      DO jgroup = 1, nn_obsgroups
+         IF ( sobsgroups(jgroup)%lenabled ) THEN
+            IF ( sobsgroups(jgroup)%lprof ) THEN
+               !
+               ! Read in profile or profile obs types
+               !
+               ALLOCATE( llvar(sobsgroups(jgroup)%nobstypes) )
+               llvar(:) = .TRUE.
+               !
+               CALL obs_rea_prof( sobsgroups(jgroup)%sprofdata,   &
+                  &               sobsgroups(jgroup)%nobsfiles,   &
+                  &               sobsgroups(jgroup)%cobsfiles,   &
+                  &               sobsgroups(jgroup)%nobstypes,   &
+                  &               sobsgroups(jgroup)%naddvars,    &
+                  &               sobsgroups(jgroup)%nextvars,    &
+                  &               nitend-nit000+2,                &
+                  &               rn_dobsini,                     &
+                  &               rn_dobsend,                     &
+                  &               llvar,                          &
+                  &               sobsgroups(jgroup)%lignmis,     &
+                  &               sobsgroups(jgroup)%lall_at_all, &
+                  &               .FALSE.,                        &
+                  &               sobsgroups(jgroup)%cobstypes,   &
+                  &               kdailyavtypes = sobsgroups(jgroup)%nprofdavtypes )
+               !
+               DO jvar = 1, sobsgroups(jgroup)%nobstypes
+                  CALL obs_prof_staend( sobsgroups(jgroup)%sprofdata, jvar )
+               END DO
+               !
+               IF ( sobsgroups(jgroup)%sprofdata%next > 0 ) THEN
+                  CALL obs_prof_staend_ext( sobsgroups(jgroup)%sprofdata )
+               ENDIF
+               !
+               IF( sobsgroups(jgroup)%loutput_clim ) THEN
+                  sobsgroups(jgroup)%sprofdata%caddvars(sobsgroups(jgroup)%nadd_clm)  = 'CLM'
+                  DO jvar = 1, sobsgroups(jgroup)%nobstypes
+                     sobsgroups(jgroup)%sprofdata%var(jvar)%vadd(:,sobsgroups(jgroup)%nadd_clm) = fbrmdi
+                     sobsgroups(jgroup)%sprofdata%caddlong(sobsgroups(jgroup)%nadd_clm,jvar) = 'Climatology'
+                     sobsgroups(jgroup)%sprofdata%caddunit(sobsgroups(jgroup)%nadd_clm,jvar) = sobsgroups(jgroup)%sprofdata%cunit(jvar)
+                  END DO
+               ENDIF
+               !
+               sobsgroups(jgroup)%sprofdata%cgrid = sobsgroups(jgroup)%cgrid
+               !
+               CALL obs_pre_prof( sobsgroups(jgroup)%sprofdata,     &
+                  &               sobsgroups(jgroup)%sprofdataqc,   &
+                  &               llvar,                            &
+                  &               jpi, jpj, jpk,                    &
+                  &               sobsgroups(jgroup)%rmask,         &
+                  &               sobsgroups(jgroup)%rglam,         &
+                  &               sobsgroups(jgroup)%rgphi,         &
+                  &               sobsgroups(jgroup)%lnea,          &
+                  &               sobsgroups(jgroup)%lbound_reject, &
+                  &               kdailyavtypes = sobsgroups(jgroup)%nprofdavtypes )
+               !
+               DEALLOCATE( llvar )
+               !
+            ELSEIF (sobsgroups(jgroup)%lsurf) THEN
+               !
+               ! Read in surface obs types
+               !
+               CALL obs_rea_surf( sobsgroups(jgroup)%ssurfdata,         &
+                  &               sobsgroups(jgroup)%nobsfiles,         &
+                  &               sobsgroups(jgroup)%cobsfiles,         &
+                  &               sobsgroups(jgroup)%nobstypes,         &
+                  &               sobsgroups(jgroup)%naddvars,          &
+                  &               sobsgroups(jgroup)%nextvars,          &
+                  &               nitend-nit000+2,                      &
+                  &               rn_dobsini,                           &
+                  &               rn_dobsend,                           &
+                  &               sobsgroups(jgroup)%rtime_mean_period, &
+                  &               sobsgroups(jgroup)%ltime_mean_bkg,    &
+                  &               sobsgroups(jgroup)%lignmis,           &
+                  &               .FALSE.,                              &
+                  &               sobsgroups(jgroup)%lnight,            &
+                  &               sobsgroups(jgroup)%cobstypes )
+               !
+               IF( sobsgroups(jgroup)%lsla ) THEN
+                  sobsgroups(jgroup)%ssurfdata%cextvars(sobsgroups(jgroup)%next_mdt) = 'MDT'
+                  sobsgroups(jgroup)%ssurfdata%cextlong(sobsgroups(jgroup)%next_mdt) = 'Mean dynamic topography'
+                  sobsgroups(jgroup)%ssurfdata%cextunit(sobsgroups(jgroup)%next_mdt) = 'Metres'
+                  sobsgroups(jgroup)%ssurfdata%caddvars(sobsgroups(jgroup)%nadd_ssh) = 'SSH'
+                  DO jvar = 1, sobsgroups(jgroup)%nobstypes
+                     sobsgroups(jgroup)%ssurfdata%caddlong(sobsgroups(jgroup)%nadd_ssh,jvar) = 'Model Sea surface height'
+                     sobsgroups(jgroup)%ssurfdata%caddunit(sobsgroups(jgroup)%nadd_ssh,jvar) = 'Metres'
+                  END DO
+               ENDIF
+               !
+               IF( sobsgroups(jgroup)%lfbd ) THEN
+                  sobsgroups(jgroup)%ssurfdata%cextvars(sobsgroups(jgroup)%next_snow) = 'SNOW'
+                  sobsgroups(jgroup)%ssurfdata%cextlong(sobsgroups(jgroup)%next_snow) = 'Snow thickness'
+                  sobsgroups(jgroup)%ssurfdata%cextunit(sobsgroups(jgroup)%next_snow) = 'Metres'
+                  sobsgroups(jgroup)%ssurfdata%caddvars(sobsgroups(jgroup)%nadd_fbd)  = 'FBD'
+                  DO jvar = 1, sobsgroups(jgroup)%nobstypes
+                     sobsgroups(jgroup)%ssurfdata%caddlong(sobsgroups(jgroup)%nadd_fbd,jvar) = 'Freeboard'
+                     sobsgroups(jgroup)%ssurfdata%caddunit(sobsgroups(jgroup)%nadd_fbd,jvar) = 'Metres'
+                  END DO
+               ENDIF
+               !
+               IF( sobsgroups(jgroup)%loutput_clim ) THEN
+                  sobsgroups(jgroup)%ssurfdata%caddvars(sobsgroups(jgroup)%nadd_clm)  = 'CLM'
+                  DO jvar = 1, sobsgroups(jgroup)%nobstypes
+                     sobsgroups(jgroup)%ssurfdata%radd(:,:,jvar) = fbrmdi
+                     sobsgroups(jgroup)%ssurfdata%caddlong(sobsgroups(jgroup)%nadd_clm,jvar) = 'Climatology'
+                     sobsgroups(jgroup)%ssurfdata%caddunit(sobsgroups(jgroup)%nadd_clm,jvar) = sobsgroups(jgroup)%ssurfdata%cunit(jvar)
+                  END DO
+               ENDIF
+               !
+               sobsgroups(jgroup)%ssurfdata%cgrid = sobsgroups(jgroup)%cgrid
+               !
+               CALL obs_pre_surf( sobsgroups(jgroup)%ssurfdata,      &
+                  &               sobsgroups(jgroup)%ssurfdataqc,    &
+                  &               jpi, jpj,                          &
+                  &               sobsgroups(jgroup)%rmask(:,:,1,:), &
+                  &               sobsgroups(jgroup)%rglam,          &
+                  &               sobsgroups(jgroup)%rgphi,          &
+                  &               sobsgroups(jgroup)%lnea,           &
+                  &               sobsgroups(jgroup)%lbound_reject )
+               !
+               IF( sobsgroups(jgroup)%lsla ) THEN
+                  CALL obs_rea_mdt( sobsgroups(jgroup)%ssurfdataqc, &
+                     &              sobsgroups(jgroup)%n2dint,      &
+                     &              sobsgroups(jgroup)%next_mdt,    &
+                     &              sobsgroups(jgroup)%nmsshc,      &
+                     &              sobsgroups(jgroup)%rmdtcorr,    &
+                     &              sobsgroups(jgroup)%rmdtcutoff )
+                  IF( sobsgroups(jgroup)%laltbias ) THEN
+                     CALL obs_app_bias( sobsgroups(jgroup)%ssurfdataqc,   &
+                        &               sobsgroups(jgroup)%next_mdt,      & 
+                        &               sobsgroups(jgroup)%n2dint,        & 
+                        &               1,                                &
+                        &               sobsgroups(jgroup)%caltbiasfile,  &
+                        &               'altbias',                        &
+                        &               ld_extvar=.TRUE. ) 
+                  ENDIF
+               ENDIF
+               !
+#if defined key_si3
+               IF( sobsgroups(jgroup)%lfbd ) THEN
+                  CALL obs_rea_snowdepth( sobsgroups(jgroup)%ssurfdataqc, &
+                     &                    sobsgroups(jgroup)%n2dint,      &
+                     &                    sobsgroups(jgroup)%next_snow,   &
+                     &                    hm_s(:,:) )
+               ENDIF
+#elif defined key_cice
+               IF( sobsgroups(jgroup)%lfbd ) THEN
+                  CALL obs_rea_snowdepth( sobsgroups(jgroup)%ssurfdataqc, &
+                     &                    sobsgroups(jgroup)%n2dint,      &
+                     &                    sobsgroups(jgroup)%next_snow,   &
+                     &                    thick_s(:,:) )
+               ENDIF
+#endif
+               !
+               IF( sobsgroups(jgroup)%lobsbias ) THEN
+                  CALL obs_app_bias( sobsgroups(jgroup)%ssurfdataqc,   &
+                     &               sobsgroups(jgroup)%nbiasvar,      & 
+                     &               sobsgroups(jgroup)%n2dint,        & 
+                     &               sobsgroups(jgroup)%nobsbiasfiles, &
+                     &               sobsgroups(jgroup)%cobsbiasfiles, &
+                     &               sobsgroups(jgroup)%cbiasvarname ) 
+               ENDIF
+               !
             ENDIF
-            IF ( TRIM(cobstypesprof(jtype)) == 'vel' )  THEN
-               nextrprof(jtype) = 2
-               llvar1 = ln_vel3d
-               llvar2 = ln_vel3d
-               zglam1 = glamu
-               zgphi1 = gphiu
-               zmask1 = umask
-               zglam2 = glamv
-               zgphi2 = gphiv
-               zmask2 = vmask
-            ENDIF
-            !
-            ! Read in profile or profile obs types
-            CALL obs_rea_prof( profdata(jtype), ifilesprof(jtype),       &
-               &               clproffiles(jtype,1:ifilesprof(jtype)), &
-               &               nvarsprof(jtype), nextrprof(jtype), nitend-nit000+2, &
-               &               rn_dobsini, rn_dobsend, llvar1, llvar2, &
-               &               ln_ignmis, ln_s_at_t, .FALSE., &
-               &               kdailyavtypes = nn_profdavtypes )
-               !
-            DO jvar = 1, nvarsprof(jtype)
-               CALL obs_prof_staend( profdata(jtype), jvar )
-            END DO
-            !
-            CALL obs_pre_prof( profdata(jtype), profdataqc(jtype), &
-               &               llvar1, llvar2, &
-               &               jpi, jpj, jpk, &
-               &               zmask1, zglam1, zgphi1, zmask2, zglam2, zgphi2,  &
-               &               ln_nea, ln_bound_reject, &
-               &               kdailyavtypes = nn_profdavtypes )
-         END DO
-         !
-         DEALLOCATE( ifilesprof, clproffiles )
-         !
-      ENDIF
-      !
-      IF( nsurftypes > 0 ) THEN
-         !
-         ALLOCATE( surfdata  (nsurftypes) , nvarssurf(nsurftypes) )
-         ALLOCATE( surfdataqc(nsurftypes) , nextrsurf(nsurftypes) )
-         !
-         DO jtype = 1, nsurftypes
-            !
-            nvarssurf(jtype) = 1
-            nextrsurf(jtype) = 0
-            llnightav(jtype) = .FALSE.
-            IF( TRIM(cobstypessurf(jtype)) == 'sla' )   nextrsurf(jtype) = 2
-            IF( TRIM(cobstypessurf(jtype)) == 'sst' )   llnightav(jtype) = ln_sstnight
-            !
-            ! Read in surface obs types
-            CALL obs_rea_surf( surfdata(jtype), ifilessurf(jtype), &
-               &               clsurffiles(jtype,1:ifilessurf(jtype)), &
-               &               nvarssurf(jtype), nextrsurf(jtype), nitend-nit000+2, &
-               &               rn_dobsini, rn_dobsend, ln_ignmis, .FALSE., llnightav(jtype) )
-               !
-            CALL obs_pre_surf( surfdata(jtype), surfdataqc(jtype), ln_nea, ln_bound_reject )
-            !
-            IF( TRIM(cobstypessurf(jtype)) == 'sla' ) THEN
-               CALL obs_rea_mdt( surfdataqc(jtype), n2dintsurf(jtype) )
-               IF( ln_altbias )   &
-                  & CALL obs_rea_altbias ( surfdataqc(jtype), n2dintsurf(jtype), cn_altbiasfile )
-            ENDIF
-            !
-            IF( TRIM(cobstypessurf(jtype)) == 'sst' .AND. ln_sstbias ) THEN
-               jnumsstbias = 0
-               DO jfile = 1, jpmaxnfiles
-                  IF( TRIM(cn_sstbiasfiles(jfile)) /= '' )   jnumsstbias = jnumsstbias + 1
-               END DO
-               IF( jnumsstbias == 0 )   CALL ctl_stop("ln_sstbias set but no bias files to read in")    
-               !
-               CALL obs_app_sstbias( surfdataqc(jtype), n2dintsurf(jtype)             ,   & 
-                  &                  jnumsstbias      , cn_sstbiasfiles(1:jnumsstbias) ) 
-            ENDIF
-         END DO
-         !
-         DEALLOCATE( ifilessurf, clsurffiles )
-         !
-      ENDIF
+         ENDIF
+      END DO
       !
    END SUBROUTINE dia_obs_init
@@ -500,10 +383,11 @@
       USE oce    , ONLY : tsn, un, vn, sshn   ! Ocean dynamics and tracers variables
       USE phycst , ONLY : rday                ! Physical constants
-#if defined  key_si3
-      USE ice    , ONLY : at_i                ! SI3 Ice model variables
+#if defined key_si3
+      USE ice    , ONLY : at_i, hm_i          ! SI3 Ice model variables
+#elif defined key_cice
+      USE sbc_oce, ONLY : fr_i, thick_i       ! CICE Ice model variables
 #endif
-#if defined key_cice
-      USE sbc_oce, ONLY : fr_i     ! ice fraction
-#endif
+      USE tradmp,  ONLY : tclim, sclim        ! T&S climatology
+      USE obs_fbm, ONLY : fbrmdi              ! Real missing data indicator
 
       IMPLICIT NONE
@@ -513,23 +397,20 @@
       !! * Local declarations
       INTEGER :: idaystp           ! Number of timesteps per day
+      INTEGER :: imeanstp          ! Number of timesteps for time averaging
       INTEGER :: jtype             ! Data loop variable
       INTEGER :: jvar              ! Variable number
-      INTEGER :: ji, jj            ! Loop counters
-      REAL(wp), DIMENSION(jpi,jpj,jpk) :: &
-         & zprofvar1, &            ! Model values for 1st variable in a prof ob
-         & zprofvar2               ! Model values for 2nd variable in a prof ob
-      REAL(wp), DIMENSION(jpi,jpj,jpk) :: &
-         & zprofmask1, &           ! Mask associated with zprofvar1
-         & zprofmask2              ! Mask associated with zprofvar2
-      REAL(wp), DIMENSION(jpi,jpj) :: &
-         & zsurfvar, &             ! Model values equivalent to surface ob.
-         & zsurfmask               ! Mask associated with surface variable
-      REAL(wp), DIMENSION(jpi,jpj) :: &
-         & zglam1,    &            ! Model longitudes for prof variable 1
-         & zglam2,    &            ! Model longitudes for prof variable 2
-         & zgphi1,    &            ! Model latitudes for prof variable 1
-         & zgphi2                  ! Model latitudes for prof variable 2
-
-      !-----------------------------------------------------------------------
+      INTEGER :: jgroup
+      INTEGER :: ji, jj, jobs      ! Loop counters
+      LOGICAL :: lstp0             ! Flag special treatment on zeroth time step
+      REAL(wp), DIMENSION(:,:,:), ALLOCATABLE :: &
+         & zprofvar, &             ! Model values for variables in a prof ob
+         & zprofclim               ! Climatology values for variables in a prof ob
+      REAL(wp), DIMENSION(:,:), ALLOCATABLE :: &
+         & zsurfvar, &             ! Model values for variables in a surf ob
+         & zsurfclim               ! Climatology values for variables in a surf ob
+
+      !-----------------------------------------------------------------------
+
+      IF( ln_timing )   CALL timing_start('dia_obs')
 
       IF(lwp) THEN
@@ -545,89 +426,163 @@
       !-----------------------------------------------------------------------
 
-      IF ( nproftypes > 0 ) THEN
-
-         DO jtype = 1, nproftypes
-
-            SELECT CASE ( TRIM(cobstypesprof(jtype)) )
-            CASE('prof')
-               zprofvar1(:,:,:) = tsn(:,:,:,jp_tem)
-               zprofvar2(:,:,:) = tsn(:,:,:,jp_sal)
-               zprofmask1(:,:,:) = tmask(:,:,:)
-               zprofmask2(:,:,:) = tmask(:,:,:)
-               zglam1(:,:) = glamt(:,:)
-               zglam2(:,:) = glamt(:,:)
-               zgphi1(:,:) = gphit(:,:)
-               zgphi2(:,:) = gphit(:,:)
-            CASE('vel')
-               zprofvar1(:,:,:) = un(:,:,:)
-               zprofvar2(:,:,:) = vn(:,:,:)
-               zprofmask1(:,:,:) = umask(:,:,:)
-               zprofmask2(:,:,:) = vmask(:,:,:)
-               zglam1(:,:) = glamu(:,:)
-               zglam2(:,:) = glamv(:,:)
-               zgphi1(:,:) = gphiu(:,:)
-               zgphi2(:,:) = gphiv(:,:)
-            CASE DEFAULT
-               CALL ctl_stop( 'Unknown profile observation type '//TRIM(cobstypesprof(jtype))//' in dia_obs' )
-            END SELECT
-
-            CALL obs_prof_opt( profdataqc(jtype), kstp, jpi, jpj, jpk,  &
-               &               nit000, idaystp,                         &
-               &               zprofvar1, zprofvar2,                    &
-               &               gdept_n(:,:,:), gdepw_n(:,:,:),            & 
-               &               zprofmask1, zprofmask2,                  &
-               &               zglam1, zglam2, zgphi1, zgphi2,          &
-               &               nn_1dint, nn_2dint,                      &
-               &               kdailyavtypes = nn_profdavtypes )
-
-         END DO
-
-      ENDIF
-
-      IF ( nsurftypes > 0 ) THEN
-
-         DO jtype = 1, nsurftypes
-
-            !Defaults which might be changed
-            zsurfmask(:,:) = tmask(:,:,1)
-
-            SELECT CASE ( TRIM(cobstypessurf(jtype)) )
-            CASE('sst')
-               zsurfvar(:,:) = tsn(:,:,1,jp_tem)
-            CASE('sla')
-               zsurfvar(:,:) = sshn(:,:)
-            CASE('sss')
-               zsurfvar(:,:) = tsn(:,:,1,jp_sal)
-            CASE('sic')
-               IF ( kstp == 0 ) THEN
-                  IF ( lwp .AND. surfdataqc(jtype)%nsstpmpp(1) > 0 ) THEN
-                     CALL ctl_warn( 'Sea-ice not initialised on zeroth '// &
-                        &           'time-step but some obs are valid then.' )
-                     WRITE(numout,*)surfdataqc(jtype)%nsstpmpp(1), &
-                        &           ' sea-ice obs will be missed'
+      ALLOCATE( zprofvar(jpi,jpj,jpk),  &
+         &      zprofclim(jpi,jpj,jpk), &
+         &      zsurfvar(jpi,jpj),      &
+         &      zsurfclim(jpi,jpj) )
+
+      DO jgroup = 1, nn_obsgroups
+         IF ( sobsgroups(jgroup)%lenabled ) THEN
+
+            IF ( sobsgroups(jgroup)%lprof ) THEN
+
+               zprofclim(:,:,:) = fbrmdi
+
+               DO jvar = 1, sobsgroups(jgroup)%nobstypes
+
+                  SELECT CASE ( TRIM(sobsgroups(jgroup)%cobstypes(jvar)) )
+                  CASE('POTM')
+                     zprofvar(:,:,:) = tsn(:,:,:,jp_tem)
+                     IF (sobsgroups(jgroup)%loutput_clim) THEN
+                        zprofclim(:,:,:) = tclim(:,:,:)
+                     ENDIF
+                  CASE('PSAL')
+                     zprofvar(:,:,:) = tsn(:,:,:,jp_sal)
+                     IF (sobsgroups(jgroup)%loutput_clim) THEN
+                        zprofclim(:,:,:) = sclim(:,:,:)
+                     ENDIF
+                  CASE('UVEL')
+                     zprofvar(:,:,:) = un(:,:,:)
+                  CASE('VVEL')
+                     zprofvar(:,:,:) = vn(:,:,:)
+                  CASE DEFAULT
+                     CALL ctl_stop( 'Unknown profile observation type '//TRIM(sobsgroups(jgroup)%cobstypes(jvar))//' in dia_obs' )
+                  END SELECT
+
+                  CALL obs_prof_opt( sobsgroups(jgroup)%sprofdataqc,       &
+                     &               kstp, jpi, jpj, jpk,                  &
+                     &               nit000, idaystp, jvar,                &
+                     &               zprofvar,                             &
+                     &               sobsgroups(jgroup)%loutput_clim,      &
+                     &               sobsgroups(jgroup)%nadd_clm,          &
+                     &               zprofclim,                            &
+                     &               gdept_n,                              &
+                     &               gdepw_n,                              & 
+                     &               sobsgroups(jgroup)%rmask(:,:,:,jvar), &
+                     &               sobsgroups(jgroup)%rglam(:,:,jvar),   &
+                     &               sobsgroups(jgroup)%rgphi(:,:,jvar),   &
+                     &               sobsgroups(jgroup)%n1dint,            &
+                     &               sobsgroups(jgroup)%n2dint,            &
+                     &               kdailyavtypes = sobsgroups(jgroup)%nprofdavtypes )
+
+               END DO
+
+            ELSEIF (sobsgroups(jgroup)%lsurf) THEN
+
+               zsurfclim(:,:) = fbrmdi
+
+               DO jvar = 1, sobsgroups(jgroup)%nobstypes
+
+                  lstp0 = .FALSE.
+                  SELECT CASE ( TRIM(sobsgroups(jgroup)%cobstypes(jvar)) )
+                  CASE('SST')
+                     zsurfvar(:,:) = tsn(:,:,1,jp_tem)
+                     IF (sobsgroups(jgroup)%loutput_clim) THEN
+                        zsurfclim(:,:) = tclim(:,:,1)
+                     ENDIF
+                  CASE('SLA')
+                     zsurfvar(:,:) = sshn(:,:)
+                  CASE('SSS')
+                     zsurfvar(:,:) = tsn(:,:,1,jp_sal)
+                     IF (sobsgroups(jgroup)%loutput_clim) THEN
+                        zsurfclim(:,:) = sclim(:,:,1)
+                     ENDIF
+                  CASE('UVEL')
+                     zsurfvar(:,:) = un(:,:,1)
+                  CASE('VVEL')
+                     zsurfvar(:,:) = vn(:,:,1)
+                  CASE('ICECONC')
+                     IF ( kstp == 0 ) THEN
+                        lstp0 = .TRUE.
+                     ELSE
+#if defined key_si3
+                        zsurfvar(:,:) = at_i(:,:)
+#elif defined key_cice
+                        zsurfvar(:,:) = fr_i(:,:)
+#else
+                        CALL ctl_stop( ' Trying to run sea-ice observation operator', &
+                           &           ' but no sea-ice model appears to have been defined' )
+#endif
+                     ENDIF
+                  CASE('SIT','FBD')
+                     IF ( kstp == 0 ) THEN
+                        lstp0 = .TRUE.
+                     ELSE
+#if defined key_si3
+                        zsurfvar(:,:) = hm_i(:,:)
+#elif defined key_cice
+                        zsurfvar(:,:) = thick_i(:,:)
+#else
+                        CALL ctl_stop( ' Trying to run sea-ice observation operator', &
+                           &           ' but no sea-ice model appears to have been defined' )
+#endif
+                     ENDIF
+                  END SELECT
+
+                  IF ( lstp0 ) THEN
+                     IF ( sobsgroups(jgroup)%ssurfdataqc%nsstpmpp(1) > 0 ) THEN
+                        DO jobs = sobsgroups(jgroup)%ssurfdataqc%nsurfup + 1, &
+                           &      sobsgroups(jgroup)%ssurfdataqc%nsurfup + sobsgroups(jgroup)%ssurfdataqc%nsstp(1)
+                           sobsgroups(jgroup)%ssurfdata%nqc(jobs) = IBSET(sobsgroups(jgroup)%ssurfdata%nqc(jobs),13)
+                        END DO
+                        IF ( lwp ) THEN
+                           CALL ctl_warn( TRIM(sobsgroups(jgroup)%cobstypes(jvar))// &
+                              &           ' not initialised on zeroth '           // &
+                              &           'time-step but some obs are valid then.' )
+                           WRITE(numout,*)sobsgroups(jgroup)%ssurfdataqc%nsstpmpp(1), &
+                              &           TRIM(sobsgroups(jgroup)%cobstypes(jvar)),   &
+                              &           'observations will be flagged as bad'
+                        ENDIF
+                     ENDIF
+                     IF ( jvar == sobsgroups(jgroup)%ssurfdataqc%nvar ) THEN
+                        sobsgroups(jgroup)%ssurfdataqc%nsurfup = sobsgroups(jgroup)%ssurfdataqc%nsurfup + &
+                           &                                     sobsgroups(jgroup)%ssurfdataqc%nsstp(1)
+                     ENDIF
+                  ELSE
+                     IF ( sobsgroups(jgroup)%ltime_mean_bkg ) THEN
+                        ! Number of time-steps in meaning period
+                        imeanstp = NINT( ( sobsgroups(jgroup)%rtime_mean_period * 60.0 * 60.0 ) / rdt )
+                     ENDIF
+                     CALL obs_surf_opt( sobsgroups(jgroup)%ssurfdataqc,       &
+                        &               kstp, jpi, jpj,                       &
+                        &               nit000, idaystp,                      &
+                        &               jvar, zsurfvar,                       &
+                        &               sobsgroups(jgroup)%loutput_clim,      &
+                        &               sobsgroups(jgroup)%nadd_clm,          &
+                        &               zsurfclim,                            &
+                        &               sobsgroups(jgroup)%rmask(:,:,1,jvar), &
+                        &               sobsgroups(jgroup)%n2dint,            &
+                        &               sobsgroups(jgroup)%lnight,            &
+                        &               sobsgroups(jgroup)%ravglamscl,        &
+                        &               sobsgroups(jgroup)%ravgphiscl,        &
+                        &               sobsgroups(jgroup)%lfp_indegs,        &
+                        &               sobsgroups(jgroup)%ltime_mean_bkg,    &
+                        &               imeanstp,                             &
+                        &               kssh=sobsgroups(jgroup)%nadd_ssh,     &
+                        &               kmdt=sobsgroups(jgroup)%next_mdt,     &
+                        &               kfbd=sobsgroups(jgroup)%nadd_fbd,     &
+                        &               ksnow=sobsgroups(jgroup)%next_snow )
                   ENDIF
-                  surfdataqc(jtype)%nsurfup = surfdataqc(jtype)%nsurfup + &
-                     &                        surfdataqc(jtype)%nsstp(1)
-                  CYCLE
-               ELSE
-#if defined key_cice || defined key_si3
-                  zsurfvar(:,:) = fr_i(:,:)
-#else
-                  CALL ctl_stop( ' Trying to run sea-ice observation operator', &
-                     &           ' but no sea-ice model appears to have been defined' )
-#endif
-               ENDIF
-
-            END SELECT
-
-            CALL obs_surf_opt( surfdataqc(jtype), kstp, jpi, jpj,       &
-               &               nit000, idaystp, zsurfvar, zsurfmask,    &
-               &               n2dintsurf(jtype), llnightav(jtype),     &
-               &               zavglamscl(jtype), zavgphiscl(jtype),     &
-               &               lfpindegs(jtype) )
-
-         END DO
-
-      ENDIF
+
+               END DO
+
+            ENDIF
+
+         ENDIF
+      END DO
+
+      DEALLOCATE( zprofvar, zprofclim, &
+         &        zsurfvar, zsurfclim )
+
+      IF( ln_timing )   CALL timing_stop('dia_obs')
 
    END SUBROUTINE dia_obs
@@ -657,9 +612,14 @@
 
       !! * Local declarations
-      INTEGER :: jtype                    ! Data set loop variable
-      INTEGER :: jo, jvar, jk
+      INTEGER :: jgroup                   ! Data set loop variable
+      INTEGER :: jo, jvar, jk, jadd, jext, jadd2, jext2
+      INTEGER :: iuvar, ivvar
       REAL(wp), DIMENSION(:), ALLOCATABLE :: &
          & zu, &
          & zv
+      LOGICAL, DIMENSION(:), ALLOCATABLE :: ll_write
+      TYPE(obswriinfo) :: sladd, slext
+
+      IF( ln_timing )   CALL timing_start('dia_obs_wri')
 
       !-----------------------------------------------------------------------
@@ -667,87 +627,276 @@
       !-----------------------------------------------------------------------
 
-      IF ( nproftypes > 0 ) THEN
-
-         DO jtype = 1, nproftypes
-
-            IF ( TRIM(cobstypesprof(jtype)) == 'vel' ) THEN
-
-               ! For velocity data, rotate the model velocities to N/S, E/W
-               ! using the compressed data structure.
-               ALLOCATE( &
-                  & zu(profdataqc(jtype)%nvprot(1)), &
-                  & zv(profdataqc(jtype)%nvprot(2))  &
-                  & )
-
-               CALL obs_rotvel( profdataqc(jtype), nn_2dint, zu, zv )
-
-               DO jo = 1, profdataqc(jtype)%nprof
-                  DO jvar = 1, 2
-                     DO jk = profdataqc(jtype)%npvsta(jo,jvar), profdataqc(jtype)%npvend(jo,jvar)
-
-                        IF ( jvar == 1 ) THEN
-                           profdataqc(jtype)%var(jvar)%vmod(jk) = zu(jk)
-                        ELSE
-                           profdataqc(jtype)%var(jvar)%vmod(jk) = zv(jk)
+      DO jgroup = 1, nn_obsgroups
+         IF (sobsgroups(jgroup)%lenabled) THEN
+
+            IF (sobsgroups(jgroup)%lprof) THEN
+
+               IF (sobsgroups(jgroup)%lvel) THEN
+                  iuvar = 0
+                  ivvar = 0
+                  DO jvar = 1, sobsgroups(jgroup)%nobstypes
+                     IF ( TRIM(sobsgroups(jgroup)%cobstypes(jvar)) == cobsname_uvel ) THEN
+                        iuvar = jvar
+                     ELSEIF ( TRIM(sobsgroups(jgroup)%cobstypes(jvar)) == cobsname_vvel ) THEN
+                        ivvar = jvar
+                     ENDIF
+                  END DO
+                  IF ( (iuvar > 0) .AND. (ivvar > 0) ) THEN
+
+                     ! For velocity data, rotate the model velocities to N/S, E/W
+                     ! using the compressed data structure.
+                     ALLOCATE( &
+                        & zu(sobsgroups(jgroup)%sprofdataqc%nvprot(iuvar)), &
+                        & zv(sobsgroups(jgroup)%sprofdataqc%nvprot(ivvar))  &
+                        & )
+
+                     CALL obs_rotvel_pro( sobsgroups(jgroup)%sprofdataqc, sobsgroups(jgroup)%n2dint, &
+                        &                 iuvar, ivvar, zu, zv )
+
+                     DO jo = 1, sobsgroups(jgroup)%sprofdataqc%nprof
+                        DO jk = sobsgroups(jgroup)%sprofdataqc%npvsta(jo,iuvar), sobsgroups(jgroup)%sprofdataqc%npvend(jo,iuvar)
+                           sobsgroups(jgroup)%sprofdataqc%var(iuvar)%vmod(jk) = zu(jk)
+                        END DO
+                        DO jk = sobsgroups(jgroup)%sprofdataqc%npvsta(jo,ivvar), sobsgroups(jgroup)%sprofdataqc%npvend(jo,ivvar)
+                           sobsgroups(jgroup)%sprofdataqc%var(ivvar)%vmod(jk) = zv(jk)
+                        END DO
+                     END DO
+
+                     DEALLOCATE( zu )
+                     DEALLOCATE( zv )
+
+                  ELSE
+                     CALL ctl_stop( 'Could not identify velocity observation variables to rotate' )
+                  END IF
+               END IF
+
+               CALL obs_prof_decompress( sobsgroups(jgroup)%sprofdataqc, &
+                  &                      sobsgroups(jgroup)%sprofdata, .TRUE., numout )
+
+               ! Put additional and extra variable information into obswriinfo structure
+               ! used by obs_write.
+               ! add/ext variables generated by the OBS code (1...sobsgroups(jgroup)%naddvars)
+               ! may duplicate ones read in (%naddvars+1...sobsgroups(jgroup)%sprofdata%nadd)
+               ! Check for this, and if so only write out the version generated by the OBS code
+               sladd%inum = sobsgroups(jgroup)%sprofdata%nadd
+               ALLOCATE( ll_write(sobsgroups(jgroup)%sprofdata%nadd) )
+               ll_write(:) = .TRUE.
+               IF ( (sobsgroups(jgroup)%naddvars > 0) .AND. &
+                  & (sobsgroups(jgroup)%sprofdata%nadd > sobsgroups(jgroup)%naddvars) ) THEN
+                  DO jadd = sobsgroups(jgroup)%naddvars + 1, sobsgroups(jgroup)%sprofdata%nadd
+                     DO jadd2 = 1, sobsgroups(jgroup)%naddvars
+                        IF ( TRIM(sobsgroups(jgroup)%sprofdata%caddvars(jadd )) == &
+                           & TRIM(sobsgroups(jgroup)%sprofdata%caddvars(jadd2)) ) THEN
+                           sladd%inum = sladd%inum - 1
+                           ll_write(jadd) = .FALSE.
                         ENDIF
-
                      END DO
                   END DO
-               END DO
-
-               DEALLOCATE( zu )
-               DEALLOCATE( zv )
-
-            END IF
-
-            CALL obs_prof_decompress( profdataqc(jtype), &
-               &                      profdata(jtype), .TRUE., numout )
-
-            CALL obs_wri_prof( profdata(jtype) )
-
-         END DO
-
-      ENDIF
-
-      IF ( nsurftypes > 0 ) THEN
-
-         DO jtype = 1, nsurftypes
-
-            CALL obs_surf_decompress( surfdataqc(jtype), &
-               &                      surfdata(jtype), .TRUE., numout )
-
-            CALL obs_wri_surf( surfdata(jtype) )
-
-         END DO
-
-      ENDIF
+               ENDIF
+               IF ( sladd%inum > 0 ) THEN
+                  ALLOCATE( sladd%ipoint(sladd%inum),                                   &
+                     &      sladd%cdname(sladd%inum),                                   &
+                     &      sladd%cdlong(sladd%inum,sobsgroups(jgroup)%sprofdata%nvar), &
+                     &      sladd%cdunit(sladd%inum,sobsgroups(jgroup)%sprofdata%nvar) )
+                  jadd2 = 0
+                  DO jadd = 1, sobsgroups(jgroup)%sprofdata%nadd
+                     IF ( ll_write(jadd) ) THEN
+                        jadd2 = jadd2 + 1
+                        sladd%ipoint(jadd2) = jadd
+                        sladd%cdname(jadd2) = sobsgroups(jgroup)%sprofdata%caddvars(jadd)
+                        DO jvar = 1, sobsgroups(jgroup)%sprofdata%nvar
+                           sladd%cdlong(jadd2,jvar) = sobsgroups(jgroup)%sprofdata%caddlong(jadd,jvar)
+                           sladd%cdunit(jadd2,jvar) = sobsgroups(jgroup)%sprofdata%caddunit(jadd,jvar)
+                        END DO
+                     ENDIF
+                  END DO
+               ENDIF
+               DEALLOCATE( ll_write )
+               
+               slext%inum = sobsgroups(jgroup)%sprofdata%next
+               ALLOCATE( ll_write(sobsgroups(jgroup)%sprofdata%next) )
+               ll_write(:) = .TRUE.
+               IF ( (sobsgroups(jgroup)%nextvars > 0) .AND. &
+                  & (sobsgroups(jgroup)%sprofdata%next > sobsgroups(jgroup)%nextvars) ) THEN
+                  DO jext = sobsgroups(jgroup)%nextvars + 1, sobsgroups(jgroup)%sprofdata%next
+                     DO jext2 = 1, sobsgroups(jgroup)%nextvars
+                        IF ( TRIM(sobsgroups(jgroup)%sprofdata%cextvars(jext )) == &
+                           & TRIM(sobsgroups(jgroup)%sprofdata%cextvars(jext2)) ) THEN
+                           slext%inum = slext%inum - 1
+                           ll_write(jext) = .FALSE.
+                        ENDIF
+                     END DO
+                  END DO
+               ENDIF
+               IF ( slext%inum > 0 ) THEN
+                  ALLOCATE( slext%ipoint(slext%inum),   &
+                     &      slext%cdname(slext%inum),   &
+                     &      slext%cdlong(slext%inum,1), &
+                     &      slext%cdunit(slext%inum,1) )
+                  jext2 = 0
+                  DO jext = 1, sobsgroups(jgroup)%sprofdata%next
+                     IF ( ll_write(jext) ) THEN
+                        jext2 = jext2 + 1
+                        slext%ipoint(jext2)   = jext
+                        slext%cdname(jext2)   = sobsgroups(jgroup)%sprofdata%cextvars(jext)
+                        slext%cdlong(jext2,1) = sobsgroups(jgroup)%sprofdata%cextlong(jext)
+                        slext%cdunit(jext2,1) = sobsgroups(jgroup)%sprofdata%cextunit(jext)
+                     ENDIF
+                  END DO
+               ENDIF
+               DEALLOCATE( ll_write )
+
+               CALL obs_wri_prof( sobsgroups(jgroup)%sprofdata, sobsgroups(jgroup)%cgroupname, sladd, slext )
+
+               IF ( sladd%inum > 0 ) THEN
+                  DEALLOCATE( sladd%ipoint, sladd%cdname, sladd%cdlong, sladd%cdunit )
+               ENDIF
+               IF ( slext%inum > 0 ) THEN
+                  DEALLOCATE( slext%ipoint, slext%cdname, slext%cdlong, slext%cdunit )
+               ENDIF
+
+            ELSEIF (sobsgroups(jgroup)%lsurf) THEN
+
+               IF (sobsgroups(jgroup)%lvel) THEN
+                  iuvar = 0
+                  ivvar = 0
+                  DO jvar = 1, sobsgroups(jgroup)%nobstypes
+                     IF ( TRIM(sobsgroups(jgroup)%cobstypes(jvar)) == cobsname_uvel ) THEN
+                        iuvar = jvar
+                     ELSEIF ( TRIM(sobsgroups(jgroup)%cobstypes(jvar)) == cobsname_vvel ) THEN
+                        ivvar = jvar
+                     ENDIF
+                  END DO
+                  IF ( (iuvar > 0) .AND. (ivvar > 0) ) THEN
+
+                     ! For velocity data, rotate the model velocities to N/S, E/W
+                     ! using the compressed data structure.
+                     ALLOCATE( &
+                        & zu(sobsgroups(jgroup)%ssurfdataqc%nsurf), &
+                        & zv(sobsgroups(jgroup)%ssurfdataqc%nsurf)  &
+                        & )
+
+                     CALL obs_rotvel_surf( sobsgroups(jgroup)%ssurfdataqc, sobsgroups(jgroup)%n2dint, &
+                        &                  iuvar, ivvar, zu, zv )
+
+                     DO jo = 1, sobsgroups(jgroup)%ssurfdataqc%nsurf
+                        sobsgroups(jgroup)%ssurfdataqc%rmod(jo,iuvar) = zu(jo)
+                        sobsgroups(jgroup)%ssurfdataqc%rmod(jo,ivvar) = zv(jo)
+                     END DO
+
+                     DEALLOCATE( zu )
+                     DEALLOCATE( zv )
+
+                  ELSE
+                     CALL ctl_stop( 'Could not identify velocity observation variables to rotate' )
+                  END IF
+               END IF
+
+               CALL obs_surf_decompress( sobsgroups(jgroup)%ssurfdataqc, &
+                  &                      sobsgroups(jgroup)%ssurfdata, .TRUE., numout )
+
+               IF (sobsgroups(jgroup)%lfbd) THEN
+                  ! Input observations were freeboard, but we're outputting ice thickness
+                  DO jvar = 1, sobsgroups(jgroup)%nobstypes
+                     IF ( sobsgroups(jgroup)%cobstypes(jvar) == cobsname_fbd ) THEN
+                        sobsgroups(jgroup)%ssurfdata%cvars(jvar) = 'SIT'
+                        sobsgroups(jgroup)%ssurfdata%clong(jvar) = 'Sea ice thickness'
+                        sobsgroups(jgroup)%ssurfdata%cunit(jvar) = 'm'
+                        EXIT
+                     ENDIF
+                  END DO
+               ENDIF
+
+               ! Put additional and extra variable information into obswriinfo structure
+               ! used by obs_write.
+               ! add/ext variables generated by the OBS code (1...sobsgroups(jgroup)%naddvars)
+               ! may duplicate ones read in (%naddvars+1...sobsgroups(jgroup)%ssurfdata%nadd)
+               ! Check for this, and if so only write out the version generated by the OBS code
+               sladd%inum = sobsgroups(jgroup)%ssurfdata%nadd
+               ALLOCATE( ll_write(sobsgroups(jgroup)%ssurfdata%nadd) )
+               ll_write(:) = .TRUE.
+               IF ( (sobsgroups(jgroup)%naddvars > 0) .AND. &
+                  & (sobsgroups(jgroup)%ssurfdata%nadd > sobsgroups(jgroup)%naddvars) ) THEN
+                  DO jadd = sobsgroups(jgroup)%naddvars + 1, sobsgroups(jgroup)%ssurfdata%nadd
+                     DO jadd2 = 1, sobsgroups(jgroup)%naddvars
+                        IF ( TRIM(sobsgroups(jgroup)%ssurfdata%caddvars(jadd )) == &
+                           & TRIM(sobsgroups(jgroup)%ssurfdata%caddvars(jadd2)) ) THEN
+                           sladd%inum = sladd%inum - 1
+                           ll_write(jadd) = .FALSE.
+                        ENDIF
+                     END DO
+                  END DO
+               ENDIF
+               IF ( sladd%inum > 0 ) THEN
+                  ALLOCATE( sladd%ipoint(sladd%inum),                                   &
+                     &      sladd%cdname(sladd%inum),                                   &
+                     &      sladd%cdlong(sladd%inum,sobsgroups(jgroup)%ssurfdata%nvar), &
+                     &      sladd%cdunit(sladd%inum,sobsgroups(jgroup)%ssurfdata%nvar) )
+                  jadd2 = 0
+                  DO jadd = 1, sobsgroups(jgroup)%ssurfdata%nadd
+                     IF ( ll_write(jadd) ) THEN
+                        jadd2 = jadd2 + 1
+                        sladd%ipoint(jadd2) = jadd
+                        sladd%cdname(jadd2) = sobsgroups(jgroup)%ssurfdata%caddvars(jadd)
+                        DO jvar = 1, sobsgroups(jgroup)%ssurfdata%nvar
+                           sladd%cdlong(jadd2,jvar) = sobsgroups(jgroup)%ssurfdata%caddlong(jadd,jvar)
+                           sladd%cdunit(jadd2,jvar) = sobsgroups(jgroup)%ssurfdata%caddunit(jadd,jvar)
+                        END DO
+                     ENDIF
+                  END DO
+               ENDIF
+               DEALLOCATE( ll_write )
+               
+               slext%inum = sobsgroups(jgroup)%ssurfdata%nextra
+               ALLOCATE( ll_write(sobsgroups(jgroup)%ssurfdata%nextra) )
+               ll_write(:) = .TRUE.
+               IF ( (sobsgroups(jgroup)%nextvars > 0) .AND. &
+                  & (sobsgroups(jgroup)%ssurfdata%nextra > sobsgroups(jgroup)%nextvars) ) THEN
+                  DO jext = sobsgroups(jgroup)%nextvars + 1, sobsgroups(jgroup)%ssurfdata%nextra
+                     DO jext2 = 1, sobsgroups(jgroup)%nextvars
+                        IF ( TRIM(sobsgroups(jgroup)%ssurfdata%cextvars(jext )) == &
+                           & TRIM(sobsgroups(jgroup)%ssurfdata%cextvars(jext2)) ) THEN
+                           slext%inum = slext%inum - 1
+                           ll_write(jext) = .FALSE.
+                        ENDIF
+                     END DO
+                  END DO
+               ENDIF
+               IF ( slext%inum > 0 ) THEN
+                  ALLOCATE( slext%ipoint(slext%inum),   &
+                     &      slext%cdname(slext%inum),   &
+                     &      slext%cdlong(slext%inum,1), &
+                     &      slext%cdunit(slext%inum,1) )
+                  jext2 = 0
+                  DO jext = 1, sobsgroups(jgroup)%ssurfdata%nextra
+                     IF ( ll_write(jext) ) THEN
+                        jext2 = jext2 + 1
+                        slext%ipoint(jext2)   = jext
+                        slext%cdname(jext2)   = sobsgroups(jgroup)%ssurfdata%cextvars(jext)
+                        slext%cdlong(jext2,1) = sobsgroups(jgroup)%ssurfdata%cextlong(jext)
+                        slext%cdunit(jext2,1) = sobsgroups(jgroup)%ssurfdata%cextunit(jext)
+                     ENDIF
+                  END DO
+               ENDIF
+               DEALLOCATE( ll_write )
+
+               CALL obs_wri_surf( sobsgroups(jgroup)%ssurfdata, sobsgroups(jgroup)%cgroupname, sladd, slext )
+
+               IF ( sladd%inum > 0 ) THEN
+                  DEALLOCATE( sladd%ipoint, sladd%cdname, sladd%cdlong, sladd%cdunit )
+               ENDIF
+               IF ( slext%inum > 0 ) THEN
+                  DEALLOCATE( slext%ipoint, slext%cdname, slext%cdlong, slext%cdunit )
+               ENDIF
+
+            ENDIF
+
+         ENDIF
+
+      END DO
+
+      IF( ln_timing )   CALL timing_stop('dia_obs_wri')
 
    END SUBROUTINE dia_obs_wri
-
-   SUBROUTINE dia_obs_dealloc
-      IMPLICIT NONE
-      !!----------------------------------------------------------------------
-      !!                    *** ROUTINE dia_obs_dealloc ***
-      !!
-      !!  ** Purpose : To deallocate data to enable the obs_oper online loop.
-      !!               Specifically: dia_obs_init --> dia_obs --> dia_obs_wri
-      !!
-      !!  ** Method : Clean up various arrays left behind by the obs_oper.
-      !!
-      !!  ** Action :
-      !!
-      !!----------------------------------------------------------------------
-      ! obs_grid deallocation
-      CALL obs_grid_deallocate
-
-      ! diaobs deallocation
-      IF ( nproftypes > 0 ) &
-         &   DEALLOCATE( cobstypesprof, profdata, profdataqc, nvarsprof, nextrprof )
-
-      IF ( nsurftypes > 0 ) &
-         &   DEALLOCATE( cobstypessurf, surfdata, surfdataqc, nvarssurf, nextrsurf, &
-         &               n2dintsurf, zavglamscl, zavgphiscl, lfpindegs, llnightav )
-
-   END SUBROUTINE dia_obs_dealloc
 
    SUBROUTINE calc_date( kstp, ddobs )
@@ -895,119 +1044,4 @@
 
    END SUBROUTINE fin_date
-   
-    SUBROUTINE obs_settypefiles( ntypes, jpmaxnfiles, jtype, ctypein, &
-       &                         cfilestype, ifiles, cobstypes, cfiles )
-
-    INTEGER, INTENT(IN) :: ntypes      ! Total number of obs types
-    INTEGER, INTENT(IN) :: jpmaxnfiles ! Maximum number of files allowed for each type
-    INTEGER, INTENT(IN) :: jtype       ! Index of the current type of obs
-    INTEGER, DIMENSION(ntypes), INTENT(INOUT) :: &
-       &                   ifiles      ! Out appended number of files for this type
-
-    CHARACTER(len=6), INTENT(IN) :: ctypein 
-    CHARACTER(len=128), DIMENSION(jpmaxnfiles), INTENT(IN) :: &
-       &                   cfilestype  ! In list of files for this obs type
-    CHARACTER(len=6), DIMENSION(ntypes), INTENT(INOUT) :: &
-       &                   cobstypes   ! Out appended list of obs types
-    CHARACTER(len=128), DIMENSION(ntypes, jpmaxnfiles), INTENT(INOUT) :: &
-       &                   cfiles      ! Out appended list of files for all types
-
-    !Local variables
-    INTEGER :: jfile
-
-    cfiles(jtype,:) = cfilestype(:)
-    cobstypes(jtype) = ctypein
-    ifiles(jtype) = 0
-    DO jfile = 1, jpmaxnfiles
-       IF ( trim(cfiles(jtype,jfile)) /= '' ) &
-                 ifiles(jtype) = ifiles(jtype) + 1
-    END DO
-
-    IF ( ifiles(jtype) == 0 ) THEN
-         CALL ctl_stop( 'Logical for observation type '//TRIM(ctypein)//   &
-            &           ' set to true but no files available to read' )
-    ENDIF
-
-    IF(lwp) THEN    
-       WRITE(numout,*) '             '//cobstypes(jtype)//' input observation file names:'
-       DO jfile = 1, ifiles(jtype)
-          WRITE(numout,*) '                '//TRIM(cfiles(jtype,jfile))
-       END DO
-    ENDIF
-
-    END SUBROUTINE obs_settypefiles
-
-    SUBROUTINE obs_setinterpopts( ntypes, jtype, ctypein,             &
-               &                  n2dint_default, n2dint_type,        &
-               &                  zavglamscl_type, zavgphiscl_type,   &
-               &                  lfp_indegs_type, lavnight_type,     &
-               &                  n2dint, zavglamscl, zavgphiscl,     &
-               &                  lfpindegs, lavnight )
-
-    INTEGER, INTENT(IN)  :: ntypes             ! Total number of obs types
-    INTEGER, INTENT(IN)  :: jtype              ! Index of the current type of obs
-    INTEGER, INTENT(IN)  :: n2dint_default     ! Default option for interpolation type
-    INTEGER, INTENT(IN)  :: n2dint_type        ! Option for interpolation type
-    REAL(wp), INTENT(IN) :: &
-       &                    zavglamscl_type, & !E/W diameter of obs footprint for this type
-       &                    zavgphiscl_type    !N/S diameter of obs footprint for this type
-    LOGICAL, INTENT(IN)  :: lfp_indegs_type    !T=> footprint in degrees, F=> in metres
-    LOGICAL, INTENT(IN)  :: lavnight_type      !T=> obs represent night time average
-    CHARACTER(len=6), INTENT(IN) :: ctypein 
-
-    INTEGER, DIMENSION(ntypes), INTENT(INOUT) :: &
-       &                    n2dint 
-    REAL(wp), DIMENSION(ntypes), INTENT(INOUT) :: &
-       &                    zavglamscl, zavgphiscl
-    LOGICAL, DIMENSION(ntypes), INTENT(INOUT) :: &
-       &                    lfpindegs, lavnight
-
-    lavnight(jtype) = lavnight_type
-
-    IF ( (n2dint_type >= 1) .AND. (n2dint_type <= 6) ) THEN
-       n2dint(jtype) = n2dint_type
-    ELSE
-       n2dint(jtype) = n2dint_default
-    ENDIF
-
-    ! For averaging observation footprints set options for size of footprint 
-    IF ( (n2dint(jtype) > 4) .AND. (n2dint(jtype) <= 6) ) THEN
-       IF ( zavglamscl_type > 0._wp ) THEN
-          zavglamscl(jtype) = zavglamscl_type
-       ELSE
-          CALL ctl_stop( 'Incorrect value set for averaging footprint '// &
-                         'scale (zavglamscl) for observation type '//TRIM(ctypein) )      
-       ENDIF
-
-       IF ( zavgphiscl_type > 0._wp ) THEN
-          zavgphiscl(jtype) = zavgphiscl_type
-       ELSE
-          CALL ctl_stop( 'Incorrect value set for averaging footprint '// &
-                         'scale (zavgphiscl) for observation type '//TRIM(ctypein) )      
-       ENDIF
-
-       lfpindegs(jtype) = lfp_indegs_type 
-
-    ENDIF
-
-    ! Write out info 
-    IF(lwp) THEN
-       IF ( n2dint(jtype) <= 4 ) THEN
-          WRITE(numout,*) '             '//TRIM(ctypein)// &
-             &            ' model counterparts will be interpolated horizontally'
-       ELSE IF ( n2dint(jtype) <= 6 ) THEN
-          WRITE(numout,*) '             '//TRIM(ctypein)// &
-             &            ' model counterparts will be averaged horizontally'
-          WRITE(numout,*) '             '//'    with E/W scale: ',zavglamscl(jtype)
-          WRITE(numout,*) '             '//'    with N/S scale: ',zavgphiscl(jtype)
-          IF ( lfpindegs(jtype) ) THEN
-              WRITE(numout,*) '             '//'    (in degrees)'
-          ELSE
-              WRITE(numout,*) '             '//'    (in metres)'
-          ENDIF
-       ENDIF
-    ENDIF
-
-    END SUBROUTINE obs_setinterpopts
 
 END MODULE diaobs
Index: NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_bias.F90
===================================================================
--- NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_bias.F90	(revision 15799)
+++ NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_bias.F90	(revision 15799)
@@ -0,0 +1,262 @@
+MODULE obs_bias
+   !!======================================================================
+   !!                       ***  MODULE obs_bias  ***
+   !! Observation diagnostics: Read the bias for observation data
+   !!======================================================================
+   !!----------------------------------------------------------------------
+   !!   obs_app_bias : Driver for reading and applying the bias
+   !!----------------------------------------------------------------------
+   !! * Modules used   
+   USE par_kind, ONLY : &       ! Precision variables
+      & wp
+   USE par_oce, ONLY : &        ! Domain parameters
+      & jpi, &
+      & jpj
+   USE in_out_manager, ONLY : & ! I/O manager
+      & lwp,    &
+      & numout 
+   USE obs_surf_def             ! Surface observation definitions
+   USE dom_oce, ONLY : &        ! Domain variables
+      & tmask, &
+      & gphit, &
+      & glamt
+   USE obs_inter_h2d
+   USE obs_utils               ! Various observation tools
+   USE obs_inter_sup
+   IMPLICIT NONE
+   !! * Routine accessibility
+   PRIVATE
+   PUBLIC obs_app_bias     ! Read the observation bias
+CONTAINS
+   SUBROUTINE obs_app_bias( obsdata, kvar, k2dint, knumtypes, &
+                            cl_bias_files, cd_biasname,       &
+                            ld_extvar )
+      !!---------------------------------------------------------------------
+      !!
+      !!                   *** ROUTINE obs_app_bias ***
+      !!
+      !! ** Purpose : Read bias data from files and apply correction to
+      !!              observations
+      !!
+      !! ** Method  :
+      !!
+      !! ** Action  :
+      !!
+      !! References :
+      !!
+      !! History : 
+      !!      ! :  2014-08 (J. While) Bias correction code for SST obs,
+      !!      !                       based on obs_rea_altbias
+      !!      ! :  2021-07 (D. Ford)  Renamed obs_app_bias and made generic
+      !!----------------------------------------------------------------------
+      !! * Modules used
+      USE iom
+      USE netcdf
+
+      !! * Arguments
+      TYPE(obs_surf), INTENT(INOUT) :: obsdata       ! Observation data
+      INTEGER, INTENT(IN) :: kvar    ! Index of obs type being bias corrected
+      INTEGER, INTENT(IN) :: k2dint
+      INTEGER, INTENT(IN) :: knumtypes !number of bias types to read in
+      CHARACTER(LEN=128), DIMENSION(knumtypes), INTENT(IN) :: &
+                          cl_bias_files !List of files to read
+      CHARACTER(LEN=128), INTENT(IN) :: cd_biasname ! Variable name in file
+      LOGICAL, OPTIONAL, INTENT(IN)  :: ld_extvar   ! If T correct an extra var
+
+      !! * Local declarations
+      INTEGER :: jobs         ! Obs loop variable
+      INTEGER :: iico         ! Grid point indices
+      INTEGER :: ijco
+      INTEGER :: jt
+      INTEGER, DIMENSION(knumtypes) :: &
+         & ibiastypes             ! Array of the bias types in each file
+      REAL(wp), DIMENSION(jpi,jpj,knumtypes) :: & 
+         & z_obsbias              ! Array to store the bias values
+      REAL(wp), DIMENSION(jpi,jpj) :: & 
+         & z_obsbias_2d           ! Array to store the bias values   
+      REAL(wp), DIMENSION(1) :: &
+         & zext, &
+         & zobsmask
+      REAL(wp), DIMENSION(2,2,1) :: &
+         & zweig
+      REAL(wp), DIMENSION(:,:,:), ALLOCATABLE :: &
+         & zmask, &
+         & zglam, &
+         & zgphi
+      REAL(wp), DIMENSION(:,:,:), ALLOCATABLE :: &
+         & zmask_tmp, &
+         & zglam_tmp, &
+         & zgphi_tmp   
+      REAL(wp), ALLOCATABLE, DIMENSION(:,:,:) ::  zbias   
+      REAL(wp) :: zlam
+      REAL(wp) :: zphi
+      INTEGER, DIMENSION(:,:,:), ALLOCATABLE :: &
+         & igrdi, &
+         & igrdj
+      INTEGER, DIMENSION(:,:,:), ALLOCATABLE :: &
+         & igrdi_tmp, &
+         & igrdj_tmp   
+      INTEGER :: numobsbias
+      INTEGER(KIND=NF90_INT) :: ifile_source     
+      INTEGER :: incfile
+      INTEGER :: jtype
+      INTEGER :: iret 
+      INTEGER :: inumtype
+      LOGICAL :: ll_extvar
+
+      IF ( PRESENT(ld_extvar) ) THEN
+         ll_extvar = ld_extvar
+      ELSE
+         ll_extvar = .FALSE.
+      ENDIF
+      IF ( ll_extvar .AND. ( knumtypes /= 1 ) ) THEN
+         CALL ctl_stop( 'obs_app_bias: If correcting an extra variable', &
+            &           '              knumtypes must be 1' )
+      ENDIF
+      
+      IF (lwp) WRITE(numout,*) 
+      IF (lwp) WRITE(numout,*) 'obs_app_bias : '
+      IF (lwp) WRITE(numout,*) '----------------- '
+      IF ( ll_extvar ) THEN
+         IF (lwp) WRITE(numout,*) 'Read observation bias for ', TRIM(obsdata%cextvars(kvar))
+      ELSE
+         IF (lwp) WRITE(numout,*) 'Read observation bias for ', TRIM(obsdata%cvars(kvar))
+      ENDIF
+
+      ! Open and read the files
+      z_obsbias(:,:,:) = 0.0_wp
+      DO jtype = 1, knumtypes
+     
+         numobsbias = 0
+         IF (lwp) WRITE(numout,*) 'Opening ', cl_bias_files(jtype)
+         CALL iom_open( cl_bias_files(jtype), numobsbias, ldstop=.FALSE. )       
+         IF (numobsbias > 0) THEN
+     
+            IF ( .NOT. ll_extvar ) THEN
+               !Read the bias type from the file
+               !No IOM get attribute command at time of writing, 
+               !so have to use NETCDF
+               !routines directly - should be upgraded in the future
+               iret = NF90_OPEN(TRIM(cl_bias_files(jtype)), NF90_NOWRITE, incfile)
+               IF ( .NOT. ll_extvar ) THEN
+                  iret=NF90_GET_ATT( incfile, NF90_GLOBAL, TRIM(obsdata%cvars(kvar))//"_source", &
+                                    ifile_source )
+                  ibiastypes(jtype) = ifile_source
+               ENDIF
+               iret = NF90_CLOSE(incfile)
+               IF ( iret /= 0  ) CALL ctl_stop( &
+                  'obs_app_bias : Cannot read bias type from file '// &
+                  cl_bias_files(jtype) )
+            ENDIF
+
+            ! Get the bias data
+            CALL iom_get( numobsbias, jpdom_data, TRIM(cd_biasname), z_obsbias_2d(:,:), 1 )
+            z_obsbias(:,:,jtype) = z_obsbias_2d(:,:)       
+            ! Close the file
+            CALL iom_close(numobsbias)       
+         ELSE
+            CALL ctl_stop('obs_app_bias: File '// & 
+                           TRIM( cl_bias_files(jtype) )//' Not found')
+         ENDIF
+      END DO
+           
+      ! Interpolate the bias already on the model grid at the observation point
+      ALLOCATE( &
+         & igrdi(2,2,obsdata%nsurf), &
+         & igrdj(2,2,obsdata%nsurf), &
+         & zglam(2,2,obsdata%nsurf), &
+         & zgphi(2,2,obsdata%nsurf), &
+         & zmask(2,2,obsdata%nsurf)  )
+       
+      DO jobs = 1, obsdata%nsurf 
+         igrdi(1,1,jobs) = obsdata%mi(jobs)-1
+         igrdj(1,1,jobs) = obsdata%mj(jobs)-1
+         igrdi(1,2,jobs) = obsdata%mi(jobs)-1
+         igrdj(1,2,jobs) = obsdata%mj(jobs)
+         igrdi(2,1,jobs) = obsdata%mi(jobs)
+         igrdj(2,1,jobs) = obsdata%mj(jobs)-1
+         igrdi(2,2,jobs) = obsdata%mi(jobs)
+         igrdj(2,2,jobs) = obsdata%mj(jobs)
+      END DO
+      CALL obs_int_comm_2d( 2, 2, obsdata%nsurf, jpi, jpj, &
+         &                  igrdi, igrdj, glamt, zglam )
+      CALL obs_int_comm_2d( 2, 2, obsdata%nsurf, jpi, jpj, &
+         &                  igrdi, igrdj, gphit, zgphi )
+      CALL obs_int_comm_2d( 2, 2, obsdata%nsurf, jpi, jpj, &
+         &                  igrdi, igrdj, tmask(:,:,1), zmask )
+      DO jtype = 1, knumtypes
+         
+         !Find the number observations of type and allocate tempory arrays
+         inumtype = COUNT( obsdata%ntyp(:) == ibiastypes(jtype) )
+         ALLOCATE( &
+            & igrdi_tmp(2,2,inumtype), &
+            & igrdj_tmp(2,2,inumtype), &
+            & zglam_tmp(2,2,inumtype), &
+            & zgphi_tmp(2,2,inumtype), &
+            & zmask_tmp(2,2,inumtype), &
+            & zbias( 2,2,inumtype ) )
+         jt = 1
+         DO jobs = 1, obsdata%nsurf 
+            IF ( obsdata%ntyp(jobs) == ibiastypes(jtype) ) THEN
+               igrdi_tmp(:,:,jt) = igrdi(:,:,jobs) 
+               igrdj_tmp(:,:,jt) = igrdj(:,:,jobs)
+               zglam_tmp(:,:,jt) = zglam(:,:,jobs)
+               zgphi_tmp(:,:,jt) = zgphi(:,:,jobs)
+               zmask_tmp(:,:,jt) = zmask(:,:,jobs)
+               jt = jt +1
+            ENDIF
+         END DO
+                         
+         CALL obs_int_comm_2d( 2, 2, inumtype, jpi, jpj, &
+               &           igrdi_tmp(:,:,:), igrdj_tmp(:,:,:), &
+               &           z_obsbias(:,:,jtype), zbias(:,:,:) )
+         jt = 1
+         DO jobs = 1, obsdata%nsurf
+            IF ( ( obsdata%ntyp(jobs) == ibiastypes(jtype) ) .OR. &
+               &  ll_extvar ) THEN
+               zlam = obsdata%rlam(jobs)
+               zphi = obsdata%rphi(jobs)
+               iico = obsdata%mi(jobs)
+               ijco = obsdata%mj(jobs)         
+               CALL obs_int_h2d_init( 1, 1, k2dint, zlam, zphi,         &
+                  &                   zglam_tmp(:,:,jt), &
+                  &                   zgphi_tmp(:,:,jt), &
+                  &                   zmask_tmp(:,:,jt), zweig, zobsmask )
+               CALL obs_int_h2d( 1, 1, zweig, zbias(:,:,jt),  zext )
+               ! adjust observations with bias field
+               IF ( ll_extvar ) THEN
+                  obsdata%rext(jobs,kvar) = obsdata%rext(jobs,kvar) - zext(1)
+               ELSE
+                  obsdata%robs(jobs,kvar) = obsdata%robs(jobs,kvar) - zext(1)
+               ENDIF
+               jt = jt + 1
+            ENDIF
+         END DO 
+               
+         !Deallocate arrays
+         DEALLOCATE( &
+         & igrdi_tmp, &
+         & igrdj_tmp, &
+         & zglam_tmp, &
+         & zgphi_tmp, &
+         & zmask_tmp, &
+         & zbias )           
+      END DO
+      DEALLOCATE( &
+         & igrdi, &
+         & igrdj, &
+         & zglam, &
+         & zgphi, &
+         & zmask )
+
+      IF(lwp) THEN
+         WRITE(numout,*) " "
+         WRITE(numout,*) "Bias correction applied successfully"
+         IF ( .NOT. ll_extvar ) THEN
+            WRITE(numout,*) "Obs types: ", ibiastypes(:), &
+               &            " Have all been bias corrected"
+         ENDIF
+      ENDIF
+   END SUBROUTINE obs_app_bias
+ 
+END MODULE obs_bias
Index: NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_grid.F90
===================================================================
--- NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_grid.F90	(revision 15731)
+++ NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_grid.F90	(revision 15799)
@@ -687,5 +687,5 @@
       IF (ln_grid_search_lookup) THEN
          
-         WRITE(numout,*) 'Calling obs_grid_setup'
+         IF(lwp) WRITE(numout,*) 'Calling obs_grid_setup'
          
          IF(lwp) WRITE(numout,*)
@@ -724,5 +724,5 @@
             ! initially assume size is as defined (to be fixed)
             
-            WRITE(numout,*) 'Reading: ',cfname
+            IF(lwp) WRITE(numout,*) 'Reading: ',cfname
             
             CALL chkerr( nf90_open( TRIM( cfname ), nf90_nowrite, idfile ), &
Index: NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_group_def.F90
===================================================================
--- NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_group_def.F90	(revision 15799)
+++ NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_group_def.F90	(revision 15799)
@@ -0,0 +1,521 @@
+MODULE obs_group_def
+   !!=====================================================================
+   !!                       ***  MODULE obs_group_def  ***
+   !! Observation diagnostics: Routines specific to observation groups
+   !!=====================================================================
+   !! History : 4.0  !  2021-06  (D Ford)  Original code
+   !!----------------------------------------------------------------------
+   !!   obs_group_alloc         : allocate observation group types
+   !!   obs_group_dealloc       : deallocate observation group types
+   !!   obs_group_read_namelist : read observation group namelists
+   !!   obs_group_check         : check observation group options
+   !!----------------------------------------------------------------------
+
+   !! * Modules used
+   USE iom                ! In/out manager
+   USE par_kind, ONLY : & ! Precision variables
+      & wp
+   USE obs_surf_def       ! Surface data definitions
+   USE obs_profiles_def   ! Profile data definitions
+   USE tradmp, ONLY : &   ! Damping to climatology
+      & ln_tradmp
+   USE obs_grid, ONLY : & ! Use global distribution of observations
+      & ln_grid_global
+
+   IMPLICIT NONE
+
+   !! * Routine/type accessibility
+   PRIVATE
+
+   PUBLIC &
+      & obs_group,               &
+      & obs_group_alloc,         &
+      & obs_group_dealloc,       &
+      & obs_group_read_namelist, &
+      & obs_group_check
+
+   !! * Shared Module variables
+   INTEGER, PARAMETER :: jpmaxntypes = 1000   ! Maximum number of obs types for each obs group
+   INTEGER, PARAMETER :: jpmaxnfiles = 1000   ! Maximum number of files for each obs group
+
+   INTEGER, PARAMETER, PUBLIC :: imaxavtypes = 20   !: Max number of daily avgd obs types
+   
+   ! Expected names for observation types with special behaviours (not needed for all observation types)
+   CHARACTER(LEN=8), PUBLIC :: cobsname_uvel = 'UVEL' ! Expected variable name for U velocity (2D or 3D)
+   CHARACTER(LEN=8), PUBLIC :: cobsname_vvel = 'VVEL' ! Expected variable name for V velocity (2D or 3D)
+   CHARACTER(LEN=8), PUBLIC :: cobsname_sla  = 'SLA'  ! Expected variable name for sea level anomaly
+   CHARACTER(LEN=8), PUBLIC :: cobsname_fbd  = 'FBD'  ! Expected variable name for sea ice freeboard
+   CHARACTER(LEN=8), PUBLIC :: cobsname_t3d  = 'POTM' ! Expected variable name for 3D temperature
+   CHARACTER(LEN=8), PUBLIC :: cobsname_s3d  = 'PSAL' ! Expected variable name for 3D salinity
+   CHARACTER(LEN=8), PUBLIC :: cobsname_t2d  = 'SST'  ! Expected variable name for 2D temperature
+   CHARACTER(LEN=8), PUBLIC :: cobsname_s2d  = 'SSS'  ! Expected variable name for 2D salinity
+
+   !! * Type definition for observation groups
+   TYPE obs_group
+      !
+      CHARACTER(LEN=25)                             :: cgroupname    !: Name of obs group (for stdout)
+      CHARACTER(LEN=8),   DIMENSION(:), ALLOCATABLE :: cobstypes     !: Observation types to read from files
+      CHARACTER(LEN=128), DIMENSION(:), ALLOCATABLE :: cobsfiles     !: Observation file names
+      CHARACTER(LEN=128), DIMENSION(:), ALLOCATABLE :: cobsbiasfiles !: Bias input file names
+      CHARACTER(LEN=128)                            :: cbiasvarname  !: Bias variable name in input file
+      CHARACTER(LEN=128)                            :: caltbiasfile  !: Altimeter bias input file name
+      CHARACTER(LEN=1)                              :: cgrid         !: Grid type (T,U,V)
+      !
+      INTEGER,            DIMENSION(:), ALLOCATABLE :: nprofdavtypes !: Profile data types representing a daily average
+      !
+      INTEGER  :: nobstypes          !: Number of observation types
+      INTEGER  :: nobsfiles          !: Number of observation files
+      INTEGER  :: nobsbiasfiles      !: Number of bias files
+      INTEGER  :: nbiasvar           !: Index of observation type to be bias corrected
+      INTEGER  :: navtypes           !: Number of profile data types representing a daily average
+      INTEGER  :: nextvars           !: Number of extra variables in addition to any in input files
+      INTEGER  :: naddvars           !: Number of additional variables in addition to any in input files
+      INTEGER  :: n1dint             !: Type of vertical interpolation method
+      INTEGER  :: n2dint             !: Type of horizontal interpolation method
+      INTEGER  :: nmsshc             !: MSSH correction scheme
+      INTEGER  :: nadd_ssh           !: Index of additional variable representing SSH
+      INTEGER  :: next_mdt           !: Index of extra variable representing MDT
+      INTEGER  :: nadd_fbd           !: Index of additional variable representing ice freeboard
+      INTEGER  :: next_snow          !: Index of extra variable representing snow thickness
+      INTEGER  :: nadd_clm           !: Index of additional variable representing climatology
+      !
+      LOGICAL  :: lenabled           !: Logical switch for group being processed and not ignored
+      LOGICAL  :: lsurf              !: Logical switch for surface data
+      LOGICAL  :: lprof              !: Logical switch for profile data
+      LOGICAL  :: lvel               !: Logical switch for velocity data
+      LOGICAL  :: lsla               !: Logical switch for SLA data
+      LOGICAL  :: lfbd               !: Logical switch for ice freeboard data
+      LOGICAL  :: laltbias           !: Logical switch for altimeter bias correction
+      LOGICAL  :: lobsbias           !: Logical switch for bias correction
+      LOGICAL  :: lnea               !: Logical switch for rejecting observations near land
+      LOGICAL  :: lbound_reject      !: Logical switch for rejecting obs near the boundary
+      LOGICAL  :: lignmis            !: Logical switch for ignoring missing files
+      LOGICAL  :: lall_at_all        !: Logical switch for computing all model variables at all obs points
+      LOGICAL  :: lnight             !: Logical switch for calculating night-time average
+      LOGICAL  :: ltime_mean_bkg     !: Logical switch for applying time mean of background (e.g. to remove tidal signal)
+      LOGICAL  :: loutput_clim       !: Logical switch for outputting climatological temperature/salinity
+      LOGICAL  :: lfp_indegs         !: Logical: T=> averaging footprint is in degrees, F=> in metres
+      !
+      REAL(wp) :: ravglamscl         !: E/W diameter of observation footprint (metres/degrees)
+      REAL(wp) :: ravgphiscl         !: N/S diameter of observation footprint (metres/degrees)
+      REAL(wp) :: rmdtcorr           !: MDT correction
+      REAL(wp) :: rmdtcutoff         !: MDT cutoff for computed correction
+      REAL(wp) :: rtime_mean_period  !: Meaning period if ltime_mean_bkg
+      !
+      REAL(wp), POINTER, DIMENSION(:,:,:)   :: rglam  !: Longitudes
+      REAL(wp), POINTER, DIMENSION(:,:,:)   :: rgphi  !: Latitudes
+      REAL(wp), POINTER, DIMENSION(:,:,:,:) :: rmask  !: Land/sea masks
+      !
+      TYPE(obs_surf) :: ssurfdata    !: Initial surface data
+      TYPE(obs_surf) :: ssurfdataqc  !: Surface data after quality control
+      TYPE(obs_prof) :: sprofdata    !: Initial profile data
+      TYPE(obs_prof) :: sprofdataqc  !: Profile data after quality control
+      !
+   END TYPE
+
+CONTAINS
+
+   SUBROUTINE obs_group_alloc( sdobsgroup )
+      !!----------------------------------------------------------------------
+      !!                     ***  ROUTINE obs_group_alloc  ***
+      !!
+      !! ** Purpose : - Allocate data for observation group types
+      !!
+      !! ** Method  : - Allocate arrays
+      !!
+      !! ** Action  : - Allocate arrays
+      !!
+      !!----------------------------------------------------------------------
+      !! * Arguments
+      TYPE(obs_group), INTENT(INOUT) :: sdobsgroup ! Obs group to be allocated
+      !!----------------------------------------------------------------------
+
+      ALLOCATE( sdobsgroup%cobstypes    (sdobsgroup%nobstypes            ), &
+         &      sdobsgroup%cobsfiles    (sdobsgroup%nobsfiles            ), &
+         &      sdobsgroup%cobsbiasfiles(sdobsgroup%nobsbiasfiles        ), &
+         &      sdobsgroup%nprofdavtypes(sdobsgroup%navtypes             ), &
+         &      sdobsgroup%rglam        (jpi,jpj,    sdobsgroup%nobstypes), &
+         &      sdobsgroup%rgphi        (jpi,jpj,    sdobsgroup%nobstypes), &
+         &      sdobsgroup%rmask        (jpi,jpj,jpk,sdobsgroup%nobstypes) )
+
+   END SUBROUTINE obs_group_alloc
+
+
+   SUBROUTINE obs_group_dealloc( sdobsgroup )
+      !!----------------------------------------------------------------------
+      !!                     ***  ROUTINE obs_group_dealloc  ***
+      !!
+      !! ** Purpose : - Deallocate data for observation group types
+      !!
+      !! ** Method  : - Deallocate arrays
+      !!
+      !! ** Action  : - Deallocate arrays
+      !!
+      !!----------------------------------------------------------------------
+      !! * Arguments
+      TYPE(obs_group), INTENT(INOUT) :: sdobsgroup ! Obs group to be deallocated
+      !!----------------------------------------------------------------------
+
+      DEALLOCATE( sdobsgroup%cobstypes,     &
+         &        sdobsgroup%cobsfiles,     &
+         &        sdobsgroup%cobsbiasfiles, &
+         &        sdobsgroup%nprofdavtypes, &
+         &        sdobsgroup%rglam,         &
+         &        sdobsgroup%rgphi,         &
+         &        sdobsgroup%rmask )
+
+   END SUBROUTINE obs_group_dealloc
+
+
+   SUBROUTINE obs_group_read_namelist( sdobsgroup )
+      !!----------------------------------------------------------------------
+      !!                     ***  ROUTINE obs_group_read_namelist  ***
+      !!
+      !! ** Purpose : - Read namelist for observation group types
+      !!
+      !! ** Method  : - Read namelist
+      !!
+      !! ** Action  : - Read namelist
+      !!
+      !!----------------------------------------------------------------------
+      !! * Arguments
+      TYPE(obs_group), INTENT(INOUT) :: sdobsgroup ! Obs group to be populated
+      !! * Local variables
+      INTEGER :: ios                               ! Status for namelist read
+      INTEGER :: itype, ifile                      ! Loop counters
+      INTEGER :: jtype, jfile                      ! Loop counters
+      !
+      CHARACTER(LEN=128)                         :: cn_groupname
+      CHARACTER(LEN=8),   DIMENSION(jpmaxntypes) :: cn_obstypes
+      CHARACTER(LEN=128), DIMENSION(jpmaxnfiles) :: cn_obsfiles
+      CHARACTER(LEN=128), DIMENSION(jpmaxnfiles) :: cn_obsbiasfiles
+      CHARACTER(LEN=128)                         :: cn_type_to_biascorrect
+      CHARACTER(LEN=128)                         :: cn_obsbiasfile_varname
+      CHARACTER(LEN=128)                         :: cn_altbiasfile
+      INTEGER,            DIMENSION(imaxavtypes) :: nn_profdavtypes
+      INTEGER                                    :: nn_1dint
+      INTEGER                                    :: nn_2dint
+      INTEGER                                    :: nn_msshc
+      LOGICAL                                    :: ln_enabled
+      LOGICAL                                    :: ln_surf
+      LOGICAL                                    :: ln_prof
+      LOGICAL                                    :: ln_altbias
+      LOGICAL                                    :: ln_obsbias
+      LOGICAL                                    :: ln_nea
+      LOGICAL                                    :: ln_bound_reject
+      LOGICAL                                    :: ln_ignmis
+      LOGICAL                                    :: ln_all_at_all
+      LOGICAL                                    :: ln_night
+      LOGICAL                                    :: ln_time_mean_bkg
+      LOGICAL                                    :: ln_output_clim
+      LOGICAL                                    :: ln_fp_indegs
+      REAL(wp)                                   :: rn_avglamscl
+      REAL(wp)                                   :: rn_avgphiscl
+      REAL(wp)                                   :: rn_mdtcorr
+      REAL(wp)                                   :: rn_mdtcutoff
+      REAL(wp)                                   :: rn_time_mean_period
+      !!
+      NAMELIST/namobs_dta/cn_groupname, ln_prof, ln_surf, ln_enabled,           &
+         &                cn_obsfiles, cn_obstypes, ln_nea, ln_bound_reject,    &
+         &                ln_ignmis, nn_2dint, nn_1dint, nn_profdavtypes,       &
+         &                ln_fp_indegs, rn_avglamscl, rn_avgphiscl, ln_obsbias, &
+         &                cn_obsbiasfiles, cn_type_to_biascorrect,              &
+         &                cn_obsbiasfile_varname, ln_night, ln_time_mean_bkg,   &
+         &                rn_time_mean_period, ln_altbias, cn_altbiasfile,      &
+         &                nn_msshc, rn_mdtcorr, rn_mdtcutoff, ln_all_at_all,    &
+         &                ln_output_clim
+      !!----------------------------------------------------------------------
+
+      cn_obstypes(:)     = ''
+      cn_obsfiles(:)     = ''
+      cn_obsbiasfiles(:) = ''
+      nn_profdavtypes(:) = -1
+
+      ! There is only one namobs_dta block in namelist_ref -> use it for each group so we do a rewind
+      REWIND(numnam_ref)
+      READ  ( numnam_ref, namobs_dta, IOSTAT = ios, ERR = 901)
+901   IF( ios /= 0 )   CALL ctl_nam ( ios , 'namobs_dta in reference namelist' )
+
+      ! Read namobs_dta from namelist_cfg
+      ! WARNING: we don't do a rewind here, each group reads its own namobs_dta block one after another
+      READ  ( numnam_cfg, namobs_dta, IOSTAT = ios, ERR = 902 )
+902   IF( ios >  0 )   CALL ctl_nam ( ios , 'namobs_dta in configuration namelist' )
+      IF(lwm) WRITE( numond, namobs_dta )
+      
+      sdobsgroup%cgroupname = cn_groupname
+      sdobsgroup%lenabled   = ln_enabled
+
+      IF (sdobsgroup%lenabled) THEN
+         sdobsgroup%nobstypes     = 0
+         sdobsgroup%nobsfiles     = 0
+         sdobsgroup%naddvars      = 0
+         sdobsgroup%nextvars      = 0
+         sdobsgroup%navtypes      = 0
+         sdobsgroup%nobsbiasfiles = 0
+         sdobsgroup%lvel          = .false.
+         sdobsgroup%lsla          = .false.
+         sdobsgroup%lfbd          = .false.
+         sdobsgroup%nadd_ssh      = 0
+         sdobsgroup%next_mdt      = 0
+         sdobsgroup%nadd_fbd      = 0
+         sdobsgroup%next_snow     = 0
+
+         DO jtype = 1, jpmaxntypes
+            IF ( TRIM(cn_obstypes(jtype)) /= '' ) THEN
+               sdobsgroup%nobstypes = sdobsgroup%nobstypes + 1
+            ENDIF
+         END DO
+         DO jfile = 1, jpmaxnfiles
+            IF ( TRIM(cn_obsfiles(jfile)) /= '' ) THEN
+               sdobsgroup%nobsfiles = sdobsgroup%nobsfiles + 1
+            ENDIF
+         END DO
+         DO jtype = 1, imaxavtypes
+            IF ( nn_profdavtypes(jtype) /= -1 ) THEN
+               sdobsgroup%navtypes = sdobsgroup%navtypes + 1
+            ENDIF
+         END DO
+         DO jfile = 1, jpmaxnfiles
+            IF ( TRIM(cn_obsbiasfiles(jfile)) /= '' ) THEN
+               sdobsgroup%nobsbiasfiles = sdobsgroup%nobsbiasfiles + 1
+            ENDIF
+         END DO
+
+         CALL obs_group_alloc( sdobsgroup )
+
+         itype = 0
+         DO jtype = 1, jpmaxntypes
+            IF ( TRIM(cn_obstypes(jtype)) /= '' ) THEN
+               itype = itype + 1
+               sdobsgroup%cobstypes(itype) = TRIM(cn_obstypes(jtype))
+               IF ( (TRIM(sdobsgroup%cobstypes(itype)) == cobsname_uvel) .OR. &
+                  & (TRIM(sdobsgroup%cobstypes(itype)) == cobsname_vvel) ) THEN
+                  sdobsgroup%lvel = .true.
+               ELSEIF ( TRIM(sdobsgroup%cobstypes(itype)) == cobsname_sla ) THEN
+                  sdobsgroup%lsla = .true.
+                  ! SSH=additional, MDT=extra
+                  sdobsgroup%naddvars = sdobsgroup%naddvars + 1
+                  sdobsgroup%nextvars = sdobsgroup%nextvars + 1
+                  sdobsgroup%nadd_ssh = sdobsgroup%naddvars
+                  sdobsgroup%next_mdt = sdobsgroup%nextvars
+               ELSEIF ( TRIM(sdobsgroup%cobstypes(itype)) == cobsname_fbd ) THEN
+                  sdobsgroup%lfbd = .true.
+                  ! freeboard=additional, snow thickness=extra
+                  sdobsgroup%naddvars  = sdobsgroup%naddvars + 1
+                  sdobsgroup%nextvars  = sdobsgroup%nextvars + 1
+                  sdobsgroup%nadd_fbd  = sdobsgroup%naddvars
+                  sdobsgroup%next_snow = sdobsgroup%nextvars
+               ENDIF
+               !
+               IF ( ln_output_clim .AND. ln_tradmp .AND. (.NOT. sdobsgroup%loutput_clim) ) THEN
+                  IF ( (TRIM(sdobsgroup%cobstypes(itype)) == cobsname_t3d) .OR. &
+                     & (TRIM(sdobsgroup%cobstypes(itype)) == cobsname_s3d) .OR. &
+                     & (TRIM(sdobsgroup%cobstypes(itype)) == cobsname_t2d) .OR. &
+                     & (TRIM(sdobsgroup%cobstypes(itype)) == cobsname_s2d) ) THEN
+                     sdobsgroup%loutput_clim = .TRUE.
+                     sdobsgroup%naddvars = sdobsgroup%naddvars + 1
+                     sdobsgroup%nadd_clm = sdobsgroup%naddvars
+                  ENDIF
+               ENDIF
+               !
+               IF (TRIM(sdobsgroup%cobstypes(itype)) == cobsname_uvel) THEN
+                  sdobsgroup%cgrid              = 'U'
+                  sdobsgroup%rglam(:,:,itype)   = glamu(:,:)
+                  sdobsgroup%rgphi(:,:,itype)   = gphiu(:,:)
+                  sdobsgroup%rmask(:,:,:,itype) = umask(:,:,:)
+               ELSEIF (TRIM(sdobsgroup%cobstypes(itype)) == cobsname_vvel) THEN
+                  sdobsgroup%cgrid              = 'V'
+                  sdobsgroup%rglam(:,:,itype)   = glamv(:,:)
+                  sdobsgroup%rgphi(:,:,itype)   = gphiv(:,:)
+                  sdobsgroup%rmask(:,:,:,itype) = vmask(:,:,:)
+               ELSE
+                  sdobsgroup%cgrid              = 'T'
+                  sdobsgroup%rglam(:,:,itype)   = glamt(:,:)
+                  sdobsgroup%rgphi(:,:,itype)   = gphit(:,:)
+                  sdobsgroup%rmask(:,:,:,itype) = tmask(:,:,:)
+               ENDIF
+            ENDIF
+         END DO
+         ifile = 0
+         DO jfile = 1, jpmaxnfiles
+            IF ( TRIM(cn_obsfiles(jfile)) /= '' ) THEN
+               ifile = ifile + 1
+               sdobsgroup%cobsfiles(ifile) = TRIM(cn_obsfiles(jfile))
+            ENDIF
+         END DO
+         itype = 0
+         DO jtype = 1, imaxavtypes
+            IF ( nn_profdavtypes(jtype) /= -1 ) THEN
+               itype = itype + 1
+               sdobsgroup%nprofdavtypes(itype) = nn_profdavtypes(jtype)
+            ENDIF
+         END DO
+         ifile = 0
+         DO jfile = 1, jpmaxnfiles
+            IF ( TRIM(cn_obsbiasfiles(jfile)) /= '' ) THEN
+               ifile = ifile + 1
+               sdobsgroup%cobsbiasfiles(ifile) = cn_obsbiasfiles(jfile)
+            ENDIF
+         END DO
+         IF ( ln_obsbias ) THEN
+            sdobsgroup%nbiasvar = -1
+            DO jtype = 1, sdobsgroup%nobstypes
+               IF ( TRIM(sdobsgroup%cobstypes(itype)) == TRIM(cn_type_to_biascorrect) ) THEN
+                  sdobsgroup%nbiasvar = jtype
+                  EXIT
+               ENDIF
+            ENDDO
+         ENDIF
+
+         sdobsgroup%caltbiasfile       = cn_altbiasfile
+         sdobsgroup%n1dint             = nn_1dint
+         sdobsgroup%n2dint             = nn_2dint
+         sdobsgroup%nmsshc             = nn_msshc
+         sdobsgroup%lsurf              = ln_surf
+         sdobsgroup%lprof              = ln_prof
+         sdobsgroup%laltbias           = ln_altbias
+         sdobsgroup%lobsbias           = ln_obsbias
+         sdobsgroup%cbiasvarname       = cn_obsbiasfile_varname
+         sdobsgroup%lnea               = ln_nea
+         sdobsgroup%lbound_reject      = ln_bound_reject
+         sdobsgroup%lignmis            = ln_ignmis
+         sdobsgroup%lall_at_all        = ln_all_at_all
+         sdobsgroup%lnight             = ln_night
+         sdobsgroup%ltime_mean_bkg     = ln_time_mean_bkg
+         sdobsgroup%lfp_indegs         = ln_fp_indegs
+         sdobsgroup%ravglamscl         = rn_avglamscl
+         sdobsgroup%ravgphiscl         = rn_avgphiscl
+         sdobsgroup%rmdtcorr           = rn_mdtcorr
+         sdobsgroup%rmdtcutoff         = rn_mdtcutoff
+         sdobsgroup%rtime_mean_period  = rn_time_mean_period
+      ENDIF
+
+   END SUBROUTINE obs_group_read_namelist
+
+
+   SUBROUTINE obs_group_check( sdobsgroup, kgroup )
+      !!----------------------------------------------------------------------
+      !!                     ***  ROUTINE obs_group_check  ***
+      !!
+      !! ** Purpose : - Error check observation group types
+      !!
+      !! ** Method  : - Check and print options
+      !!
+      !! ** Action  : - Check and print options
+      !!
+      !!----------------------------------------------------------------------
+      !! * Arguments
+      TYPE(obs_group), INTENT(IN) :: sdobsgroup ! Obs group to be checked
+      INTEGER,         INTENT(IN) :: kgroup     ! Number of group being checked
+      !! * Local variables
+      INTEGER :: jtype, jfile                   ! Loop counters
+      !!----------------------------------------------------------------------
+
+      IF (lwp) THEN
+         WRITE(numout,*)
+         WRITE(numout,*) 'obs_group_check : Options for group ', kgroup, ', ', TRIM(sdobsgroup%cgroupname)
+         WRITE(numout,*) '~~~~~~~~~~~~'
+         WRITE(numout,*) '          Logical switch for group being enabled                  ln_enabled = ', sdobsgroup%lenabled
+         IF ( .NOT. sdobsgroup%lenabled ) THEN
+            WRITE(numout,*) '             Group disabled, will not be used'
+         ELSE
+            WRITE(numout,*) '          Observation types in group:', sdobsgroup%nobstypes
+            DO jtype = 1, sdobsgroup%nobstypes
+               WRITE(numout,*) '             ', TRIM(sdobsgroup%cobstypes(jtype))
+            END DO
+               WRITE(numout,*) '          Observation files in group:', sdobsgroup%nobsfiles
+            DO jfile = 1, sdobsgroup%nobsfiles
+               WRITE(numout,*) '             ', TRIM(sdobsgroup%cobsfiles(jfile))
+            END DO
+            WRITE(numout,*) '          General settings:'
+            WRITE(numout,*) '             Logical switch for surface data                         ln_surf = ', sdobsgroup%lsurf
+            WRITE(numout,*) '             Logical switch for profile data                         ln_prof = ', sdobsgroup%lprof
+            WRITE(numout,*) '             Rejection of observations near land switch               ln_nea = ', sdobsgroup%lnea
+            WRITE(numout,*) '             Rejection of obs near open bdys                 ln_bound_reject = ', sdobsgroup%lbound_reject
+            WRITE(numout,*) '             Logical switch for ignoring missing files             ln_ignmis = ', sdobsgroup%lignmis
+            WRITE(numout,*) '             Type of horizontal interpolation method                nn_2dint = ', sdobsgroup%n2dint
+            IF ( sdobsgroup%n2dint <= 4 ) THEN
+               WRITE(numout,*) '                model counterparts will be interpolated horizontally'
+            ELSE
+               WRITE(numout,*) '                model counterparts will be averaged horizontally'
+            ENDIF
+            WRITE(numout,*) '          Settings only for surface data, which is ', sdobsgroup%lsurf
+            WRITE(numout,*) '             Obs footprint in deg [T] or m [F]                  ln_fp_indegs = ', sdobsgroup%lfp_indegs
+            WRITE(numout,*) '             E/W diameter of obs footprint                      rn_avglamscl = ', sdobsgroup%ravglamscl
+            WRITE(numout,*) '             N/S diameter of obs footprint                      rn_avgphiscl = ', sdobsgroup%ravgphiscl
+            WRITE(numout,*) '             Logical switch for night-time average                  ln_night = ', sdobsgroup%lnight
+            WRITE(numout,*) '             Logical switch for time-mean background        ln_time_mean_bkg = ', sdobsgroup%ltime_mean_bkg
+            WRITE(numout,*) '             Meaning period (hours) for time-mean bkg    rn_time_mean_period = ', sdobsgroup%rtime_mean_period
+            WRITE(numout,*) '             Logical switch for bias correction                   ln_obsbias = ', sdobsgroup%lobsbias
+            IF ( sdobsgroup%lobsbias ) THEN
+               WRITE(numout,*) '             Observation type to be bias corrected    cn_type_to_biascorrect = ', TRIM(sdobsgroup%cobstypes(sdobsgroup%nbiasvar))
+               WRITE(numout,*) '             Bias variable name in bias files         cn_obsbiasfile_varname = ', TRIM(sdobsgroup%cbiasvarname)
+               WRITE(numout,*) '             Bias files in group:', sdobsgroup%nobsbiasfiles
+               DO jfile = 1, sdobsgroup%nobsbiasfiles
+                  WRITE(numout,*) '                ', TRIM(sdobsgroup%cobsbiasfiles(jfile))
+               END DO
+            ENDIF
+            WRITE(numout,*) '          Settings only for profile data, which is ', sdobsgroup%lprof
+            WRITE(numout,*) '             Type of vertical interpolation method                  nn_1dint = ', sdobsgroup%n1dint
+            WRITE(numout,*) '             Daily average types                             nn_profdavtypes = ', sdobsgroup%nprofdavtypes
+            WRITE(numout,*) '             Logical switch to compute all vars at all pts     ln_all_at_all = ', sdobsgroup%lall_at_all
+            WRITE(numout,*) '          Settings only for SLA data, which is ', sdobsgroup%lsla
+            WRITE(numout,*) '             Logical switch for alt bias                          ln_altbias = ', sdobsgroup%laltbias
+            WRITE(numout,*) '             Alt bias file name                               cn_altbiasfile = ', TRIM(sdobsgroup%caltbiasfile)
+            WRITE(numout,*) '             MSSH correction scheme                                 nn_msshc = ', sdobsgroup%nmsshc
+            WRITE(numout,*) '             MDT  correction                                      rn_mdtcorr = ', sdobsgroup%rmdtcorr
+            WRITE(numout,*) '             MDT cutoff for computed correction                 rn_mdtcutoff = ', sdobsgroup%rmdtcutoff
+            WRITE(numout,*) '          Settings only for temperature/salinity data'
+            WRITE(numout,*) '             Logical switch for outputting climatology        ln_output_clim = ', sdobsgroup%loutput_clim
+
+            IF ( (       sdobsgroup%lsurf .AND.       sdobsgroup%lprof ) .OR. &
+               & ( .NOT. sdobsgroup%lsurf .AND. .NOT. sdobsgroup%lprof ) ) THEN
+               CALL ctl_stop( ' One and only one of ln_surf or ln_prof must be set per observation group' )
+            ENDIF
+
+            IF ( sdobsgroup%nobstypes == 0 ) THEN
+               CALL ctl_stop( ' No observation types specified for this observation group' )
+            ENDIF
+
+            IF ( sdobsgroup%nobsfiles == 0 ) THEN
+               CALL ctl_stop( ' No observation files specified for this observation group' )
+            ENDIF
+
+            IF ( (sdobsgroup%lobsbias) .AND. (sdobsgroup%nobsbiasfiles == 0) ) THEN
+               CALL ctl_stop( ' No bias files specified for this observation group' )
+            ENDIF
+
+            IF ( (sdobsgroup%n2dint < 0) .OR. (sdobsgroup%n2dint > 6) ) THEN
+               CALL ctl_stop( ' Invalid horizontal interpolation type' )
+            ENDIF
+
+            IF( (sdobsgroup%n1dint < 0) .OR. (sdobsgroup%n1dint > 1) ) THEN
+               CALL ctl_stop(' Invalid vertical interpolation type')
+            ENDIF
+
+            IF ( (sdobsgroup%n2dint > 4) .AND. (sdobsgroup%n2dint <= 6) ) THEN
+               IF ( sdobsgroup%ravglamscl <= 0._wp ) THEN
+                  CALL ctl_stop( ' Incorrect value set for averaging footprint scale rn_avglamscl' )
+               ENDIF
+               IF ( sdobsgroup%ravgphiscl <= 0._wp ) THEN
+                  CALL ctl_stop( ' Incorrect value set for averaging footprint scale rn_avgphiscl' )
+               ENDIF
+            ENDIF
+
+            IF ( sdobsgroup%lsla .AND. sdobsgroup%laltbias ) THEN
+               IF ( TRIM(sdobsgroup%caltbiasfile) == '' ) THEN
+                  CALL ctl_stop( ' No altimeter bias file specified' )
+               ENDIF
+            ENDIF
+
+            IF( sdobsgroup%lvel .AND. (.NOT. ln_grid_global) ) THEN
+               CALL ctl_stop( ' Velocity data only works with ln_grid_global=.true.' )
+            ENDIF
+
+         ENDIF
+
+      ENDIF
+
+   END SUBROUTINE obs_group_check
+
+END MODULE obs_group_def
Index: NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_level_search.h90
===================================================================
--- NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_level_search.h90	(revision 15731)
+++ NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_level_search.h90	(revision 15799)
@@ -13,5 +13,8 @@
       !! ** Method  : Straightforward search
       !!
-      !! ** Action  : 
+      !! ** Action  : Will return level associated with T-point below the obs
+      !!              depth, except when observation is in the top box will 
+      !!              return level 2. Also, if obs depth greater than depth 
+      !!              of last wet T-point (kpk-1) will return level kpk.
       !!
       !! History :
@@ -43,5 +46,5 @@
       DO ji = 1, kobs 
          kobsk(ji) = 1
-         depk: DO jk = 2, kgrd
+         depk: DO jk = 2, kgrd-1
             IF ( pgrddep(jk) >= pobsdep(ji) ) EXIT depk
          END DO depk
Index: NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_oper.F90
===================================================================
--- NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_oper.F90	(revision 15731)
+++ NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_oper.F90	(revision 15799)
@@ -18,5 +18,9 @@
    USE lib_mpp,       ONLY :   ctl_warn, ctl_stop           ! Warning and stopping routines
    USE sbcdcy,        ONLY :   sbc_dcy, nday_qsr            ! For calculation of where it is night-time
-   USE obs_grid,      ONLY :   obs_level_search     
+   USE obs_grid,      ONLY :   obs_level_search
+   USE obs_group_def, ONLY : cobsname_sla, cobsname_fbd, imaxavtypes
+#if defined key_si3 || defined key_cice
+   USE phycst,        ONLY : rhos, rhoi, rhow               ! For conversion from sea ice freeboard to thickness
+#endif
    !
    USE par_kind     , ONLY :   wp   ! Precision variables
@@ -28,6 +32,4 @@
    PUBLIC   obs_prof_opt   !: Compute the model counterpart of profile obs
    PUBLIC   obs_surf_opt   !: Compute the model counterpart of surface obs
-
-   INTEGER, PARAMETER, PUBLIC ::   imaxavtypes = 20   !: Max number of daily avgd obs types
 
    !!----------------------------------------------------------------------
@@ -38,9 +40,11 @@
 CONTAINS
 
-   SUBROUTINE obs_prof_opt( prodatqc, kt, kpi, kpj, kpk,          &
-      &                     kit000, kdaystp,                      &
-      &                     pvar1, pvar2, pgdept, pgdepw,         &
-      &                     pmask1, pmask2,                       &  
-      &                     plam1, plam2, pphi1, pphi2,           &
+   SUBROUTINE obs_prof_opt( prodatqc, kt, kpi, kpj, kpk, &
+      &                     kit000, kdaystp, kvar,       &
+      &                     pvar,                        &
+      &                     ldclim, kclim, pclim,        &
+      &                     pgdept, pgdepw,              &
+      &                     pmask,                       &  
+      &                     plam, pphi,                  &
       &                     k1dint, k2dint, kdailyavtypes )
       !!-----------------------------------------------------------------------
@@ -103,8 +107,12 @@
       INTEGER       , INTENT(in   ) ::   k2dint          ! Horizontal interpolation type (see header)
       INTEGER       , INTENT(in   ) ::   kdaystp         ! Number of time steps per day
-      REAL(KIND=wp) , INTENT(in   ), DIMENSION(kpi,kpj,kpk) ::   pvar1 , pvar2    ! Model field     1 and 2
-      REAL(KIND=wp) , INTENT(in   ), DIMENSION(kpi,kpj,kpk) ::   pmask1, pmask2   ! Land-sea mask   1 and 2
-      REAL(KIND=wp) , INTENT(in   ), DIMENSION(kpi,kpj)     ::   plam1 , plam2    ! Model longitude 1 and 2
-      REAL(KIND=wp) , INTENT(in   ), DIMENSION(kpi,kpj)     ::   pphi1 , pphi2    ! Model latitudes 1 and 2
+      INTEGER       , INTENT(in   ) ::   kvar            ! Index of variable in prodatqc
+      INTEGER       , INTENT(in   ) ::   kclim           ! Index of climatology in prodatqc
+      LOGICAL       , INTENT(in   ) ::   ldclim          ! Switch to interpolate climatology
+      REAL(KIND=wp) , INTENT(in   ), DIMENSION(kpi,kpj,kpk) ::   pvar             ! Model field
+      REAL(KIND=wp) , INTENT(in   ), DIMENSION(kpi,kpj,kpk) ::   pclim            ! Climatology field
+      REAL(KIND=wp) , INTENT(in   ), DIMENSION(kpi,kpj,kpk) ::   pmask            ! Land-sea mask
+      REAL(KIND=wp) , INTENT(in   ), DIMENSION(kpi,kpj)     ::   plam             ! Model longitude
+      REAL(KIND=wp) , INTENT(in   ), DIMENSION(kpi,kpj)     ::   pphi             ! Model latitudes
       REAL(KIND=wp) , INTENT(in   ), DIMENSION(kpi,kpj,kpk) ::   pgdept, pgdepw   ! depth of T and W levels 
       INTEGER, DIMENSION(imaxavtypes), OPTIONAL ::   kdailyavtypes             ! Types for daily averages
@@ -126,8 +134,6 @@
          & idailyavtypes
       INTEGER, DIMENSION(:,:,:), ALLOCATABLE :: &
-         & igrdi1, &
-         & igrdi2, &
-         & igrdj1, &
-         & igrdj2
+         & igrdi, &
+         & igrdj
       INTEGER, ALLOCATABLE, DIMENSION(:) :: iv_indic
 
@@ -136,28 +142,23 @@
       REAL(KIND=wp) :: zdaystp
       REAL(KIND=wp), DIMENSION(kpk) :: &
-         & zobsmask1, &
-         & zobsmask2, &
-         & zobsk,    &
-         & zobs2k
+         & zobsk,  &
+         & zobs2k, &
+         & zclm2k
       REAL(KIND=wp), DIMENSION(2,2,1) :: &
          & zweig1, &
-         & zweig2, &
          & zweig
       REAL(wp), DIMENSION(:,:,:,:), ALLOCATABLE :: &
-         & zmask1, &
-         & zmask2, &
-         & zint1,  &
-         & zint2,  &
-         & zinm1,  &
-         & zinm2,  &
+         & zmask,  &
+         & zclim,  &
+         & zint,   &
+         & zinm,   &
          & zgdept, & 
          & zgdepw
       REAL(wp), DIMENSION(:,:,:), ALLOCATABLE :: &
-         & zglam1, &
-         & zglam2, &
-         & zgphi1, &
-         & zgphi2
-      REAL(KIND=wp), DIMENSION(1) :: zmsk_1, zmsk_2   
+         & zglam,  &
+         & zgphi
+      REAL(KIND=wp), DIMENSION(1) :: zmsk
       REAL(KIND=wp), DIMENSION(:,:,:), ALLOCATABLE :: interp_corner
+      REAL(KIND=wp), DIMENSION(:,:,:), ALLOCATABLE :: interp_corner_clim
 
       LOGICAL :: ld_dailyav
@@ -190,6 +191,5 @@
                DO jj = 1, jpj
                   DO ji = 1, jpi
-                     prodatqc%vdmean(ji,jj,jk,1) = 0.0
-                     prodatqc%vdmean(ji,jj,jk,2) = 0.0
+                     prodatqc%vdmean(ji,jj,jk,kvar) = 0.0
                   END DO
                END DO
@@ -201,9 +201,6 @@
                DO ji = 1, jpi
                   ! Increment field 1 for computing daily mean
-                  prodatqc%vdmean(ji,jj,jk,1) = prodatqc%vdmean(ji,jj,jk,1) &
-                     &                        + pvar1(ji,jj,jk)
-                  ! Increment field 2 for computing daily mean
-                  prodatqc%vdmean(ji,jj,jk,2) = prodatqc%vdmean(ji,jj,jk,2) &
-                     &                        + pvar2(ji,jj,jk)
+                  prodatqc%vdmean(ji,jj,jk,kvar) = prodatqc%vdmean(ji,jj,jk,kvar) &
+                     &                           + pvar(ji,jj,jk)
                END DO
             END DO
@@ -213,13 +210,11 @@
          zdaystp = 1.0 / REAL( kdaystp )
          IF ( idayend == 0 ) THEN
-            IF (lwp) WRITE(numout,*) 'Calculating prodatqc%vdmean on time-step: ',kt
+            IF (lwp) WRITE(numout,*) 'Calculating prodatqc%vdmean on time-step: ', kt
             CALL FLUSH(numout)
             DO jk = 1, jpk
                DO jj = 1, jpj
                   DO ji = 1, jpi
-                     prodatqc%vdmean(ji,jj,jk,1) = prodatqc%vdmean(ji,jj,jk,1) &
-                        &                        * zdaystp
-                     prodatqc%vdmean(ji,jj,jk,2) = prodatqc%vdmean(ji,jj,jk,2) &
-                        &                        * zdaystp
+                     prodatqc%vdmean(ji,jj,jk,kvar) = prodatqc%vdmean(ji,jj,jk,kvar) &
+                        &                           * zdaystp
                   END DO
                END DO
@@ -231,38 +226,28 @@
       ! Get the data for interpolation
       ALLOCATE( &
-         & igrdi1(2,2,ipro),      &
-         & igrdi2(2,2,ipro),      &
-         & igrdj1(2,2,ipro),      &
-         & igrdj2(2,2,ipro),      &
-         & zglam1(2,2,ipro),      &
-         & zglam2(2,2,ipro),      &
-         & zgphi1(2,2,ipro),      &
-         & zgphi2(2,2,ipro),      &
-         & zmask1(2,2,kpk,ipro),  &
-         & zmask2(2,2,kpk,ipro),  &
-         & zint1(2,2,kpk,ipro),   &
-         & zint2(2,2,kpk,ipro),   &
-         & zgdept(2,2,kpk,ipro),  & 
-         & zgdepw(2,2,kpk,ipro)   & 
+         & igrdi(2,2,ipro),      &
+         & igrdj(2,2,ipro),      &
+         & zglam(2,2,ipro),      &
+         & zgphi(2,2,ipro),      &
+         & zmask(2,2,kpk,ipro),  &
+         & zint(2,2,kpk,ipro),   &
+         & zgdept(2,2,kpk,ipro), & 
+         & zgdepw(2,2,kpk,ipro)  & 
          & )
+
+      IF ( ldclim ) THEN
+         ALLOCATE( zclim(2,2,kpk,ipro) )
+      ENDIF
 
       DO jobs = prodatqc%nprofup + 1, prodatqc%nprofup + ipro
          iobs = jobs - prodatqc%nprofup
-         igrdi1(1,1,iobs) = prodatqc%mi(jobs,1)-1
-         igrdj1(1,1,iobs) = prodatqc%mj(jobs,1)-1
-         igrdi1(1,2,iobs) = prodatqc%mi(jobs,1)-1
-         igrdj1(1,2,iobs) = prodatqc%mj(jobs,1)
-         igrdi1(2,1,iobs) = prodatqc%mi(jobs,1)
-         igrdj1(2,1,iobs) = prodatqc%mj(jobs,1)-1
-         igrdi1(2,2,iobs) = prodatqc%mi(jobs,1)
-         igrdj1(2,2,iobs) = prodatqc%mj(jobs,1)
-         igrdi2(1,1,iobs) = prodatqc%mi(jobs,2)-1
-         igrdj2(1,1,iobs) = prodatqc%mj(jobs,2)-1
-         igrdi2(1,2,iobs) = prodatqc%mi(jobs,2)-1
-         igrdj2(1,2,iobs) = prodatqc%mj(jobs,2)
-         igrdi2(2,1,iobs) = prodatqc%mi(jobs,2)
-         igrdj2(2,1,iobs) = prodatqc%mj(jobs,2)-1
-         igrdi2(2,2,iobs) = prodatqc%mi(jobs,2)
-         igrdj2(2,2,iobs) = prodatqc%mj(jobs,2)
+         igrdi(1,1,iobs) = prodatqc%mi(jobs,kvar)-1
+         igrdj(1,1,iobs) = prodatqc%mj(jobs,kvar)-1
+         igrdi(1,2,iobs) = prodatqc%mi(jobs,kvar)-1
+         igrdj(1,2,iobs) = prodatqc%mj(jobs,kvar)
+         igrdi(2,1,iobs) = prodatqc%mi(jobs,kvar)
+         igrdj(2,1,iobs) = prodatqc%mj(jobs,kvar)-1
+         igrdi(2,2,iobs) = prodatqc%mi(jobs,kvar)
+         igrdj(2,2,iobs) = prodatqc%mj(jobs,kvar)
       END DO
 
@@ -271,29 +256,23 @@
       zgdepw(:,:,:,:) = 0.0
 
-      CALL obs_int_comm_2d( 2, 2, ipro, kpi, kpj, igrdi1, igrdj1, plam1, zglam1 )
-      CALL obs_int_comm_2d( 2, 2, ipro, kpi, kpj, igrdi1, igrdj1, pphi1, zgphi1 )
-      CALL obs_int_comm_3d( 2, 2, ipro, kpi, kpj, kpk, igrdi1, igrdj1, pmask1, zmask1 )
-      CALL obs_int_comm_3d( 2, 2, ipro, kpi, kpj, kpk, igrdi1, igrdj1, pvar1,   zint1 )
-      
-      CALL obs_int_comm_2d( 2, 2, ipro, kpi, kpj, igrdi2, igrdj2, plam2, zglam2 )
-      CALL obs_int_comm_2d( 2, 2, ipro, kpi, kpj, igrdi2, igrdj2, pphi2, zgphi2 )
-      CALL obs_int_comm_3d( 2, 2, ipro, kpi, kpj, kpk, igrdi2, igrdj2, pmask2, zmask2 )
-      CALL obs_int_comm_3d( 2, 2, ipro, kpi, kpj, kpk, igrdi2, igrdj2, pvar2,   zint2 )
-
-      CALL obs_int_comm_3d( 2, 2, ipro, kpi, kpj, kpk, igrdi1, igrdj1, pgdept, zgdept ) 
-      CALL obs_int_comm_3d( 2, 2, ipro, kpi, kpj, kpk, igrdi1, igrdj1, pgdepw, zgdepw ) 
+      CALL obs_int_comm_2d( 2, 2, ipro, kpi, kpj, igrdi, igrdj, plam, zglam )
+      CALL obs_int_comm_2d( 2, 2, ipro, kpi, kpj, igrdi, igrdj, pphi, zgphi )
+      CALL obs_int_comm_3d( 2, 2, ipro, kpi, kpj, kpk, igrdi, igrdj, pmask, zmask )
+      CALL obs_int_comm_3d( 2, 2, ipro, kpi, kpj, kpk, igrdi, igrdj, pvar,   zint )
+
+      CALL obs_int_comm_3d( 2, 2, ipro, kpi, kpj, kpk, igrdi, igrdj, pgdept, zgdept ) 
+      CALL obs_int_comm_3d( 2, 2, ipro, kpi, kpj, kpk, igrdi, igrdj, pgdepw, zgdepw ) 
+
+      IF ( ldclim ) THEN
+         CALL obs_int_comm_3d( 2, 2, ipro, kpi, kpj, kpk, igrdi, igrdj, pclim, zclim )
+      ENDIF
 
       ! At the end of the day also get interpolated means
       IF ( ld_dailyav .AND. idayend == 0 ) THEN
 
-         ALLOCATE( &
-            & zinm1(2,2,kpk,ipro),  &
-            & zinm2(2,2,kpk,ipro)   &
-            & )
-
-         CALL obs_int_comm_3d( 2, 2, ipro, kpi, kpj, kpk, igrdi1, igrdj1, &
-            &                  prodatqc%vdmean(:,:,:,1), zinm1 )
-         CALL obs_int_comm_3d( 2, 2, ipro, kpi, kpj, kpk, igrdi2, igrdj2, &
-            &                  prodatqc%vdmean(:,:,:,2), zinm2 )
+         ALLOCATE( zinm(2,2,kpk,ipro) )
+
+         CALL obs_int_comm_3d( 2, 2, ipro, kpi, kpj, kpk, igrdi, igrdj, &
+            &                  prodatqc%vdmean(:,:,:,kvar), zinm )
 
       ENDIF
@@ -330,21 +309,13 @@
          ! Horizontal weights 
          ! Masked values are calculated later.  
-         IF ( prodatqc%npvend(jobs,1) > 0 ) THEN
+         IF ( prodatqc%npvend(jobs,kvar) > 0 ) THEN
 
             CALL obs_int_h2d_init( 1, 1, k2dint, zlam, zphi,     &
-               &                   zglam1(:,:,iobs), zgphi1(:,:,iobs), &
-               &                   zmask1(:,:,1,iobs), zweig1, zmsk_1 )
-
-         ENDIF
-
-         IF ( prodatqc%npvend(jobs,2) > 0 ) THEN
-
-            CALL obs_int_h2d_init( 1, 1, k2dint, zlam, zphi,     &
-               &                   zglam2(:,:,iobs), zgphi2(:,:,iobs), &
-               &                   zmask2(:,:,1,iobs), zweig2, zmsk_2 )
- 
-         ENDIF
-
-         IF ( prodatqc%npvend(jobs,1) > 0 ) THEN
+               &                   zglam(:,:,iobs), zgphi(:,:,iobs), &
+               &                   zmask(:,:,1,iobs), zweig1, zmsk )
+
+         ENDIF
+
+         IF ( prodatqc%npvend(jobs,kvar) > 0 ) THEN
 
             zobsk(:) = obfillflt
@@ -356,8 +327,11 @@
 
                   ! vertically interpolate all 4 corners 
-                  ista = prodatqc%npvsta(jobs,1) 
-                  iend = prodatqc%npvend(jobs,1) 
+                  ista = prodatqc%npvsta(jobs,kvar) 
+                  iend = prodatqc%npvend(jobs,kvar) 
                   inum_obs = iend - ista + 1 
                   ALLOCATE(interp_corner(2,2,inum_obs),iv_indic(inum_obs)) 
+                  IF ( ldclim ) THEN
+                     ALLOCATE( interp_corner_clim(2,2,inum_obs) )
+                  ENDIF
 
                   DO iin=1,2 
@@ -366,20 +340,36 @@
                         IF ( k1dint == 1 ) THEN 
                            CALL obs_int_z1d_spl( kpk, & 
-                              &     zinm1(iin,ijn,:,iobs), & 
+                              &     zinm(iin,ijn,:,iobs), & 
                               &     zobs2k, zgdept(iin,ijn,:,iobs), & 
-                              &     zmask1(iin,ijn,:,iobs)) 
+                              &     zmask(iin,ijn,:,iobs)) 
+
+                           IF ( ldclim ) THEN
+                              CALL obs_int_z1d_spl( kpk, &
+                                 &     zclim(iin,ijn,:,iobs), &
+                                 &     zclm2k, zgdept(iin,ijn,:,iobs), &
+                                 &     zmask(iin,ijn,:,iobs))
+                           ENDIF
                         ENDIF 
        
                         CALL obs_level_search(kpk, & 
                            &    zgdept(iin,ijn,:,iobs), & 
-                           &    inum_obs, prodatqc%var(1)%vdep(ista:iend), & 
+                           &    inum_obs, prodatqc%var(kvar)%vdep(ista:iend), & 
                            &    iv_indic) 
 
                         CALL obs_int_z1d(kpk, iv_indic, k1dint, inum_obs, & 
-                           &    prodatqc%var(1)%vdep(ista:iend), & 
-                           &    zinm1(iin,ijn,:,iobs), & 
+                           &    prodatqc%var(kvar)%vdep(ista:iend), & 
+                           &    zinm(iin,ijn,:,iobs), & 
                            &    zobs2k, interp_corner(iin,ijn,:), & 
                            &    zgdept(iin,ijn,:,iobs), & 
-                           &    zmask1(iin,ijn,:,iobs)) 
+                           &    zmask(iin,ijn,:,iobs)) 
+
+                        IF ( ldclim ) THEN
+                           CALL obs_int_z1d(kpk, iv_indic, k1dint, inum_obs, &
+                              &    prodatqc%var(kvar)%vdep(ista:iend), &
+                              &    zclim(iin,ijn,:,iobs), &
+                              &    zclm2k, interp_corner_clim(iin,ijn,:), &
+                              &    zgdept(iin,ijn,:,iobs), &
+                              &    zmask(iin,ijn,:,iobs))
+                        ENDIF
        
                      ENDDO 
@@ -393,8 +383,11 @@
      
                ! vertically interpolate all 4 corners 
-               ista = prodatqc%npvsta(jobs,1) 
-               iend = prodatqc%npvend(jobs,1) 
+               ista = prodatqc%npvsta(jobs,kvar) 
+               iend = prodatqc%npvend(jobs,kvar) 
                inum_obs = iend - ista + 1 
                ALLOCATE(interp_corner(2,2,inum_obs), iv_indic(inum_obs)) 
+               IF ( ldclim ) THEN
+                  ALLOCATE( interp_corner_clim(2,2,inum_obs) )
+               ENDIF
                DO iin=1,2  
                   DO ijn=1,2 
@@ -402,21 +395,36 @@
                      IF ( k1dint == 1 ) THEN 
                         CALL obs_int_z1d_spl( kpk, & 
-                           &    zint1(iin,ijn,:,iobs),& 
+                           &    zint(iin,ijn,:,iobs),& 
                            &    zobs2k, zgdept(iin,ijn,:,iobs), & 
-                           &    zmask1(iin,ijn,:,iobs)) 
-  
+                           &    zmask(iin,ijn,:,iobs)) 
+
+                        IF ( ldclim ) THEN
+                           CALL obs_int_z1d_spl( kpk, &
+                              &    zclim(iin,ijn,:,iobs),&
+                              &    zclm2k, zgdept(iin,ijn,:,iobs), &
+                              &    zmask(iin,ijn,:,iobs))
+                        ENDIF
                      ENDIF 
        
                      CALL obs_level_search(kpk, & 
                          &        zgdept(iin,ijn,:,iobs),& 
-                         &        inum_obs, prodatqc%var(1)%vdep(ista:iend), & 
+                         &        inum_obs, prodatqc%var(kvar)%vdep(ista:iend), & 
                          &        iv_indic) 
 
                      CALL obs_int_z1d(kpk, iv_indic, k1dint, inum_obs,     & 
-                         &          prodatqc%var(1)%vdep(ista:iend),     & 
-                         &          zint1(iin,ijn,:,iobs),            & 
+                         &          prodatqc%var(kvar)%vdep(ista:iend),     & 
+                         &          zint(iin,ijn,:,iobs),            & 
                          &          zobs2k,interp_corner(iin,ijn,:), & 
                          &          zgdept(iin,ijn,:,iobs),         & 
-                         &          zmask1(iin,ijn,:,iobs) )      
+                         &          zmask(iin,ijn,:,iobs) )      
+
+                     IF ( ldclim ) THEN
+                        CALL obs_int_z1d(kpk, iv_indic, k1dint, inum_obs,     &
+                            &          prodatqc%var(kvar)%vdep(ista:iend),     &
+                            &          zclim(iin,ijn,:,iobs),            &
+                            &          zclm2k,interp_corner_clim(iin,ijn,:), &
+                            &          zgdept(iin,ijn,:,iobs),         &
+                            &          zmask(iin,ijn,:,iobs) )
+                     ENDIF
          
                   ENDDO 
@@ -442,17 +450,17 @@
                   DO ijn=1,2 
      
-                     depth_loop1: DO ik=kpk,2,-1 
-                        IF(zmask1(iin,ijn,ik-1,iobs ) > 0.9 )THEN   
+                     depth_loop: DO ik=kpk,2,-1 
+                        IF(zmask(iin,ijn,ik-1,iobs ) > 0.9 )THEN   
                             
                            zweig(iin,ijn,1) = &  
                               & zweig1(iin,ijn,1) * & 
                               & MAX( SIGN(1._wp,(zgdepw(iin,ijn,ik,iobs) ) & 
-                              &  - prodatqc%var(1)%vdep(iend)),0._wp) 
+                              &  - prodatqc%var(kvar)%vdep(iend)),0._wp) 
                             
-                           EXIT depth_loop1 
+                           EXIT depth_loop 
 
                         ENDIF 
 
-                     ENDDO depth_loop1 
+                     ENDDO depth_loop
      
                   ENDDO 
@@ -460,179 +468,59 @@
    
                CALL obs_int_h2d( 1, 1, zweig, interp_corner(:,:,ikn), & 
-                  &              prodatqc%var(1)%vmod(iend:iend) ) 
-
-                  ! Set QC flag for any observations found below the bottom
-                  ! needed as the check here is more strict than that in obs_prep
-               IF (sum(zweig) == 0.0_wp) prodatqc%var(1)%nvqc(iend:iend)=4
+                  &              prodatqc%var(kvar)%vmod(iend:iend) ) 
+
+               IF ( ldclim ) THEN
+                  CALL obs_int_h2d( 1, 1, zweig, interp_corner_clim(:,:,ikn), &
+                     &              prodatqc%var(kvar)%vadd(iend:iend,kclim) )
+               ENDIF
+
+               ! Set QC flag for any observations found below the bottom
+               ! needed as the check here is more strict than that in obs_prep
+               IF (sum(zweig) == 0.0_wp) prodatqc%var(kvar)%nvqc(iend:iend)=4
  
             ENDDO 
  
             DEALLOCATE(interp_corner,iv_indic) 
+            IF ( ldclim ) THEN
+               DEALLOCATE( interp_corner_clim )
+            ENDIF
           
-         ENDIF 
-
-         ! For the second variable
-         IF ( prodatqc%npvend(jobs,2) > 0 ) THEN
-
-            zobsk(:) = obfillflt
-
-            IF ( ANY (idailyavtypes(:) == prodatqc%ntyp(jobs)) ) THEN
-
-               IF ( idayend == 0 )  THEN
-                  ! Daily averaged data
-
-                  ! vertically interpolate all 4 corners 
-                  ista = prodatqc%npvsta(jobs,2) 
-                  iend = prodatqc%npvend(jobs,2) 
-                  inum_obs = iend - ista + 1 
-                  ALLOCATE(interp_corner(2,2,inum_obs),iv_indic(inum_obs)) 
-
-                  DO iin=1,2 
-                     DO ijn=1,2 
-
-                        IF ( k1dint == 1 ) THEN 
-                           CALL obs_int_z1d_spl( kpk, & 
-                              &     zinm2(iin,ijn,:,iobs), & 
-                              &     zobs2k, zgdept(iin,ijn,:,iobs), & 
-                              &     zmask2(iin,ijn,:,iobs)) 
-                        ENDIF 
-       
-                        CALL obs_level_search(kpk, & 
-                           &    zgdept(iin,ijn,:,iobs), & 
-                           &    inum_obs, prodatqc%var(2)%vdep(ista:iend), & 
-                           &    iv_indic) 
-
-                        CALL obs_int_z1d(kpk, iv_indic, k1dint, inum_obs, & 
-                           &    prodatqc%var(2)%vdep(ista:iend), & 
-                           &    zinm2(iin,ijn,:,iobs), & 
-                           &    zobs2k, interp_corner(iin,ijn,:), & 
-                           &    zgdept(iin,ijn,:,iobs), & 
-                           &    zmask2(iin,ijn,:,iobs)) 
-       
-                     ENDDO 
-                  ENDDO 
-
-               ENDIF !idayend
-
-            ELSE   
-
-               ! Point data 
-     
-               ! vertically interpolate all 4 corners 
-               ista = prodatqc%npvsta(jobs,2) 
-               iend = prodatqc%npvend(jobs,2) 
-               inum_obs = iend - ista + 1 
-               ALLOCATE(interp_corner(2,2,inum_obs), iv_indic(inum_obs)) 
-               DO iin=1,2  
-                  DO ijn=1,2 
-                    
-                     IF ( k1dint == 1 ) THEN 
-                        CALL obs_int_z1d_spl( kpk, & 
-                           &    zint2(iin,ijn,:,iobs),& 
-                           &    zobs2k, zgdept(iin,ijn,:,iobs), & 
-                           &    zmask2(iin,ijn,:,iobs)) 
-  
-                     ENDIF 
-       
-                     CALL obs_level_search(kpk, & 
-                         &        zgdept(iin,ijn,:,iobs),& 
-                         &        inum_obs, prodatqc%var(2)%vdep(ista:iend), & 
-                         &        iv_indic) 
-
-                     CALL obs_int_z1d(kpk, iv_indic, k1dint, inum_obs,     & 
-                         &          prodatqc%var(2)%vdep(ista:iend),     & 
-                         &          zint2(iin,ijn,:,iobs),            & 
-                         &          zobs2k,interp_corner(iin,ijn,:), & 
-                         &          zgdept(iin,ijn,:,iobs),         & 
-                         &          zmask2(iin,ijn,:,iobs) )      
-         
-                  ENDDO 
-               ENDDO 
-             
-            ENDIF 
-
-            !------------------------------------------------------------- 
-            ! Compute the horizontal interpolation for every profile level 
-            !------------------------------------------------------------- 
-             
-            DO ikn=1,inum_obs 
-               iend=ista+ikn-1
-                  
-               zweig(:,:,1) = 0._wp 
-   
-               ! This code forces the horizontal weights to be  
-               ! zero IF the observation is below the bottom of the  
-               ! corners of the interpolation nodes, Or if it is in  
-               ! the mask. This is important for observations near  
-               ! steep bathymetry 
-               DO iin=1,2 
-                  DO ijn=1,2 
-     
-                     depth_loop2: DO ik=kpk,2,-1 
-                        IF(zmask2(iin,ijn,ik-1,iobs ) > 0.9 )THEN   
-                            
-                           zweig(iin,ijn,1) = &  
-                              & zweig2(iin,ijn,1) * & 
-                              & MAX( SIGN(1._wp,(zgdepw(iin,ijn,ik,iobs) ) & 
-                              &  - prodatqc%var(2)%vdep(iend)),0._wp) 
-                            
-                           EXIT depth_loop2 
-
-                        ENDIF 
-
-                     ENDDO depth_loop2 
-     
-                  ENDDO 
-               ENDDO 
-   
-               CALL obs_int_h2d( 1, 1, zweig, interp_corner(:,:,ikn), & 
-                  &              prodatqc%var(2)%vmod(iend:iend) ) 
-
-                  ! Set QC flag for any observations found below the bottom
-                  ! needed as the check here is more strict than that in obs_prep
-               IF (sum(zweig) == 0.0_wp) prodatqc%var(2)%nvqc(iend:iend)=4
- 
-            ENDDO 
- 
-            DEALLOCATE(interp_corner,iv_indic) 
-          
-         ENDIF 
+         ENDIF
 
       ENDDO
 
       ! Deallocate the data for interpolation
-      DEALLOCATE( &
-         & igrdi1, &
-         & igrdi2, &
-         & igrdj1, &
-         & igrdj2, &
-         & zglam1, &
-         & zglam2, &
-         & zgphi1, &
-         & zgphi2, &
-         & zmask1, &
-         & zmask2, &
-         & zint1,  &
-         & zint2,  &
+      DEALLOCATE(  &
+         & igrdi,  &
+         & igrdj,  &
+         & zglam,  &
+         & zgphi,  &
+         & zmask,  &
+         & zint,   &
          & zgdept, &
          & zgdepw  &
          & )
 
+      IF ( ldclim ) THEN
+         DEALLOCATE( zclim )
+      ENDIF
+
       ! At the end of the day also get interpolated means
       IF ( ld_dailyav .AND. idayend == 0 ) THEN
-         DEALLOCATE( &
-            & zinm1,  &
-            & zinm2   &
-            & )
-      ENDIF
-
-      prodatqc%nprofup = prodatqc%nprofup + ipro 
+         DEALLOCATE( zinm )
+      ENDIF
+
+      IF ( kvar == prodatqc%nvar ) THEN
+         prodatqc%nprofup = prodatqc%nprofup + ipro 
+      ENDIF
 
    END SUBROUTINE obs_prof_opt
 
-   SUBROUTINE obs_surf_opt( surfdataqc, kt, kpi, kpj,            &
-      &                     kit000, kdaystp, psurf, psurfmask,   &
-      &                     k2dint, ldnightav, plamscl, pphiscl, &
-      &                     lindegrees )
+   SUBROUTINE obs_surf_opt( surfdataqc, kt, kpi, kpj,                &
+      &                     kit000, kdaystp, kvar, psurf,            &
+      &                     ldclim, kclim, pclim, psurfmask,         &
+      &                     k2dint, ldnightav, plamscl, pphiscl,     &
+      &                     lindegrees, ldtime_mean, kmeanstp,       &
+      &                     kssh, kmdt, kfbd, ksnow )
 
       !!-----------------------------------------------------------------------
@@ -680,7 +568,11 @@
                                        !   (kit000-1 = restart time)
       INTEGER, INTENT(IN) :: kdaystp   ! Number of time steps per day
+      INTEGER, INTENT(IN) :: kvar      ! Index of variable in surfdataqc  
+      INTEGER, INTENT(IN) :: kclim     ! Index of climatology in surfdataqc
       INTEGER, INTENT(IN) :: k2dint    ! Horizontal interpolation type (see header)
+      LOGICAL, INTENT(IN) :: ldclim    ! Switch to interpolate climatology
       REAL(wp), INTENT(IN), DIMENSION(kpi,kpj) :: &
          & psurf,  &                   ! Model surface field
+         & pclim,  &                   ! Climatology surface field
          & psurfmask                   ! Land-sea mask
       LOGICAL, INTENT(IN) :: ldnightav ! Logical for averaging night-time data
@@ -690,4 +582,15 @@
       LOGICAL, INTENT(IN) :: &
          & lindegrees                  ! T=> plamscl and pphiscl are specified in degrees, F=> in metres
+      LOGICAL, INTENT(IN) :: &
+         & ldtime_mean                 ! Observations/background represent a time mean
+      INTEGER, INTENT(IN) :: kmeanstp  ! Number of time steps for meaning if ldtime_mean
+      INTEGER, OPTIONAL, INTENT(IN) :: &
+         & kssh                        ! Index of additional variable representing SSH
+      INTEGER, OPTIONAL, INTENT(IN) :: &
+         & kmdt                        ! Index of extra variable representing MDT
+      INTEGER, OPTIONAL, INTENT(IN) :: &
+         & kfbd                        ! Index of additional variable representing ice freeboard
+      INTEGER, OPTIONAL, INTENT(IN) :: &
+         & ksnow                       ! Index of extra variable representing ice snow thickness
 
       !! * Local declarations
@@ -701,4 +604,5 @@
       INTEGER :: imodi, imodj
       INTEGER :: idayend
+      INTEGER :: imeanend
       INTEGER, DIMENSION(:,:,:), ALLOCATABLE :: &
          & igrdi,   &
@@ -711,6 +615,7 @@
       REAL(wp) :: zlam
       REAL(wp) :: zphi
-      REAL(wp), DIMENSION(1) :: zext, zobsmask
+      REAL(wp), DIMENSION(1) :: zext, zobsmask, zclm
       REAL(wp) :: zdaystp
+      REAL(wp) :: zmeanstp
       REAL(wp), DIMENSION(:,:,:), ALLOCATABLE :: &
          & zweig,  &
@@ -719,4 +624,5 @@
          & zsurfm, &
          & zsurftmp, &
+         & zclim,  &
          & zglam,  &
          & zgphi,  &
@@ -741,8 +647,49 @@
       CALL obs_max_fpsize( k2dint, plamscl, pphiscl, lindegrees, psurfmask, imaxifp, imaxjfp )
 
+      IF ( ldtime_mean .AND. ldnightav ) THEN
+         CALL ctl_stop( 'obs_surf_opt: Can have ldtime_mean or ldnightav but not both' )
+      ENDIF
+
+      IF ( ldtime_mean ) THEN
+         ! Initialize time mean for first timestep
+         imeanend = MOD( kt - kit000 + 1, kmeanstp )
+         IF (lwp) WRITE(numout,*) 'Obs time mean ', kt, kit000, kmeanstp, imeanend
+
+         ! Added kt == 0 test to catch restart case
+         IF ( ( imeanend == 1 ) .OR. ( kt == 0 ) ) THEN
+            IF (lwp) WRITE(numout,*) 'Reset surfdataqc%vdmean on time-step: ', kt
+            DO jj = 1, jpj
+               DO ji = 1, jpi
+                  surfdataqc%vdmean(ji,jj,kvar) = 0.0
+               END DO
+            END DO
+         ENDIF
+
+         ! On each time-step, increment the field for computing time mean
+         IF (lwp) WRITE(numout,*)'Accumulating surfdataqc%vdmean on time-step: ', kt
+         DO jj = 1, jpj
+            DO ji = 1, jpi
+               surfdataqc%vdmean(ji,jj,kvar) = surfdataqc%vdmean(ji,jj,kvar) &
+                  &                            + psurf(ji,jj)
+            END DO
+         END DO
+
+         ! Compute the time mean at the end of time period
+         IF ( imeanend == 0 ) THEN
+            zmeanstp = 1.0 / REAL( kmeanstp )
+            IF (lwp) WRITE(numout,*) 'Calculating surfdataqc%vdmean time mean on time-step: ', &
+               &                     kt, ' with weight: ', zmeanstp
+            DO jj = 1, jpj
+               DO ji = 1, jpi
+                  surfdataqc%vdmean(ji,jj,kvar) = surfdataqc%vdmean(ji,jj,kvar) &
+                     &                            * zmeanstp
+               END DO
+            END DO
+         ENDIF
+      ENDIF
 
       IF ( ldnightav ) THEN
 
-      ! Initialize array for night mean
+         ! Initialize array for night mean
          IF ( kt == 0 ) THEN
             ALLOCATE ( icount_night(kpi,kpj) )
@@ -762,5 +709,5 @@
             DO jj = 1, jpj
                DO ji = 1, jpi
-                  surfdataqc%vdmean(ji,jj) = 0.0
+                  surfdataqc%vdmean(ji,jj,:) = 0.0
                   zmeanday(ji,jj) = 0.0
                   icount_night(ji,jj) = 0
@@ -775,7 +722,7 @@
          DO jj = 1, jpj
             DO ji = 1, jpi
-               ! Increment the temperature field for computing night mean and counter
-               surfdataqc%vdmean(ji,jj) = surfdataqc%vdmean(ji,jj)  &
-                      &                    + psurf(ji,jj) * REAL( imask_night(ji,jj) )
+               ! Increment the model field for computing night mean and counter
+               surfdataqc%vdmean(ji,jj,kvar) = surfdataqc%vdmean(ji,jj,kvar)  &
+                      &                        + psurf(ji,jj) * REAL( imask_night(ji,jj) )
                zmeanday(ji,jj)          = zmeanday(ji,jj) + psurf(ji,jj)
                icount_night(ji,jj)      = icount_night(ji,jj) + imask_night(ji,jj)
@@ -786,15 +733,15 @@
          zdaystp = 1.0 / REAL( kdaystp )
          IF ( idayend == 0 ) THEN
-            IF (lwp) WRITE(numout,*) 'Calculating surfdataqc%vdmean on time-step: ',kt
+            IF (lwp) WRITE(numout,*) 'Calculating surfdataqc%vdmean on time-step: ', kt
             DO jj = 1, jpj
                DO ji = 1, jpi
                   ! Test if "no night" point
                   IF ( icount_night(ji,jj) > 0 ) THEN
-                     surfdataqc%vdmean(ji,jj) = surfdataqc%vdmean(ji,jj) &
-                       &                        / REAL( icount_night(ji,jj) )
+                     surfdataqc%vdmean(ji,jj,kvar) = surfdataqc%vdmean(ji,jj,kvar) &
+                       &                             / REAL( icount_night(ji,jj) )
                   ELSE
                      !At locations where there is no night (e.g. poles),
                      ! calculate daily mean instead of night-time mean.
-                     surfdataqc%vdmean(ji,jj) = zmeanday(ji,jj) * zdaystp
+                     surfdataqc%vdmean(ji,jj,kvar) = zmeanday(ji,jj) * zdaystp
                   ENDIF
                END DO
@@ -814,15 +761,24 @@
          & zmask(imaxifp,imaxjfp,isurf), &
          & zsurf(imaxifp,imaxjfp,isurf), &
-         & zsurftmp(imaxifp,imaxjfp,isurf),  &
-         & zglamf(imaxifp+1,imaxjfp+1,isurf), &
-         & zgphif(imaxifp+1,imaxjfp+1,isurf), &
-         & igrdip1(imaxifp+1,imaxjfp+1,isurf), &
-         & igrdjp1(imaxifp+1,imaxjfp+1,isurf) &
+         & zsurftmp(imaxifp,imaxjfp,isurf) &
          & )
+
+      IF ( k2dint > 4 ) THEN
+         ALLOCATE( &
+            & zglamf(imaxifp+1,imaxjfp+1,isurf),  &
+            & zgphif(imaxifp+1,imaxjfp+1,isurf),  &
+            & igrdip1(imaxifp+1,imaxjfp+1,isurf), &
+            & igrdjp1(imaxifp+1,imaxjfp+1,isurf)  &
+            & )
+      ENDIF
+
+      IF ( ldclim ) THEN
+         ALLOCATE( zclim(imaxifp,imaxjfp,isurf) )
+      ENDIF
 
       DO jobs = surfdataqc%nsurfup + 1, surfdataqc%nsurfup + isurf
          iobs = jobs - surfdataqc%nsurfup
          DO ji = 0, imaxifp
-            imodi = surfdataqc%mi(jobs) - int(imaxifp/2) + ji - 1
+            imodi = surfdataqc%mi(jobs,kvar) - int(imaxifp/2) + ji - 1
             !
             !Deal with wrap around in longitude
@@ -831,5 +787,5 @@
             !
             DO jj = 0, imaxjfp
-               imodj = surfdataqc%mj(jobs) - int(imaxjfp/2) + jj - 1
+               imodj = surfdataqc%mj(jobs,kvar) - int(imaxjfp/2) + jj - 1
                !If model values are out of the domain to the north/south then
                !set them to be the edge of the domain
@@ -837,6 +793,8 @@
                IF ( imodj > jpjglo ) imodj = jpjglo
                !
-               igrdip1(ji+1,jj+1,iobs) = imodi
-               igrdjp1(ji+1,jj+1,iobs) = imodj
+               IF ( k2dint > 4 ) THEN
+                  igrdip1(ji+1,jj+1,iobs) = imodi
+                  igrdjp1(ji+1,jj+1,iobs) = imodj
+               ENDIF
                !
                IF ( ji >= 1 .AND. jj >= 1 ) THEN
@@ -855,10 +813,29 @@
       CALL obs_int_comm_2d( imaxifp, imaxjfp, isurf, kpi, kpj, &
          &                  igrdi, igrdj, psurfmask, zmask )
-      CALL obs_int_comm_2d( imaxifp, imaxjfp, isurf, kpi, kpj, &
-         &                  igrdi, igrdj, psurf, zsurf )
-      CALL obs_int_comm_2d( imaxifp+1, imaxjfp+1, isurf, kpi, kpj, &
-         &                  igrdip1, igrdjp1, glamf, zglamf )
-      CALL obs_int_comm_2d( imaxifp+1, imaxjfp+1, isurf, kpi, kpj, &
-         &                  igrdip1, igrdjp1, gphif, zgphif )
+
+      ! At the end of the averaging period get interpolated means
+      IF ( ldtime_mean ) THEN
+         IF ( imeanend == 0 ) THEN
+            ALLOCATE( zsurfm(imaxifp,imaxjfp,isurf) )
+            IF (lwp) WRITE(numout,*)' Interpolating the time mean values on time step: ', kt
+            CALL obs_int_comm_2d( imaxifp, imaxjfp, isurf, kpi, kpj, &
+               &                  igrdi, igrdj, surfdataqc%vdmean(:,:,kvar), zsurfm )
+         ENDIF
+      ELSE
+         CALL obs_int_comm_2d( imaxifp, imaxjfp, isurf, kpi, kpj, &
+            &                  igrdi, igrdj, psurf, zsurf )
+      ENDIF
+
+      IF ( k2dint > 4 ) THEN 
+         CALL obs_int_comm_2d( imaxifp+1, imaxjfp+1, isurf, kpi, kpj, &
+            &                  igrdip1, igrdjp1, glamf, zglamf )
+         CALL obs_int_comm_2d( imaxifp+1, imaxjfp+1, isurf, kpi, kpj, &
+            &                  igrdip1, igrdjp1, gphif, zgphif )
+      ENDIF
+      
+      IF ( ldclim ) THEN
+         CALL obs_int_comm_2d( imaxifp, imaxjfp, isurf, kpi, kpj, &
+            &                  igrdi, igrdj, pclim, zclim )
+      ENDIF
 
       ! At the end of the day get interpolated means
@@ -870,5 +847,5 @@
 
          CALL obs_int_comm_2d( imaxifp,imaxjfp, isurf, kpi, kpj, igrdi, igrdj, &
-            &               surfdataqc%vdmean(:,:), zsurfm )
+            &               surfdataqc%vdmean(:,:,kvar), zsurfm )
 
       ENDIF
@@ -900,6 +877,6 @@
          zphi = surfdataqc%rphi(jobs)
 
-         IF ( ldnightav .AND. idayend == 0 ) THEN
-            ! Night-time averaged data
+         IF ( ( ldnightav .AND. idayend == 0 ) .OR. (ldtime_mean .AND. imeanend == 0) ) THEN
+            ! Night-time or N=kmeanstp timestep averaged data
             zsurftmp(:,:,iobs) = zsurfm(:,:,iobs)
          ELSE
@@ -907,40 +884,73 @@
          ENDIF
 
-         IF ( k2dint <= 4 ) THEN
-
-            ! Get weights to interpolate the model value to the observation point
-            CALL obs_int_h2d_init( 1, 1, k2dint, zlam, zphi,         &
-               &                   zglam(:,:,iobs), zgphi(:,:,iobs), &
-               &                   zmask(:,:,iobs), zweig, zobsmask )
-
-            ! Interpolate the model value to the observation point 
-            CALL obs_int_h2d( 1, 1, zweig, zsurftmp(:,:,iobs), zext )
-
-         ELSE
-
-            ! Get weights to average the model SLA to the observation footprint
-            CALL obs_avg_h2d_init( 1, 1, imaxifp, imaxjfp, k2dint, zlam,  zphi, &
-               &                   zglam(:,:,iobs), zgphi(:,:,iobs), &
-               &                   zglamf(:,:,iobs), zgphif(:,:,iobs), &
-               &                   zmask(:,:,iobs), plamscl, pphiscl, &
-               &                   lindegrees, zweig, zobsmask )
-
-            ! Average the model SST to the observation footprint
-            CALL obs_avg_h2d( 1, 1, imaxifp, imaxjfp, &
-               &              zweig, zsurftmp(:,:,iobs),  zext )
-
-         ENDIF
-
-         IF ( TRIM(surfdataqc%cvars(1)) == 'SLA' .AND. surfdataqc%nextra == 2 ) THEN
-            ! ... Remove the MDT from the SSH at the observation point to get the SLA
-            surfdataqc%rext(jobs,1) = zext(1)
-            surfdataqc%rmod(jobs,1) = surfdataqc%rext(jobs,1) - surfdataqc%rext(jobs,2)
-         ELSE
-            surfdataqc%rmod(jobs,1) = zext(1)
-         ENDIF
-         
-         IF ( zext(1) == obfillflt ) THEN
-            ! If the observation value is a fill value, set QC flag to bad
-            surfdataqc%nqc(jobs) = 4
+         IF ( ( .NOT. ldtime_mean ) .OR. ( ldtime_mean .AND. imeanend == 0) ) THEN
+
+            IF ( k2dint <= 4 ) THEN
+
+               ! Get weights to interpolate the model value to the observation point
+               CALL obs_int_h2d_init( 1, 1, k2dint, zlam, zphi,         &
+                  &                   zglam(:,:,iobs), zgphi(:,:,iobs), &
+                  &                   zmask(:,:,iobs), zweig, zobsmask )
+
+               ! Interpolate the model value to the observation point 
+               CALL obs_int_h2d( 1, 1, zweig, zsurftmp(:,:,iobs), zext )
+
+               IF ( ldclim ) THEN
+                  CALL obs_int_h2d( 1, 1, zweig, zclim(:,:,iobs), zclm )
+               ENDIF
+
+            ELSE
+
+               ! Get weights to average the model field to the observation footprint
+               CALL obs_avg_h2d_init( 1, 1, imaxifp, imaxjfp, k2dint, zlam,  zphi, &
+                  &                   zglam(:,:,iobs), zgphi(:,:,iobs), &
+                  &                   zglamf(:,:,iobs), zgphif(:,:,iobs), &
+                  &                   zmask(:,:,iobs), plamscl, pphiscl, &
+                  &                   lindegrees, zweig, zobsmask )
+
+               ! Average the model field to the observation footprint
+               CALL obs_avg_h2d( 1, 1, imaxifp, imaxjfp, &
+                  &              zweig, zsurftmp(:,:,iobs),  zext )
+
+               IF ( ldclim ) THEN
+                  CALL obs_avg_h2d( 1, 1, imaxifp, imaxjfp, &
+                     &              zweig, zclim(:,:,iobs),  zclm )
+               ENDIF
+
+            ENDIF
+
+            IF ( TRIM(surfdataqc%cvars(kvar)) == cobsname_sla .AND. PRESENT(kssh) .AND. PRESENT(kmdt) ) THEN
+               ! ... Remove the MDT from the SSH at the observation point to get the SLA
+               surfdataqc%radd(jobs,kssh,kvar) = zext(1)
+               surfdataqc%rmod(jobs,kvar) = surfdataqc%radd(jobs,kssh,kvar) - surfdataqc%rext(jobs,kmdt)
+#if defined key_si3 || defined key_cice
+            ELSE IF ( TRIM(surfdataqc%cvars(kvar)) == cobsname_fbd .AND. PRESENT(kfbd) .AND. PRESENT(ksnow) ) THEN
+               surfdataqc%rmod(jobs,kvar) = zext(1)
+               ! Convert radar freeboard to true freeboard
+               ! (add 1/4 snow depth; 1/4 based on ratio of speed of light in vacuum
+               !  compared to snow (3.0e8 vs 2.4e8 m/s))
+               surfdataqc%radd(jobs,kfbd,kvar) = surfdataqc%robs(jobs,kvar)
+               surfdataqc%robs(jobs,kvar) = surfdataqc%radd(jobs,kfbd,kvar) + 0.25*surfdataqc%rext(jobs,ksnow)
+               ! If the corrected freeboard observation is outside -0.3 to 3.0 m (CPOM) then set the QC flag to bad
+               IF ((surfdataqc%robs(jobs,kvar) < -0.3) .OR. (surfdataqc%robs(jobs,kvar) > 3.0)) THEN
+                  surfdataqc%nqc(jobs) = 4
+               ENDIF           
+               ! Convert corrected freeboard to ice thickness following Tilling et al. (2016)
+               surfdataqc%robs(jobs,kvar) = (surfdataqc%robs(jobs,kvar)*rhow + surfdataqc%rext(jobs,ksnow)*rhos)/ &
+                  &                         (rhow - rhoi)
+#endif
+            ELSE
+               surfdataqc%rmod(jobs,kvar) = zext(1)
+            ENDIF
+
+            IF ( ldclim ) THEN
+               surfdataqc%radd(jobs,kclim,kvar) = zclm(1)
+            ENDIF
+
+            IF ( zext(1) == obfillflt ) THEN
+               ! If the observation value is a fill value, set QC flag to bad
+               surfdataqc%nqc(jobs) = 4
+            ENDIF
+
          ENDIF
 
@@ -956,13 +966,22 @@
          & zmask, &
          & zsurf, &
-         & zsurftmp, &
-         & zglamf, &
-         & zgphif, &
-         & igrdip1,&
-         & igrdjp1 &
+         & zsurftmp &
          & )
 
-      ! At the end of the day also deallocate night-time mean array
-      IF ( idayend == 0 .AND. ldnightav ) THEN
+      IF ( k2dint > 4 ) THEN
+         DEALLOCATE( &     
+            & zglamf, &
+            & zgphif, &
+            & igrdip1,&
+            & igrdjp1 &
+            & )
+      ENDIF
+            
+      IF ( ldclim ) THEN
+         DEALLOCATE( zclim )
+      ENDIF
+
+      ! At the end of the day also deallocate time mean array
+      IF ( ( idayend == 0 .AND. ldnightav ) .OR. ( imeanend == 0 .AND. ldtime_mean ) ) THEN
          DEALLOCATE( &
             & zsurfm  &
@@ -970,5 +989,7 @@
       ENDIF
       !
-      surfdataqc%nsurfup = surfdataqc%nsurfup + isurf
+      IF ( kvar == surfdataqc%nvar ) THEN
+         surfdataqc%nsurfup = surfdataqc%nsurfup + isurf
+      ENDIF
       !
    END SUBROUTINE obs_surf_opt
Index: NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_prep.F90
===================================================================
--- NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_prep.F90	(revision 15731)
+++ NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_prep.F90	(revision 15799)
@@ -22,4 +22,8 @@
    USE obs_inter_sup      ! Interpolation support
    USE obs_oper           ! Observation operators
+   USE obs_group_def, ONLY : &  ! Observation variable information
+      & cobsname_uvel, &
+      & cobsname_vvel, &
+      & imaxavtypes
    USE lib_mpp, ONLY :   ctl_warn, ctl_stop
    USE bdy_oce, ONLY : &        ! Boundary information
@@ -42,8 +46,11 @@
 CONTAINS
 
-   SUBROUTINE obs_pre_surf( surfdata, surfdataqc, ld_nea, ld_bound_reject, &
-                            kqc_cutoff )
-      !!----------------------------------------------------------------------
-      !!                    ***  ROUTINE obs_pre_sla  ***
+   SUBROUTINE obs_pre_surf( surfdata, surfdataqc, &
+      &                     kpi, kpj, &   
+      &                     zmask, pglam, pgphi, &
+      &                     ld_nea, ld_bound_reject, &
+      &                     kqc_cutoff )
+      !!----------------------------------------------------------------------
+      !!                    ***  ROUTINE obs_pre_surf  ***
       !!
       !! ** Purpose : First level check and screening of surface observations
@@ -65,8 +72,14 @@
       !! * Arguments
       TYPE(obs_surf), INTENT(INOUT) :: surfdata    ! Full set of surface data
-      TYPE(obs_surf), INTENT(INOUT) :: surfdataqc   ! Subset of surface data not failing screening
-      LOGICAL, INTENT(IN) :: ld_nea         ! Switch for rejecting observation near land
+      TYPE(obs_surf), INTENT(INOUT) :: surfdataqc  ! Subset of surface data not failing screening
+      INTEGER, INTENT(IN) :: kpi, kpj              ! Local domain sizes      
+      REAL(wp), INTENT(IN), DIMENSION(kpi,kpj,surfdata%nvar) :: &
+         & zmask      
+      REAL(wp), INTENT(IN), DIMENSION(kpi,kpj,surfdata%nvar) :: &
+         & pglam, &
+         & pgphi
+      LOGICAL, INTENT(IN) :: ld_nea                ! Switch for rejecting observation near land
       LOGICAL, INTENT(IN) :: ld_bound_reject       ! Switch for rejecting obs near the boundary
-      INTEGER, INTENT(IN), OPTIONAL :: kqc_cutoff   ! cut off for QC value
+      INTEGER, INTENT(IN), OPTIONAL :: kqc_cutoff  ! cut off for QC value
       !! * Local declarations
       INTEGER :: iqc_cutoff = 255   ! cut off for QC value
@@ -77,23 +90,26 @@
       INTEGER :: imin0
       INTEGER :: icycle       ! Current assimilation cycle
-                              ! Counters for observations that
-      INTEGER :: iotdobs      !  - outside time domain
-      INTEGER :: iosdsobs     !  - outside space domain
-      INTEGER :: ilansobs     !  - within a model land cell
-      INTEGER :: inlasobs     !  - close to land
-      INTEGER :: igrdobs      !  - fail the grid search
-      INTEGER :: ibdysobs     !  - close to open boundary
-                              ! Global counters for observations that
-      INTEGER :: iotdobsmpp     !  - outside time domain
-      INTEGER :: iosdsobsmpp    !  - outside space domain
-      INTEGER :: ilansobsmpp    !  - within a model land cell
-      INTEGER :: inlasobsmpp    !  - close to land
-      INTEGER :: igrdobsmpp     !  - fail the grid search
-      INTEGER :: ibdysobsmpp  !  - close to open boundary
+                                                        ! Counters for observations that are
+      INTEGER                           :: iotdobs      !  - outside time domain
+      INTEGER, DIMENSION(surfdata%nvar) :: iosdsobs     !  - outside space domain
+      INTEGER, DIMENSION(surfdata%nvar) :: ilansobs     !  - within a model land cell
+      INTEGER, DIMENSION(surfdata%nvar) :: inlasobs     !  - close to land
+      INTEGER, DIMENSION(surfdata%nvar) :: ibdysobs     !  - close to open boundary
+      INTEGER                           :: igrdobs      !  - fail the grid search      
+                                                        ! Global counters for observations that
+      INTEGER                           :: iotdobsmpp   !  - outside time domain
+      INTEGER, DIMENSION(surfdata%nvar) :: iosdsobsmpp  !  - outside space domain
+      INTEGER, DIMENSION(surfdata%nvar) :: ilansobsmpp  !  - within a model land cell
+      INTEGER, DIMENSION(surfdata%nvar) :: inlasobsmpp  !  - close to land
+      INTEGER, DIMENSION(surfdata%nvar) :: ibdysobsmpp  !  - close to open boundary
+      INTEGER                           :: igrdobsmpp   !  - fail the grid search
+
       LOGICAL, DIMENSION(:), ALLOCATABLE :: & 
          & llvalid            ! SLA data selection
-      INTEGER :: jobs         ! Obs. loop variable
+      INTEGER :: jobs         ! Obs. loop counter
+      INTEGER :: jvar         ! Variable loop counter
       INTEGER :: jstp         ! Time loop variable
       INTEGER :: inrc         ! Time index variable
+      CHARACTER(LEN=256) :: cout1  ! Diagnostic output line
       !!----------------------------------------------------------------------
 
@@ -110,15 +126,15 @@
       icycle = nn_no     ! Assimilation cycle
 
-      ! Diagnotics counters for various failures.
+      ! Diagnostic counters for various failures.
 
       iotdobs  = 0
       igrdobs  = 0
-      iosdsobs = 0
-      ilansobs = 0
-      inlasobs = 0
-      ibdysobs = 0 
+      iosdsobs(:) = 0
+      ilansobs(:) = 0
+      inlasobs(:) = 0
+      ibdysobs(:) = 0 
 
       ! Set QC cutoff to optional value if provided
-      IF ( PRESENT(kqc_cutoff) ) iqc_cutoff=kqc_cutoff
+      IF ( PRESENT(kqc_cutoff) ) iqc_cutoff = kqc_cutoff
 
       ! -----------------------------------------------------------------------
@@ -138,6 +154,8 @@
       ! -----------------------------------------------------------------------
 
-      CALL obs_coo_grd( surfdata%nsurf,   surfdata%mi, surfdata%mj, &
-         &              surfdata%nqc,     igrdobs                         )
+      DO jvar = 1, surfdata%nvar
+         CALL obs_coo_grd( surfdata%nsurf,      surfdata%mi(:,jvar),         &
+            &              surfdata%mj(:,jvar), surfdata%nqc,        igrdobs )
+      END DO
 
       CALL obs_mpp_sum_integer( igrdobs, igrdobsmpp )
@@ -147,19 +165,20 @@
       ! -----------------------------------------------------------------------
 
-      CALL obs_coo_spc_2d( surfdata%nsurf,              &
-         &                 jpi,          jpj,          &
-         &                 surfdata%mi,   surfdata%mj,   & 
-         &                 surfdata%rlam, surfdata%rphi, &
-         &                 glamt,        gphit,        &
-         &                 tmask(:,:,1), surfdata%nqc,  &
-         &                 iosdsobs,     ilansobs,     &
-         &                 inlasobs,     ld_nea,       &
-         &                 ibdysobs,     ld_bound_reject, &
-         &                 iqc_cutoff                     )
-
-      CALL obs_mpp_sum_integer( iosdsobs, iosdsobsmpp )
-      CALL obs_mpp_sum_integer( ilansobs, ilansobsmpp )
-      CALL obs_mpp_sum_integer( inlasobs, inlasobsmpp )
-      CALL obs_mpp_sum_integer( ibdysobs, ibdysobsmpp )
+      DO jvar = 1, surfdata%nvar
+         CALL obs_coo_spc_2d( surfdata%nsurf,                           &
+            &                 jpi,                 jpj,                 &
+            &                 surfdata%mi(:,jvar), surfdata%mj(:,jvar), & 
+            &                 surfdata%rlam,       surfdata%rphi,       &
+            &                 pglam(:,:,jvar),     pgphi(:,:,jvar),     &
+            &                 zmask(:,:,jvar),     surfdata%nqc,        &
+            &                 iosdsobs(jvar),      ilansobs(jvar),      &
+            &                 inlasobs(jvar),      ld_nea,              &
+            &                 ibdysobs(jvar),      ld_bound_reject,     &
+            &                 iqc_cutoff                     )
+         CALL obs_mpp_sum_integer( iosdsobs(jvar), iosdsobsmpp(jvar) )
+         CALL obs_mpp_sum_integer( ilansobs(jvar), ilansobsmpp(jvar) )
+         CALL obs_mpp_sum_integer( inlasobs(jvar), inlasobsmpp(jvar) )
+         CALL obs_mpp_sum_integer( ibdysobs(jvar), ibdysobsmpp(jvar) )
+      END DO
 
       ! -----------------------------------------------------------------------
@@ -191,30 +210,41 @@
       
       IF(lwp) THEN
+         DO jvar = 1, surfdataqc%nvar       
+            IF ( jvar == 1 ) THEN
+               cout1 = TRIM(surfdataqc%cvars(1))                  
+            ELSE
+               WRITE(cout1,'(A,A1,A)') TRIM(cout1), '/', TRIM(surfdataqc%cvars(jvar))            
+            ENDIF
+         END DO
+               
          WRITE(numout,*)
-         WRITE(numout,*) ' '//surfdataqc%cvars(1)//' data outside time domain                  = ', &
+         WRITE(numout,*) ' '//TRIM(cout1)//' data outside time domain                  = ', &
             &            iotdobsmpp
-         WRITE(numout,*) ' Remaining '//surfdataqc%cvars(1)//' data that failed grid search    = ', &
+         WRITE(numout,*) ' Remaining '//TRIM(cout1)//' data that failed grid search    = ', &
             &            igrdobsmpp
-         WRITE(numout,*) ' Remaining '//surfdataqc%cvars(1)//' data outside space domain       = ', &
-            &            iosdsobsmpp
-         WRITE(numout,*) ' Remaining '//surfdataqc%cvars(1)//' data at land points             = ', &
-            &            ilansobsmpp
-         IF (ld_nea) THEN
-            WRITE(numout,*) ' Remaining '//surfdataqc%cvars(1)//' data near land points (removed) = ', &
-               &            inlasobsmpp
-         ELSE
-            WRITE(numout,*) ' Remaining '//surfdataqc%cvars(1)//' data near land points (kept)    = ', &
-               &            inlasobsmpp
-         ENDIF
-         WRITE(numout,*) ' Remaining '//surfdataqc%cvars(1)//' data near open boundary (removed) = ', &
-            &            ibdysobsmpp  
-         WRITE(numout,*) ' '//surfdataqc%cvars(1)//' data accepted                             = ', &
-            &            surfdataqc%nsurfmpp
+
+         DO jvar = 1, surfdataqc%nvar            
+            WRITE(numout,*) ' Remaining '//surfdataqc%cvars(jvar)//' data outside space domain       = ', &
+                &            iosdsobsmpp(jvar)
+             WRITE(numout,*) ' Remaining '//surfdataqc%cvars(jvar)//' data at land points             = ', &
+                &            ilansobsmpp(jvar)
+             IF (ld_nea) THEN
+                WRITE(numout,*) ' Remaining '//surfdataqc%cvars(jvar)//' data near land points (removed) = ', &
+                   &            inlasobsmpp(jvar)
+             ELSE
+                WRITE(numout,*) ' Remaining '//surfdataqc%cvars(jvar)//' data near land points (kept)    = ', &
+                   &            inlasobsmpp(jvar)
+             ENDIF     
+             WRITE(numout,*) ' Remaining '//surfdataqc%cvars(jvar)//' data near open boundary (removed) = ', &
+                &            ibdysobsmpp(jvar)
+          END DO
+          WRITE(numout,*) ' '//TRIM(cout1)//' data accepted                             = ', &
+             &            surfdataqc%nsurfmpp
 
          WRITE(numout,*)
          WRITE(numout,*) ' Number of observations per time step :'
          WRITE(numout,*)
-         WRITE(numout,'(10X,A,10X,A)')'Time step',surfdataqc%cvars(1)
-         WRITE(numout,'(10X,A,5X,A)')'---------','-----------------'
+         WRITE(numout,'(10X,A,10X,A)') 'Time step', TRIM(cout1)
+         WRITE(numout,'(10X,A,5X,A)')  '---------', '-----------------'
          CALL FLUSH(numout)
       ENDIF
@@ -241,7 +271,7 @@
 
 
-   SUBROUTINE obs_pre_prof( profdata, prodatqc, ld_var1, ld_var2, &
+   SUBROUTINE obs_pre_prof( profdata, prodatqc, ld_var, &
       &                     kpi, kpj, kpk, &
-      &                     zmask1, pglam1, pgphi1, zmask2, pglam2, pgphi2,  &
+      &                     zmask, pglam, pgphi,  &
       &                     ld_nea, ld_bound_reject, kdailyavtypes,  kqc_cutoff )
 
@@ -269,6 +299,6 @@
       TYPE(obs_prof), INTENT(INOUT) :: profdata   ! Full set of profile data
       TYPE(obs_prof), INTENT(INOUT) :: prodatqc   ! Subset of profile data not failing screening
-      LOGICAL, INTENT(IN) :: ld_var1              ! Observed variables switches
-      LOGICAL, INTENT(IN) :: ld_var2
+      LOGICAL, DIMENSION(profdata%nvar), INTENT(IN) :: &
+         & ld_var                                 ! Observed variables switches
       LOGICAL, INTENT(IN) :: ld_nea               ! Switch for rejecting observation near land
       LOGICAL, INTENT(IN) :: ld_bound_reject      ! Switch for rejecting observations near the boundary
@@ -276,12 +306,9 @@
       INTEGER, DIMENSION(imaxavtypes), OPTIONAL :: &
          & kdailyavtypes                          ! Types for daily averages
-      REAL(wp), INTENT(IN), DIMENSION(kpi,kpj,kpk) :: &
-         & zmask1, &
-         & zmask2
-      REAL(wp), INTENT(IN), DIMENSION(kpi,kpj) :: &
-         & pglam1, &
-         & pglam2, &
-         & pgphi1, &
-         & pgphi2
+      REAL(wp), INTENT(IN), DIMENSION(kpi,kpj,kpk,profdata%nvar) :: &
+         & zmask
+      REAL(wp), INTENT(IN), DIMENSION(kpi,kpj,profdata%nvar) :: &
+         & pglam, &
+         & pgphi
       INTEGER, INTENT(IN), OPTIONAL :: kqc_cutoff   ! cut off for QC value
 
@@ -294,37 +321,33 @@
       INTEGER :: imin0
       INTEGER :: icycle       ! Current assimilation cycle
-                              ! Counters for observations that are
-      INTEGER :: iotdobs      !  - outside time domain
-      INTEGER :: iosdv1obs    !  - outside space domain (variable 1)
-      INTEGER :: iosdv2obs    !  - outside space domain (variable 2)
-      INTEGER :: ilanv1obs    !  - within a model land cell (variable 1)
-      INTEGER :: ilanv2obs    !  - within a model land cell (variable 2)
-      INTEGER :: inlav1obs    !  - close to land (variable 1)
-      INTEGER :: inlav2obs    !  - close to land (variable 2)
-      INTEGER :: ibdyv1obs    !  - boundary (variable 1) 
-      INTEGER :: ibdyv2obs    !  - boundary (variable 2)      
-      INTEGER :: igrdobs      !  - fail the grid search
-      INTEGER :: iuvchku      !  - reject u if v rejected and vice versa
-      INTEGER :: iuvchkv      !
-                              ! Global counters for observations that are
-      INTEGER :: iotdobsmpp   !  - outside time domain
-      INTEGER :: iosdv1obsmpp !  - outside space domain (variable 1)
-      INTEGER :: iosdv2obsmpp !  - outside space domain (variable 2)
-      INTEGER :: ilanv1obsmpp !  - within a model land cell (variable 1)
-      INTEGER :: ilanv2obsmpp !  - within a model land cell (variable 2)
-      INTEGER :: inlav1obsmpp !  - close to land (variable 1)
-      INTEGER :: inlav2obsmpp !  - close to land (variable 2)
-      INTEGER :: ibdyv1obsmpp !  - boundary (variable 1) 
-      INTEGER :: ibdyv2obsmpp !  - boundary (variable 2)      
-      INTEGER :: igrdobsmpp   !  - fail the grid search
-      INTEGER :: iuvchkumpp   !  - reject var1 if var2 rejected and vice versa
-      INTEGER :: iuvchkvmpp   !
+                                                       ! Counters for observations that are
+      INTEGER                           :: iotdobs     !  - outside time domain
+      INTEGER, DIMENSION(profdata%nvar) :: iosdvobs    !  - outside space domain
+      INTEGER, DIMENSION(profdata%nvar) :: ilanvobs    !  - within a model land cell
+      INTEGER, DIMENSION(profdata%nvar) :: inlavobs    !  - close to land
+      INTEGER, DIMENSION(profdata%nvar) :: ibdyvobs    !  - boundary   
+      INTEGER                           :: igrdobs     !  - fail the grid search
+      INTEGER                           :: iuvchku     !  - reject UVEL if VVEL rejected
+      INTEGER                           :: iuvchkv     !  - reject VVEL if UVEL rejected
+                                                       ! Global counters for observations that are
+      INTEGER                           :: iotdobsmpp  !  - outside time domain
+      INTEGER, DIMENSION(profdata%nvar) :: iosdvobsmpp !  - outside space domain
+      INTEGER, DIMENSION(profdata%nvar) :: ilanvobsmpp !  - within a model land cell
+      INTEGER, DIMENSION(profdata%nvar) :: inlavobsmpp !  - close to land
+      INTEGER, DIMENSION(profdata%nvar) :: ibdyvobsmpp !  - boundary
+      INTEGER :: igrdobsmpp                            !  - fail the grid search
+      INTEGER :: iuvchkumpp                            !  - reject UVEL if VVEL rejected
+      INTEGER :: iuvchkvmpp                            !  - reject VVEL if UVEL rejected
+      INTEGER :: iuvar                                 !  - UVEL index
+      INTEGER :: ivvar                                 !  - VVEL index
       TYPE(obs_prof_valid) ::  llvalid      ! Profile selection 
       TYPE(obs_prof_valid), DIMENSION(profdata%nvar) :: &
-         & llvvalid           ! var1,var2 selection 
+         & llvvalid           ! var selection 
       INTEGER :: jvar         ! Variable loop variable
       INTEGER :: jobs         ! Obs. loop variable
       INTEGER :: jstp         ! Time loop variable
       INTEGER :: inrc         ! Time index variable
+      CHARACTER(LEN=256) :: cout1  ! Diagnostic output line
+      CHARACTER(LEN=256) :: cout2  ! Diagnostic output line
       !!----------------------------------------------------------------------
 
@@ -341,22 +364,18 @@
       icycle = nn_no     ! Assimilation cycle
 
-      ! Diagnotics counters for various failures.
-
-      iotdobs   = 0
-      igrdobs   = 0
-      iosdv1obs = 0
-      iosdv2obs = 0
-      ilanv1obs = 0
-      ilanv2obs = 0
-      inlav1obs = 0
-      inlav2obs = 0
-      ibdyv1obs = 0
-      ibdyv2obs = 0
-      iuvchku   = 0
-      iuvchkv   = 0
+      ! Diagnostic counters for various failures.
+
+      iotdobs     = 0
+      igrdobs     = 0
+      iosdvobs(:) = 0
+      ilanvobs(:) = 0
+      inlavobs(:) = 0
+      ibdyvobs(:) = 0
+      iuvchku     = 0
+      iuvchkv     = 0
 
 
       ! Set QC cutoff to optional value if provided
-      IF ( PRESENT(kqc_cutoff) ) iqc_cutoff=kqc_cutoff
+      IF ( PRESENT(kqc_cutoff) ) iqc_cutoff = kqc_cutoff
 
       ! -----------------------------------------------------------------------
@@ -387,8 +406,8 @@
       ! -----------------------------------------------------------------------
 
-      CALL obs_coo_grd( profdata%nprof,   profdata%mi(:,1), profdata%mj(:,1), &
-         &              profdata%nqc,     igrdobs                         )
-      CALL obs_coo_grd( profdata%nprof,   profdata%mi(:,2), profdata%mj(:,2), &
-         &              profdata%nqc,     igrdobs                         )
+      DO jvar = 1, profdata%nvar
+         CALL obs_coo_grd( profdata%nprof,   profdata%mi(:,jvar), profdata%mj(:,jvar), &
+            &              profdata%nqc,     igrdobs                         )
+      END DO
 
       CALL obs_mpp_sum_integer( igrdobs, igrdobsmpp )
@@ -405,47 +424,26 @@
       ! -----------------------------------------------------------------------
 
-      ! Variable 1
-      CALL obs_coo_spc_3d( profdata%nprof,        profdata%nvprot(1),   &
-         &                 profdata%npvsta(:,1),  profdata%npvend(:,1), &
-         &                 jpi,                   jpj,                  &
-         &                 jpk,                                         &
-         &                 profdata%mi,           profdata%mj,          &
-         &                 profdata%var(1)%mvk,                         &
-         &                 profdata%rlam,         profdata%rphi,        &
-         &                 profdata%var(1)%vdep,                        &
-         &                 pglam1,                pgphi1,               &
-         &                 gdept_1d,              zmask1,               &
-         &                 profdata%nqc,          profdata%var(1)%nvqc, &
-         &                 iosdv1obs,             ilanv1obs,            &
-         &                 inlav1obs,             ld_nea,               &
-         &                 ibdyv1obs,             ld_bound_reject,      &
-         &                 iqc_cutoff       )
-
-      CALL obs_mpp_sum_integer( iosdv1obs, iosdv1obsmpp )
-      CALL obs_mpp_sum_integer( ilanv1obs, ilanv1obsmpp )
-      CALL obs_mpp_sum_integer( inlav1obs, inlav1obsmpp )
-      CALL obs_mpp_sum_integer( ibdyv1obs, ibdyv1obsmpp )
-
-      ! Variable 2
-      CALL obs_coo_spc_3d( profdata%nprof,        profdata%nvprot(2),   &
-         &                 profdata%npvsta(:,2),  profdata%npvend(:,2), &
-         &                 jpi,                   jpj,                  &
-         &                 jpk,                                         &
-         &                 profdata%mi,           profdata%mj,          & 
-         &                 profdata%var(2)%mvk,                         &
-         &                 profdata%rlam,         profdata%rphi,        &
-         &                 profdata%var(2)%vdep,                        &
-         &                 pglam2,                pgphi2,               &
-         &                 gdept_1d,              zmask2,               &
-         &                 profdata%nqc,          profdata%var(2)%nvqc, &
-         &                 iosdv2obs,             ilanv2obs,            &
-         &                 inlav2obs,             ld_nea,               &
-         &                 ibdyv2obs,             ld_bound_reject,      &
-         &                 iqc_cutoff       )
-
-      CALL obs_mpp_sum_integer( iosdv2obs, iosdv2obsmpp )
-      CALL obs_mpp_sum_integer( ilanv2obs, ilanv2obsmpp )
-      CALL obs_mpp_sum_integer( inlav2obs, inlav2obsmpp )
-      CALL obs_mpp_sum_integer( ibdyv2obs, ibdyv2obsmpp )
+      DO jvar = 1, profdata%nvar
+         CALL obs_coo_spc_3d( profdata%nprof,          profdata%nvprot(jvar),   &
+            &                 profdata%npvsta(:,jvar), profdata%npvend(:,jvar), &
+            &                 jpi,                     jpj,                     &
+            &                 jpk,                                              &
+            &                 profdata%mi,             profdata%mj,             &
+            &                 profdata%var(jvar)%mvk,                           &
+            &                 profdata%rlam,           profdata%rphi,           &
+            &                 profdata%var(jvar)%vdep,                          &
+            &                 pglam(:,:,jvar),         pgphi(:,:,jvar),         &
+            &                 gdept_1d,                zmask(:,:,:,jvar),       &
+            &                 profdata%nqc,            profdata%var(jvar)%nvqc, &
+            &                 iosdvobs(jvar),          ilanvobs(jvar),          &
+            &                 inlavobs(jvar),          ld_nea,                  &
+            &                 ibdyvobs(jvar),          ld_bound_reject,         &
+            &                 iqc_cutoff       )
+
+         CALL obs_mpp_sum_integer( iosdvobs(jvar), iosdvobsmpp(jvar) )
+         CALL obs_mpp_sum_integer( ilanvobs(jvar), ilanvobsmpp(jvar) )
+         CALL obs_mpp_sum_integer( inlavobs(jvar), inlavobsmpp(jvar) )
+         CALL obs_mpp_sum_integer( ibdyvobs(jvar), ibdyvobsmpp(jvar) )
+      END DO
 
       ! -----------------------------------------------------------------------
@@ -453,6 +451,15 @@
       ! -----------------------------------------------------------------------
 
-      IF ( TRIM(profdata%cvars(1)) == 'UVEL' ) THEN
-         CALL obs_uv_rej( profdata, iuvchku, iuvchkv, iqc_cutoff )
+      iuvar = 0
+      ivvar = 0
+      DO jvar = 1,profdata%nvar
+         IF ( TRIM(profdata%cvars(jvar)) == cobsname_uvel ) THEN
+            iuvar = jvar
+         ELSEIF ( TRIM(profdata%cvars(jvar)) == cobsname_vvel ) THEN
+            ivvar = jvar
+         ENDIF
+      END DO
+      IF ( (iuvar > 0) .AND. (ivvar > 0) ) THEN
+         CALL obs_uv_rej( profdata, iuvchku, iuvchkv, iqc_cutoff, iuvar, ivvar )
          CALL obs_mpp_sum_integer( iuvchku, iuvchkumpp )
          CALL obs_mpp_sum_integer( iuvchkv, iuvchkvmpp )
@@ -498,54 +505,46 @@
       
          WRITE(numout,*)
-         WRITE(numout,*) ' Profiles outside time domain                     = ', &
+         WRITE(numout,*) ' Profiles outside time domain                       = ', &
             &            iotdobsmpp
-         WRITE(numout,*) ' Remaining profiles that failed grid search       = ', &
+         WRITE(numout,*) ' Remaining profiles that failed grid search         = ', &
             &            igrdobsmpp
-         WRITE(numout,*) ' Remaining '//prodatqc%cvars(1)//' data outside space domain       = ', &
-            &            iosdv1obsmpp
-         WRITE(numout,*) ' Remaining '//prodatqc%cvars(1)//' data at land points             = ', &
-            &            ilanv1obsmpp
-         IF (ld_nea) THEN
-            WRITE(numout,*) ' Remaining '//prodatqc%cvars(1)//' data near land points (removed) = ',&
-               &            inlav1obsmpp
-         ELSE
-            WRITE(numout,*) ' Remaining '//prodatqc%cvars(1)//' data near land points (kept)    = ',&
-               &            inlav1obsmpp
-         ENDIF
-         IF ( TRIM(profdata%cvars(1)) == 'UVEL' ) THEN
-            WRITE(numout,*) ' U observation rejected since V rejected     = ', &
-               &            iuvchku
-         ENDIF
-         WRITE(numout,*) ' Remaining '//prodatqc%cvars(1)//' data near open boundary (removed) = ',&
-               &            ibdyv1obsmpp
-         WRITE(numout,*) ' '//prodatqc%cvars(1)//' data accepted                             = ', &
-            &            prodatqc%nvprotmpp(1)
-         WRITE(numout,*) ' Remaining '//prodatqc%cvars(2)//' data outside space domain       = ', &
-            &            iosdv2obsmpp
-         WRITE(numout,*) ' Remaining '//prodatqc%cvars(2)//' data at land points             = ', &
-            &            ilanv2obsmpp
-         IF (ld_nea) THEN
-            WRITE(numout,*) ' Remaining '//prodatqc%cvars(2)//' data near land points (removed) = ',&
-               &            inlav2obsmpp
-         ELSE
-            WRITE(numout,*) ' Remaining '//prodatqc%cvars(2)//' data near land points (kept)    = ',&
-               &            inlav2obsmpp
-         ENDIF
-         IF ( TRIM(profdata%cvars(1)) == 'UVEL' ) THEN
-            WRITE(numout,*) ' V observation rejected since U rejected     = ', &
-               &            iuvchkv
-         ENDIF
-         WRITE(numout,*) ' Remaining '//prodatqc%cvars(2)//' data near open boundary (removed) = ',&
-               &            ibdyv2obsmpp
-         WRITE(numout,*) ' '//prodatqc%cvars(2)//' data accepted                             = ', &
-            &            prodatqc%nvprotmpp(2)
+         DO jvar = 1, profdata%nvar
+            WRITE(numout,*) ' Remaining '//prodatqc%cvars(jvar)//' data outside space domain       = ', &
+               &            iosdvobsmpp(jvar)
+            WRITE(numout,*) ' Remaining '//prodatqc%cvars(jvar)//' data at land points             = ', &
+               &            ilanvobsmpp(jvar)
+            IF (ld_nea) THEN
+               WRITE(numout,*) ' Remaining '//prodatqc%cvars(jvar)//' data near land points (removed) = ', &
+                  &            inlavobsmpp(jvar)
+            ELSE
+               WRITE(numout,*) ' Remaining '//prodatqc%cvars(jvar)//' data near land points (kept)    = ', &
+                  &            inlavobsmpp(jvar)
+            ENDIF
+            IF ( (iuvar > 0) .AND. (ivvar > 0) ) THEN
+               IF ( TRIM(profdata%cvars(jvar)) == cobsname_uvel ) THEN
+                  WRITE(numout,*) ' U observation rejected since V rejected     = ', &
+                     &            iuvchku
+               ELSE IF ( TRIM(profdata%cvars(jvar)) == cobsname_vvel ) THEN
+                  WRITE(numout,*) ' V observation rejected since U rejected     = ', &
+                     &            iuvchkv
+               ENDIF
+            ENDIF
+            WRITE(numout,*) ' Remaining '//prodatqc%cvars(jvar)//' data near open boundary (removed) = ', &
+                  &            ibdyvobsmpp(jvar)
+            WRITE(numout,*) ' '//prodatqc%cvars(jvar)//' data accepted                             = ', &
+               &            prodatqc%nvprotmpp(jvar)
+         END DO
 
          WRITE(numout,*)
          WRITE(numout,*) ' Number of observations per time step :'
          WRITE(numout,*)
-         WRITE(numout,'(10X,A,5X,A,5X,A,A)')'Time step','Profiles', &
-            &                               '     '//prodatqc%cvars(1)//'     ', &
-            &                               '     '//prodatqc%cvars(2)//'     '
-         WRITE(numout,998)
+         WRITE(cout1,'(10X,A9,5X,A8)') 'Time step', 'Profiles'
+         WRITE(cout2,'(10X,A9,5X,A8)') '---------', '--------'
+         DO jvar = 1, prodatqc%nvar
+            WRITE(cout1,'(A,5X,A11)') TRIM(cout1), TRIM(prodatqc%cvars(jvar))
+            WRITE(cout2,'(A,5X,A11)') TRIM(cout2), '-----------'
+         END DO
+         WRITE(numout,*) cout1
+         WRITE(numout,*) cout2
       ENDIF
       
@@ -574,12 +573,11 @@
          DO jstp = nit000 - 1, nitend
             inrc = jstp - nit000 + 2
-            WRITE(numout,999) jstp, prodatqc%npstpmpp(inrc), &
-               &                    prodatqc%nvstpmpp(inrc,1), &
-               &                    prodatqc%nvstpmpp(inrc,2)
+            WRITE(cout1,'(10X,I9,5X,I8)') jstp, prodatqc%npstpmpp(inrc)
+            DO jvar = 1, prodatqc%nvar
+               WRITE(cout1,'(A,5X,I11)') TRIM(cout1), prodatqc%nvstpmpp(inrc,jvar)
+            END DO
+            WRITE(numout,*) cout1
          END DO
       ENDIF
-
-998   FORMAT(10X,'---------',5X,'--------',5X,'-----------',5X,'----------------')
-999   FORMAT(10X,I9,5X,I8,5X,I11,5X,I8)
 
    END SUBROUTINE obs_pre_prof
@@ -834,5 +832,5 @@
       !! * Local declarations
       INTEGER :: jobs
-      INTEGER :: iqc_cutoff=255
+      INTEGER :: iqc_cutoff = 255
 
       !-----------------------------------------------------------------------
@@ -1122,5 +1120,6 @@
          & gdept_n,       &
          & ln_zco,        &
-         & ln_zps             
+         & ln_zps,        &
+         & mbkt
 
       !! * Arguments
@@ -1168,8 +1167,10 @@
       REAL(KIND=wp), DIMENSION(jpi,jpj) :: zbdymask
       REAL(KIND=wp), DIMENSION(2,2,kpk,kprofno) :: &
+         & zgdept, &
          & zgdepw
       REAL(KIND=wp), DIMENSION(2,2,kprofno) :: &
          & zglam, &           ! Model longitude at grid points
-         & zgphi              ! Model latitude at grid points
+         & zgphi, &           ! Model latitude at grid points
+         & zbathy             ! Index of deepest wet level at grid points
       INTEGER, DIMENSION(2,2,kprofno) :: &
          & igrdi, &           ! Grid i,j
@@ -1179,4 +1180,5 @@
       INTEGER :: iig, ijg           ! i,j of observation on model grid point.
       INTEGER :: jobs, jobsp, jk, ji, jj
+      REAL(KIND=wp) :: maxdept, maxdepw
       !!----------------------------------------------------------------------
 
@@ -1230,6 +1232,10 @@
       CALL obs_int_comm_2d( 2, 2, kprofno, kpi, kpj, igrdi, igrdj, plam, zglam )
       CALL obs_int_comm_2d( 2, 2, kprofno, kpi, kpj, igrdi, igrdj, pphi, zgphi )
+      CALL obs_int_comm_2d( 2, 2, kprofno, kpi, kpj, igrdi, igrdj, REAL(mbkt), zbathy )
+      ! Need to know the bathy depth for each observation for sco
       CALL obs_int_comm_3d( 2, 2, kprofno, kpi, kpj, kpk, igrdi, igrdj, gdepw_n(:,:,:), &
-        &                     zgdepw )
+        &                   zgdepw )
+      CALL obs_int_comm_3d( 2, 2, kprofno, kpi, kpj, kpk, igrdi, igrdj, gdept_n(:,:,:), &
+         &                  zgdept )
 
       DO jobs = 1, kprofno
@@ -1267,11 +1273,25 @@
          DO jobsp = kpstart(jobs), kpend(jobs)
 
+            ! Calculate max T and W depths of 2x2 grid
+            maxdept = zgdept(1,1,NINT(zbathy(1,1,jobs)),jobs)
+            maxdepw = zgdepw(1,1,NINT(zbathy(1,1,jobs))+1,jobs)
+            DO jj = 1, 2
+               DO ji = 1, 2
+                  IF ( zgdept(ji,jj,NINT(zbathy(ji,jj,jobs)),jobs) > maxdept ) THEN
+                     maxdept = zgdept(ji,jj,NINT(zbathy(ji,jj,jobs)),jobs)
+                  END IF
+                  IF ( zgdepw(ji,jj,NINT(zbathy(ji,jj,jobs))+1,jobs) > maxdepw ) THEN
+                     maxdepw = zgdepw(ji,jj,NINT(zbathy(ji,jj,jobs))+1,jobs)
+                  END IF
+               END DO
+            END DO
+
             ! Flag if the observation falls outside the model spatial domain
-            IF (       ( pobslam(jobs) < -180.         )       &
-               &  .OR. ( pobslam(jobs) >  180.         )       &
-               &  .OR. ( pobsphi(jobs) <  -90.         )       &
-               &  .OR. ( pobsphi(jobs) >   90.         )       &
-               &  .OR. ( pobsdep(jobsp) < 0.0          )       &
-               &  .OR. ( pobsdep(jobsp) > gdepw_1d(kpk)) ) THEN
+            IF (       ( pobslam(jobs) < -180.    )       &
+               &  .OR. ( pobslam(jobs) >  180.    )       &
+               &  .OR. ( pobsphi(jobs) <  -90.    )       &
+               &  .OR. ( pobsphi(jobs) >   90.    )       &
+               &  .OR. ( pobsdep(jobsp) < 0.0     )       &
+               &  .OR. ( pobsdep(jobsp) > gdepw_1d(kpk) ) ) THEN
                kobsqc(jobsp) = IBSET(kobsqc(jobsp),11)
                kosdobs = kosdobs + 1
@@ -1320,6 +1340,15 @@
             ! Set observation depth equal to that of the first model depth
             IF ( pobsdep(jobsp) <= pdep(1) ) THEN
-               pobsdep(jobsp) = pdep(1)  
-            ENDIF
+               pobsdep(jobsp) = pdep(1) 
+            ENDIF
+            !IF ( pobsdep(jobsp) < MINVAL(zgdept(1:2,1:2,1,jobs) ) ) THEN
+            !   pobsdep(jobsp) = MINVAL(zgdept(1:2,1:2,1,jobs))
+            !ENDIF
+
+            ! Set observation depth equal to that of the last wet T-point
+            !IF ( ( pobsdep(jobsp) > maxdept ) .AND. &
+            !   & ( pobsdep(jobsp) < maxdepw ) ) THEN
+            !   pobsdep(jobsp) = maxdept
+            !END IF
             
             IF (ln_bdy) THEN
@@ -1395,5 +1424,5 @@
 
 
-   SUBROUTINE obs_uv_rej( profdata, knumu, knumv, kqc_cutoff )
+   SUBROUTINE obs_uv_rej( profdata, knumu, knumv, kqc_cutoff, kuvar, kvvar )
       !!----------------------------------------------------------------------
       !!                    ***  ROUTINE obs_uv_rej ***
@@ -1412,5 +1441,7 @@
       INTEGER, INTENT(INOUT) :: knumu             ! Number of u rejected
       INTEGER, INTENT(INOUT) :: knumv             ! Number of v rejected
-      INTEGER, INTENT(IN) :: kqc_cutoff           ! QC cutoff value
+      INTEGER, INTENT(IN)    :: kqc_cutoff        ! QC cutoff value
+      INTEGER, INTENT(IN)    :: kuvar             ! Index of u
+      INTEGER, INTENT(IN)    :: kvvar             ! Index of v
       !
       INTEGER :: jprof
@@ -1421,6 +1452,6 @@
       DO jprof = 1, profdata%nprof      !==  Loop over profiles  ==!
          !
-         IF ( ( profdata%npvsta(jprof,1) /= profdata%npvsta(jprof,2) ) .OR. &
-            & ( profdata%npvend(jprof,1) /= profdata%npvend(jprof,2) ) ) THEN
+         IF ( ( profdata%npvsta(jprof,kuvar) /= profdata%npvsta(jprof,kvvar) ) .OR. &
+            & ( profdata%npvend(jprof,kuvar) /= profdata%npvend(jprof,kvvar) ) ) THEN
             !
             CALL ctl_stop('U,V profiles inconsistent in obs_uv_rej')
@@ -1429,14 +1460,14 @@
          ENDIF
          !
-         DO jobs = profdata%npvsta(jprof,1), profdata%npvend(jprof,1)
+         DO jobs = profdata%npvsta(jprof,kuvar), profdata%npvend(jprof,kuvar)
             !  
-            IF ( ( profdata%var(1)%nvqc(jobs) >  kqc_cutoff ) .AND. &
-               & ( profdata%var(2)%nvqc(jobs) <=  kqc_cutoff) ) THEN
-               profdata%var(2)%nvqc(jobs) = IBSET(profdata%var(1)%nvqc(jobs),15)
+            IF ( ( profdata%var(kuvar)%nvqc(jobs) >  kqc_cutoff ) .AND. &
+               & ( profdata%var(kvvar)%nvqc(jobs) <=  kqc_cutoff) ) THEN
+               profdata%var(kvvar)%nvqc(jobs) = IBSET(profdata%var(kuvar)%nvqc(jobs),15)
                knumv = knumv + 1
             ENDIF
-            IF ( ( profdata%var(2)%nvqc(jobs) >  kqc_cutoff ) .AND. &
-               & ( profdata%var(1)%nvqc(jobs) <=  kqc_cutoff) ) THEN
-               profdata%var(1)%nvqc(jobs) = IBSET(profdata%var(1)%nvqc(jobs),15)
+            IF ( ( profdata%var(kvvar)%nvqc(jobs) >  kqc_cutoff ) .AND. &
+               & ( profdata%var(kuvar)%nvqc(jobs) <=  kqc_cutoff) ) THEN
+               profdata%var(kuvar)%nvqc(jobs) = IBSET(profdata%var(kuvar)%nvqc(jobs),15)
                knumu = knumu + 1
             ENDIF
Index: NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_profiles.F90
===================================================================
--- NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_profiles.F90	(revision 15731)
+++ 	(revision )
@@ -1,39 +1,0 @@
-MODULE obs_profiles
-   !!=====================================================================
-   !!                       ***  MODULE  obs_profiles  ***
-   !! Observation diagnostics: Storage space for profile observations
-   !!                          arrays and additional flags etc.
-   !!=====================================================================
-   !!----------------------------------------------------------------------
-   !! NEMO/OCE 4.0 , NEMO Consortium (2018)
-   !! $Id$
-   !! Software governed by the CeCILL license (see ./LICENSE)
-   !!----------------------------------------------------------------------
-
-   
-   !! * Modules used 
-   USE obs_profiles_def ! Definition of profile data types and tools
-
-   IMPLICIT NONE
-   
-   SAVE
-
-   !! * Routine accessibility
-   PRIVATE
-
-   PUBLIC nprofsets, nprofvars, nprofextr, profdata, prodatqc
-   PUBLIC nvelosets, nvelovars, nveloextr, velodata, veldatqc
-   
-   !! * Shared Module variables
-   INTEGER :: nprofsets                    ! Total number of profile data sets
-   INTEGER :: nprofvars                    ! Total number of variables for profiles
-   INTEGER :: nprofextr                    ! Extra fields for each variable
-   TYPE(obs_prof), POINTER ::  profdata(:) ! Initial profile data
-   TYPE(obs_prof), POINTER ::  prodatqc(:) ! Profile data after quality control
-
-   INTEGER :: nvelosets                     ! Total number of velocity profile data sets
-   INTEGER :: nvelovars                     ! Total number of variables for profiles
-   INTEGER :: nveloextr                     ! Extra fields for each variable
-   TYPE(obs_prof), POINTER ::  velodata(:)  ! Initial velocity profile data
-   TYPE(obs_prof), POINTER ::  veldatqc(:)  ! Velocity profile data after quality control
-END MODULE obs_profiles
Index: NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_profiles_def.F90
===================================================================
--- NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_profiles_def.F90	(revision 15731)
+++ NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_profiles_def.F90	(revision 15799)
@@ -43,8 +43,10 @@
       & obs_prof_alloc,     &
       & obs_prof_alloc_var, &
+      & obs_prof_alloc_ext, &
       & obs_prof_dealloc,   &
       & obs_prof_compress,  &
       & obs_prof_decompress,&
-      & obs_prof_staend
+      & obs_prof_staend,    &
+      & obs_prof_staend_ext
 
    !! * Type definition for valid observations
@@ -75,5 +77,5 @@
 
       REAL(KIND=wp), POINTER, DIMENSION(:,:) :: &
-         & vext           !: Extra variables
+         & vadd           !: Additional variables
 
       INTEGER, POINTER, DIMENSION(:) :: &
@@ -87,4 +89,22 @@
    END TYPE obs_prof_var
 
+   !! * Type definition for extra variables
+
+   TYPE obs_prof_ext
+
+      ! Arrays with size equal to the number of observations
+
+      INTEGER, POINTER, DIMENSION(:) :: &
+         & nepidx,&       !: Profile number
+         & nelidx         !: Level number in profile
+
+      REAL(KIND=wp), POINTER, DIMENSION(:,:) :: &
+         & eobs           !: Profile data
+
+      INTEGER, POINTER, DIMENSION(:) :: &
+         & neind          !: Source indices of temp. data in compressed data
+
+   END TYPE obs_prof_ext
+
    !! * Type definition for profile observation type
 
@@ -94,5 +114,6 @@
 
       INTEGER :: nvar     !: Number of variables
-      INTEGER :: next     !: Number of extra fields
+      INTEGER :: next     !: Number of extra variables
+      INTEGER :: nadd     !: Number of additional variables
       INTEGER :: nprof    !: Total number of profiles within window.
       INTEGER :: nstp     !: Number of time steps
@@ -104,10 +125,29 @@
       ! Bookkeeping arrays with sizes equal to number of variables
 
-      CHARACTER(len=8), POINTER, DIMENSION(:) :: &
-         & cvars          !: Variable names
+      CHARACTER(len=ilenname), POINTER, DIMENSION(:) :: &
+         & cvars,    &    !: Variable names
+         & cextvars, &    !: Extra variable names
+         & caddvars       !: Additional variable names
+
+      CHARACTER(len=ilenlong), POINTER, DIMENSION(:) :: &
+         & clong,    &    !: Variable long names
+         & cextlong       !: Extra variable long names
+
+      CHARACTER(len=ilenlong), POINTER, DIMENSION(:,:) :: &
+         & caddlong       !: Additional variable long names
+
+      CHARACTER(len=ilenunit), POINTER, DIMENSION(:) :: &
+         & cunit,    &    !: Variable units
+         & cextunit       !: Extra variable units
+
+      CHARACTER(len=ilenunit), POINTER, DIMENSION(:,:) :: &
+         & caddunit       !: Additional variable units
+
+      CHARACTER(len=ilengrid), POINTER, DIMENSION(:) :: &
+         & cgrid          !: Variable grids
 
       INTEGER, POINTER, DIMENSION(:) :: &
-         & nvprot,   &    !: Local total number of profile T data
-         & nvprotmpp      !: Global total number of profile T data
+         & nvprot,   &    !: Local total number of profile data
+         & nvprotmpp      !: Global total number of profile data
       
       ! Arrays with size equal to the number of profiles
@@ -131,5 +171,5 @@
          & rphi           !: Latitude coordinate of profile data
 
-      CHARACTER(LEN=8), POINTER, DIMENSION(:) :: &
+      CHARACTER(LEN=ilenwmo), POINTER, DIMENSION(:) :: &
          & cwmo           !: Profile WMO indentifier
       
@@ -140,6 +180,6 @@
          & npvsta, &      !: Start of each variable profile in full arrays
          & npvend, &      !: End of each variable profile in full arrays
-         & mi,     &      !: i-th grid coord. for interpolating to profile T data
-         & mj,     &      !: j-th grid coord. for interpolating to profile T data
+         & mi,     &      !: i-th grid coord. for interpolating to profile data
+         & mj,     &      !: j-th grid coord. for interpolating to profile data
          & ivqc           !: QC flags for all levels for a variable
 
@@ -160,4 +200,14 @@
       TYPE(obs_prof_var), POINTER, DIMENSION(:) :: var
 
+      ! Extra variables
+
+      TYPE(obs_prof_ext) :: vext
+
+      INTEGER :: nvprotext  !: Local total number of extra variable profile data
+
+      INTEGER, POINTER, DIMENSION(:) :: &
+         & npvstaext, &      !: Start of extra variable profiles in full arrays
+         & npvendext         !: End of extra variable profiles in full arrays
+
       ! Arrays with size equal to the number of time steps in the window
 
@@ -197,6 +247,6 @@
 CONTAINS
    
-   SUBROUTINE obs_prof_alloc( prof,  kvar, kext, kprof,  &
-      &                       ko3dt, kstp, kpi, kpj, kpk )
+   SUBROUTINE obs_prof_alloc( prof,  kvar, kadd, kext, kprof,  &
+      &                       ko3dt, ke3dt, kstp, kpi, kpj, kpk )
       !!----------------------------------------------------------------------
       !!                     ***  ROUTINE obs_prof_alloc  ***
@@ -214,7 +264,9 @@
       INTEGER, INTENT(IN) :: kprof  ! Number of profiles
       INTEGER, INTENT(IN) :: kvar   ! Number of variables
-      INTEGER, INTENT(IN) :: kext   ! Number of extra fields within each variable
+      INTEGER, INTENT(IN) :: kadd   ! Number of additional fields within each variable
+      INTEGER, INTENT(IN) :: kext   ! Number of extra fields
       INTEGER, INTENT(IN), DIMENSION(kvar) :: &
          & ko3dt     ! Number of observations per variables
+      INTEGER, INTENT(IN) :: ke3dt  ! Number of observations per extra variables
       INTEGER, INTENT(IN) :: kstp   ! Number of time steps
       INTEGER, INTENT(IN) :: kpi    ! Number of 3D grid points
@@ -223,5 +275,5 @@
 
       !!* Local variables
-      INTEGER :: jvar
+      INTEGER :: jvar, jadd, jext
       INTEGER :: ji
 
@@ -229,4 +281,5 @@
 
       prof%nvar      = kvar
+      prof%nadd      = kadd
       prof%next      = kext
       prof%nprof     = kprof
@@ -241,4 +294,7 @@
       ALLOCATE( &
          & prof%cvars(kvar),    &
+         & prof%clong(kvar),    &
+         & prof%cunit(kvar),    &
+         & prof%cgrid(kvar),    &
          & prof%nvprot(kvar),   &
          & prof%nvprotmpp(kvar) &
@@ -247,6 +303,34 @@
       DO jvar = 1, kvar
          prof%cvars    (jvar) = "NotSet"
+         prof%clong    (jvar) = "NotSet"
+         prof%cunit    (jvar) = "NotSet"
+         prof%cgrid    (jvar) = ""
          prof%nvprot   (jvar) = ko3dt(jvar)
          prof%nvprotmpp(jvar) = 0
+      END DO
+
+      ! Allocate additional/extra variable metadata
+
+      ALLOCATE( &
+         & prof%caddvars(kadd),      &
+         & prof%caddlong(kadd,kvar), &
+         & prof%caddunit(kadd,kvar), &
+         & prof%cextvars(kext),      &
+         & prof%cextlong(kext),      &
+         & prof%cextunit(kext)       &
+         )
+         
+      DO jadd = 1, kadd
+         prof%caddvars(jadd) = "NotSet"
+         DO jvar = 1, kvar
+            prof%caddlong(jadd,jvar) = "NotSet"
+            prof%caddunit(jadd,jvar) = "NotSet"
+         END DO
+      END DO
+         
+      DO jext = 1, kext
+         prof%cextvars(jext) = "NotSet"
+         prof%cextlong(jext) = "NotSet"
+         prof%cextunit(jext) = "NotSet"
       END DO
 
@@ -306,10 +390,20 @@
 
       DO jvar = 1, kvar
-
          IF ( ko3dt(jvar) >= 0 ) THEN
-            CALL obs_prof_alloc_var( prof, jvar, kext, ko3dt(jvar) )
+            CALL obs_prof_alloc_var( prof, jvar, kadd, ko3dt(jvar) )
          ENDIF
-         
-      END DO
+      END DO
+      
+      ! Extra variables
+
+      IF ( kext > 0 ) THEN
+         prof%nvprotext = ke3dt
+         ALLOCATE( &
+            & prof%npvstaext(kprof), &  
+            & prof%npvendext(kprof) )
+         CALL obs_prof_alloc_ext( prof, kext, ke3dt )
+      ELSE
+         prof%nvprotext = 0
+      ENDIF
 
       ! Allocate arrays of size number of time step size
@@ -346,4 +440,10 @@
          END DO
       END DO
+
+      IF ( kext > 0 ) THEN
+         DO ji = 1, ke3dt
+            prof%vext%neind(ji) = ji
+         END DO
+      ENDIF
 
       ! Set defaults for number of observations per time step
@@ -377,5 +477,6 @@
       !!* Local variables
       INTEGER :: &
-         & jvar
+         & jvar, &
+         & jext
 
       ! Deallocate arrays of size number of profiles
@@ -418,11 +519,7 @@
 
       DO jvar = 1, prof%nvar
-
          IF ( prof%nvprot(jvar) >= 0 ) THEN
-
             CALL obs_prof_dealloc_var( prof, jvar )
-
          ENDIF
-         
       END DO
 
@@ -432,4 +529,13 @@
          & )
 
+      ! Deallocate extra variables
+      IF ( prof%next > 0 ) THEN
+         DEALLOCATE( &
+            & prof%npvstaext, &  
+            & prof%npvendext  &
+            )
+         CALL obs_prof_dealloc_ext( prof )
+      ENDIF
+      
       ! Deallocate arrays of size number of time step size
 
@@ -458,13 +564,26 @@
       DEALLOCATE( &
          & prof%cvars,    &
+         & prof%clong,    &
+         & prof%cunit,    &
+         & prof%cgrid,    &
          & prof%nvprot,   &
          & prof%nvprotmpp &
          )
 
+      ! Dellocate additional/extra variables metadata
+
+      DEALLOCATE( &
+         & prof%caddvars, &
+         & prof%caddlong, &
+         & prof%caddunit, &
+         & prof%cextvars, &
+         & prof%cextlong, &
+         & prof%cextunit  &
+         )
 
    END SUBROUTINE obs_prof_dealloc
 
 
-   SUBROUTINE obs_prof_alloc_var( prof, kvar, kext, kobs )
+   SUBROUTINE obs_prof_alloc_var( prof, kvar, kadd, kobs )
 
       !!----------------------------------------------------------------------
@@ -480,5 +599,5 @@
       TYPE(obs_prof), INTENT(INOUT) :: prof   ! Profile data to be allocated
       INTEGER, INTENT(IN) :: kvar   ! Variable number
-      INTEGER, INTENT(IN) :: kext   ! Number of extra fields within each variable
+      INTEGER, INTENT(IN) :: kadd   ! Number of additional fields within each variable
       INTEGER, INTENT(IN) :: kobs   ! Number of observations
       
@@ -498,7 +617,7 @@
          & prof%var(kvar)%nvqcf(idefnqcf,kobs)  &
          & )
-      IF (kext>0) THEN
+      IF (kadd>0) THEN
          ALLOCATE( & 
-            & prof%var(kvar)%vext(kobs,kext) &
+            & prof%var(kvar)%vadd(kobs,kadd) &
             & )
       ENDIF
@@ -506,10 +625,11 @@
    END SUBROUTINE obs_prof_alloc_var
 
+
    SUBROUTINE obs_prof_dealloc_var( prof, kvar )
 
       !!----------------------------------------------------------------------
-      !!                     ***  ROUTINE obs_prof_alloc_var  ***
+      !!                     ***  ROUTINE obs_prof_dealloc_var  ***
       !!                      
-      !! ** Purpose : - Allocate data for variable data in profile arrays
+      !! ** Purpose : - Deallocate data for variable data in profile arrays
       !! 
       !! ** Method  : - Fortran-90 dynamic arrays
@@ -518,5 +638,5 @@
       !!        !  07-03  (K. Mogensen) Original code
       !! * Arguments
-      TYPE(obs_prof), INTENT(INOUT) :: prof   ! Profile data to be allocated
+      TYPE(obs_prof), INTENT(INOUT) :: prof   ! Profile data to be deallocated
       INTEGER, INTENT(IN) :: kvar      ! Variable number
       
@@ -534,7 +654,7 @@
          & prof%var(kvar)%nvqcf   &
          & )
-      IF (prof%next>0) THEN
+      IF (prof%nadd>0) THEN
          DEALLOCATE( & 
-            & prof%var(kvar)%vext  &
+            & prof%var(kvar)%vadd  &
             & )
       ENDIF
@@ -542,6 +662,57 @@
    END SUBROUTINE obs_prof_dealloc_var
 
+
+   SUBROUTINE obs_prof_alloc_ext( prof, kext, kobs )
+
+      !!----------------------------------------------------------------------
+      !!                     ***  ROUTINE obs_prof_alloc_ext  ***
+      !!                      
+      !! ** Purpose : - Allocate data for extra variables in profile arrays
+      !! 
+      !! ** Method  : - Fortran-90 dynamic arrays
+      !!
+      !! History :
+      !!        !  07-03  (K. Mogensen) Original code
+      !! * Arguments
+      TYPE(obs_prof), INTENT(INOUT) :: prof   ! Profile data to be allocated
+      INTEGER,        INTENT(IN)    :: kext   ! Number of extra variables
+      INTEGER,        INTENT(IN)    :: kobs   ! Number of observations
+
+      ALLOCATE( &
+         & prof%vext%nepidx(kobs),   &
+         & prof%vext%nelidx(kobs),   &
+         & prof%vext%neind(kobs),    &
+         & prof%vext%eobs(kobs,kext) &
+         & )
+
+   END SUBROUTINE obs_prof_alloc_ext
+
+
+   SUBROUTINE obs_prof_dealloc_ext( prof )
+
+      !!----------------------------------------------------------------------
+      !!                     ***  ROUTINE obs_prof_dealloc_var  ***
+      !!                      
+      !! ** Purpose : - Deallocate data for extra variables in profile arrays
+      !! 
+      !! ** Method  : - Fortran-90 dynamic arrays
+      !!
+      !! History :
+      !!        !  07-03  (K. Mogensen) Original code
+      !! * Arguments
+      TYPE(obs_prof), INTENT(INOUT) :: prof   ! Profile data to be deallocated
+      
+      DEALLOCATE( &
+         & prof%vext%nepidx, &
+         & prof%vext%nelidx, &
+         & prof%vext%eobs,   &
+         & prof%vext%neind   &
+         & )
+
+   END SUBROUTINE obs_prof_dealloc_ext
+
+
    SUBROUTINE obs_prof_compress( prof,   newprof, lallocate, &
-      &                          kumout, lvalid,   lvvalid )
+      &                          kumout, lvalid,  lvvalid )
       !!----------------------------------------------------------------------
       !!                     ***  ROUTINE obs_prof_compress  ***
@@ -564,6 +735,6 @@
       TYPE(obs_prof), INTENT(IN)    :: prof      ! Original profile
       TYPE(obs_prof), INTENT(INOUT) :: newprof   ! New profile with the copy of the data
-      LOGICAL :: lallocate                ! Allocate newprof data
-      INTEGER,INTENT(IN) :: kumout        ! Fortran unit for messages
+      LOGICAL,        INTENT(IN)    :: lallocate ! Allocate newprof data
+      INTEGER,        INTENT(IN)    :: kumout    ! Fortran unit for messages
       TYPE(obs_prof_valid), OPTIONAL, INTENT(in) :: &
          & lvalid        ! Valid profiles
@@ -575,5 +746,7 @@
       INTEGER, DIMENSION(prof%nvar) :: &
          & invpro
+      INTEGER :: invproext
       INTEGER :: jvar
+      INTEGER :: jadd
       INTEGER :: jext
       INTEGER :: ji
@@ -587,5 +760,5 @@
       LOGICAL :: lnonepresent
 
-      ! Check that either all or none of the masks are persent.
+      ! Check that either all or none of the masks are present.
 
       lallpresent  = .FALSE.
@@ -607,7 +780,8 @@
          inprof = 0
          invpro(:) = 0
+         invproext = 0
          DO ji = 1, prof%nprof
             IF ( lvalid%luse(ji) ) THEN
-               inprof=inprof+1
+               inprof = inprof + 1
                DO jvar = 1, prof%nvar
                   DO jj = prof%npvsta(ji,jvar), prof%npvend(ji,jvar)
@@ -616,4 +790,9 @@
                   END DO
                END DO
+               IF ( prof%next > 0 ) THEN
+                  DO jj = prof%npvstaext(ji), prof%npvendext(ji)
+                     invproext = invproext + 1
+                  END DO
+               ENDIF
             ENDIF
          END DO
@@ -621,4 +800,5 @@
          inprof    = prof%nprof
          invpro(:) = prof%nvprot(:)
+         invproext = prof%nvprotext
       ENDIF
 
@@ -627,6 +807,7 @@
       IF ( lallocate ) THEN
          CALL obs_prof_alloc( newprof,   prof%nvar, &
-            &                 prof%next,            &
+            &                 prof%nadd, prof%next, &
             &                 inprof,    invpro,    &
+            &                 invproext,            &
             &                 prof%nstp, prof%npi,  &
             &                 prof%npj,  prof%npk )
@@ -655,7 +836,10 @@
       inprof    = 0
       invpro(:) = 0
-
-      newprof%npvsta(:,:) =  0
-      newprof%npvend(:,:) = -1
+      invproext = 0
+
+      newprof%npvsta(:,:)  =  0
+      newprof%npvend(:,:)  = -1
+      newprof%npvstaext(:) =  0
+      newprof%npvendext(:) = -1
       
       ! Loop over source profiles
@@ -670,5 +854,5 @@
 
             newprof%mi(inprof,:)  = prof%mi(ji,:)
-            newprof%mj(inprof,:) = prof%mj(ji,:)
+            newprof%mj(inprof,:)  = prof%mj(ji,:)
             newprof%npidx(inprof) = prof%npidx(ji)
             newprof%npfil(inprof) = prof%npfil(ji)
@@ -741,7 +925,7 @@
                      newprof%var(jvar)%vmod(invpro(jvar))   = &
                         &                           prof%var(jvar)%vmod(jj)
-                     DO jext = 1, prof%next
-                        newprof%var(jvar)%vext(invpro(jvar),jext) = &
-                           &                      prof%var(jvar)%vext(jj,jext)
+                     DO jadd = 1, prof%nadd
+                        newprof%var(jvar)%vadd(invpro(jvar),jadd) = &
+                           &                      prof%var(jvar)%vadd(jj,jadd)
                      END DO
                   
@@ -756,4 +940,38 @@
             END DO
 
+            IF ( prof%next > 0 ) THEN
+
+               ! Extra variables
+
+               lfirst = .TRUE.
+
+               DO jj = prof%npvstaext(ji), prof%npvendext(ji)
+
+                  invproext = invproext + 1
+
+                  ! Book keeping information
+
+                  IF ( lfirst ) THEN
+                     lfirst = .FALSE.
+                     newprof%npvstaext(inprof) = invproext
+                  ENDIF
+                  newprof%npvendext(inprof) = invproext
+
+                  ! Variable data
+
+                  newprof%vext%nepidx(invproext) = prof%vext%nepidx(jj)
+                  newprof%vext%nelidx(invproext) = prof%vext%nelidx(jj)
+                  DO jext = 1, prof%next
+                     newprof%vext%eobs(invproext,jext) = prof%vext%eobs(jj,jext)
+                  END DO
+
+                  ! nvind is the index of the original variable data
+
+                  newprof%vext%neind(invproext)  = jj
+
+               END DO
+
+            ENDIF
+
          ENDIF
 
@@ -767,8 +985,10 @@
       CALL obs_mpp_sum_integers ( newprof%nvprot, newprof%nvprotmpp,&
          &                        prof%nvar )
+      newprof%nvprotext = invproext
       
       ! Set book keeping variables which do not depend on number of obs.
 
       newprof%nvar     = prof%nvar
+      newprof%nadd     = prof%nadd
       newprof%next     = prof%next
       newprof%nstp     = prof%nstp
@@ -777,4 +997,13 @@
       newprof%npk      = prof%npk
       newprof%cvars(:) = prof%cvars(:)
+      newprof%clong(:) = prof%clong(:)
+      newprof%cunit(:) = prof%cunit(:)
+      newprof%cgrid(:) = prof%cgrid(:)
+      newprof%caddvars(:)   = prof%caddvars(:)
+      newprof%caddlong(:,:) = prof%caddlong(:,:)
+      newprof%caddunit(:,:) = prof%caddunit(:,:)
+      newprof%cextvars(:)   = prof%cextvars(:)
+      newprof%cextlong(:)   = prof%cextlong(:)
+      newprof%cextunit(:)   = prof%cextunit(:)
  
       ! Deallocate temporary data
@@ -810,4 +1039,5 @@
       !!* Local variables
       INTEGER :: jvar
+      INTEGER :: jadd
       INTEGER :: jext
       INTEGER :: ji
@@ -866,7 +1096,7 @@
                oldprof%var(jvar)%idqcf(:,jl) = prof%var(jvar)%idqcf(:,jj)
                oldprof%var(jvar)%nvqcf(:,jl) = prof%var(jvar)%nvqcf(:,jj)
-               DO jext = 1, prof%next
-                  oldprof%var(jvar)%vext(jl,jext) = &
-                     &                        prof%var(jvar)%vext(jj,jext)
+               DO jadd = 1, prof%nadd
+                  oldprof%var(jvar)%vadd(jl,jadd) = &
+                     &                        prof%var(jvar)%vadd(jj,jadd)
                END DO
                
@@ -874,4 +1104,20 @@
 
          END DO
+
+         IF ( prof%next > 0 ) THEN
+
+            DO jj = prof%npvstaext(ji), prof%npvendext(ji)
+
+               jl = prof%vext%neind(jj)
+
+               oldprof%vext%nepidx(jl) = prof%vext%nepidx(jj)
+               oldprof%vext%nelidx(jl) = prof%vext%nelidx(jj)
+               DO jext = 1, prof%next
+                  oldprof%vext%eobs(jl,jext) = prof%vext%eobs(jj,jext)
+               END DO
+
+            END DO
+
+         ENDIF
          
       END DO
@@ -883,7 +1129,8 @@
    END SUBROUTINE obs_prof_decompress
 
+
    SUBROUTINE obs_prof_staend( prof, kvarno )
       !!----------------------------------------------------------------------
-      !!                     ***  ROUTINE obs_prof_decompress  ***
+      !!                     ***  ROUTINE obs_prof_staend  ***
       !!                      
       !! ** Purpose : - Set npvsta and npvend of a variable within 
@@ -924,4 +1171,46 @@
 
    END SUBROUTINE obs_prof_staend
+
+
+   SUBROUTINE obs_prof_staend_ext( prof )
+      !!----------------------------------------------------------------------
+      !!                     ***  ROUTINE obs_prof_staend_ext  ***
+      !!                      
+      !! ** Purpose : - Set npvsta and npvend within 
+      !!                an obs_prof_ext type
+      !!
+      !! ** Method  : - Find the start and stop of a profile by searching 
+      !!                through the data
+      !! 
+      !! History :
+      !!        !  07-04  (K. Mogensen) Original code
+      !!----------------------------------------------------------------------
+      !! * Arguments
+      TYPE(obs_prof),INTENT(INOUT) :: prof     ! Profile data
+
+      !!* Local variables
+      INTEGER :: ji
+      INTEGER :: iprofno
+
+      !-----------------------------------------------------------------------
+      ! Compute start and end bookkeeping arrays
+      !-----------------------------------------------------------------------
+
+      prof%npvstaext(:) = prof%nvprotext + 1
+      prof%npvendext(:) = -1
+      DO ji = 1, prof%nvprotext
+         iprofno = prof%vext%nepidx(ji)
+         prof%npvstaext(iprofno) = &
+            & MIN( ji, prof%npvstaext(iprofno) )
+         prof%npvendext(iprofno) = &
+            & MAX( ji, prof%npvendext(iprofno) )
+      END DO
+
+      DO ji = 1, prof%nprof
+         IF ( prof%npvstaext(ji) == ( prof%nvprotext + 1 ) ) &
+            & prof%npvstaext(ji) = 0
+      END DO
+
+   END SUBROUTINE obs_prof_staend_ext
    
 END MODULE obs_profiles_def
Index: NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_read_altbias.F90
===================================================================
--- NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_read_altbias.F90	(revision 15731)
+++ NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_read_altbias.F90	(revision 15799)
@@ -116,5 +116,5 @@
       numaltbias=0
 
-      IF(lwp)WRITE(numout,*) 'Opening ',bias_file
+      IF (lwp) WRITE(numout,*) 'Opening ', bias_file
 
       CALL iom_open( bias_file, numaltbias, ldstop=.FALSE. )
Index: NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_read_prof.F90
===================================================================
--- NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_read_prof.F90	(revision 15731)
+++ NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_read_prof.F90	(revision 15799)
@@ -27,4 +27,8 @@
    USE lib_mpp                  ! For ctl_warn/stop
    USE obs_fbm                  ! Feedback routines
+   USE obs_group_def, ONLY : &  ! Observation variable information
+      & cobsname_uvel, &
+      & cobsname_vvel, &
+      & imaxavtypes
 
    IMPLICIT NONE
@@ -44,7 +48,7 @@
 
    SUBROUTINE obs_rea_prof( profdata, knumfiles, cdfilenames, &
-      &                     kvars, kextr, kstp, ddobsini, ddobsend, &
-      &                     ldvar1, ldvar2, ldignmis, ldsatt, &
-      &                     ldmod, kdailyavtypes )
+      &                     kvars, kadd, kextr, kstp, ddobsini, ddobsend, &
+      &                     ldvar, ldignmis, ldallatall, &
+      &                     ldmod, cdvars, kdailyavtypes )
       !!---------------------------------------------------------------------
       !!
@@ -72,13 +76,16 @@
          & cdfilenames(knumfiles)        ! File names to read in
       INTEGER, INTENT(IN) :: kvars      ! Number of variables in profdata
-      INTEGER, INTENT(IN) :: kextr      ! Number of extra fields for each var
+      INTEGER, INTENT(IN) :: kadd       ! Number of additional fields
+                                        !   in addition to those in the input file(s)
+      INTEGER, INTENT(IN) :: kextr      ! Number of extra fields
+                                        !   in addition to those in the input file(s)
       INTEGER, INTENT(IN) :: kstp       ! Ocean time-step index
-      LOGICAL, INTENT(IN) :: ldvar1     ! Observed variables switches
-      LOGICAL, INTENT(IN) :: ldvar2
+      LOGICAL, DIMENSION(kvars), INTENT(IN) :: ldvar     ! Observed variables switches
       LOGICAL, INTENT(IN) :: ldignmis   ! Ignore missing files
-      LOGICAL, INTENT(IN) :: ldsatt     ! Compute salinity at all temperature points
+      LOGICAL, INTENT(IN) :: ldallatall     ! Compute salinity at all temperature points
       LOGICAL, INTENT(IN) :: ldmod      ! Initialize model from input data
       REAL(dp), INTENT(IN) :: ddobsini  ! Obs. ini time in YYYYMMDD.HHMMSS
       REAL(dp), INTENT(IN) :: ddobsend  ! Obs. end time in YYYYMMDD.HHMMSS
+      CHARACTER(len=8), DIMENSION(kvars), INTENT(IN) :: cdvars
       INTEGER, DIMENSION(imaxavtypes), OPTIONAL :: &
          & kdailyavtypes                ! Types of daily average observations
@@ -87,10 +94,26 @@
       CHARACTER(LEN=15), PARAMETER :: cpname='obs_rea_prof'
       CHARACTER(len=8) :: clrefdate
-      CHARACTER(len=8), DIMENSION(:), ALLOCATABLE :: clvars
-      INTEGER :: jvar
+      CHARACTER(len=ilenname), DIMENSION(:),   ALLOCATABLE :: clvarsin
+      CHARACTER(len=ilenlong), DIMENSION(:),   ALLOCATABLE :: cllongin
+      CHARACTER(len=ilenunit), DIMENSION(:),   ALLOCATABLE :: clunitin
+      CHARACTER(len=ilengrid), DIMENSION(:),   ALLOCATABLE :: clgridin
+      CHARACTER(len=ilenname), DIMENSION(:),   ALLOCATABLE :: claddvarsin
+      CHARACTER(len=ilenlong), DIMENSION(:,:), ALLOCATABLE :: claddlongin
+      CHARACTER(len=ilenunit), DIMENSION(:,:), ALLOCATABLE :: claddunitin
+      CHARACTER(len=ilenname), DIMENSION(:),   ALLOCATABLE :: clextvarsin
+      CHARACTER(len=ilenlong), DIMENSION(:),   ALLOCATABLE :: clextlongin
+      CHARACTER(len=ilenunit), DIMENSION(:),   ALLOCATABLE :: clextunitin
       INTEGER :: ji
       INTEGER :: jj
       INTEGER :: jk
       INTEGER :: ij
+      INTEGER :: jind
+      INTEGER :: jext
+      INTEGER :: jvar
+      INTEGER :: jadd
+      INTEGER :: jadd2
+      INTEGER :: iadd
+      INTEGER :: iaddin
+      INTEGER :: iextr
       INTEGER :: iflag
       INTEGER :: inobf
@@ -105,29 +128,22 @@
       INTEGER :: iprof
       INTEGER :: iproftot
-      INTEGER :: ivar1t0
-      INTEGER :: ivar2t0
-      INTEGER :: ivar1t
-      INTEGER :: ivar2t
+      INTEGER, DIMENSION(kvars) :: ivart0
+      INTEGER, DIMENSION(kvars) :: ivart
       INTEGER :: ip3dt
       INTEGER :: ios
       INTEGER :: ioserrcount
-      INTEGER :: ivar1tmpp
-      INTEGER :: ivar2tmpp
+      INTEGER, DIMENSION(kvars) :: ivartmpp
       INTEGER :: ip3dtmpp
       INTEGER :: itype
       INTEGER, DIMENSION(knumfiles) :: &
          & irefdate
-      INTEGER, DIMENSION(ntyp1770+1) :: &
-         & itypvar1,    &
-         & itypvar1mpp, &
-         & itypvar2,    &
-         & itypvar2mpp 
+      INTEGER, DIMENSION(ntyp1770+1,kvars) :: &
+         & itypvar,    &
+         & itypvarmpp
+      INTEGER, DIMENSION(:,:), ALLOCATABLE :: &
+         & iobsi,    &
+         & iobsj,    &
+         & iproc
       INTEGER, DIMENSION(:), ALLOCATABLE :: &
-         & iobsi1,    &
-         & iobsj1,    &
-         & iproc1,    &
-         & iobsi2,    &
-         & iobsj2,    &
-         & iproc2,    &
          & iindx,    &
          & ifileidx, &
@@ -147,4 +163,6 @@
       LOGICAL :: llvalprof
       LOGICAL :: lldavtimset
+      LOGICAL :: llcycle
+      LOGICAL :: llpotm
       TYPE(obfbdata), POINTER, DIMENSION(:) :: &
          & inpfiles
@@ -152,6 +170,5 @@
       ! Local initialization
       iprof = 0
-      ivar1t0 = 0
-      ivar2t0 = 0
+      ivart0(:) = 0
       ip3dt = 0
 
@@ -172,4 +189,7 @@
 
       ALLOCATE( inpfiles(inobf) )
+
+      iadd  = 0
+      iextr = 0
 
       prof_files : DO jj = 1, inobf
@@ -219,25 +239,116 @@
                &                ldgrid = .TRUE. )
 
-            IF ( inpfiles(jj)%nvar < 2 ) THEN
+            IF ( inpfiles(jj)%nvar /= kvars ) THEN
                CALL ctl_stop( 'Feedback format error: ', &
-                  &           ' less than 2 vars in profile file' )
+                  &           ' unexpected number of vars in feedback file', &
+                  &           TRIM(cdfilenames(jj)) )
             ENDIF
 
             IF ( ldmod .AND. ( inpfiles(jj)%nadd == 0 ) ) THEN
-               CALL ctl_stop( 'Model not in input data' )
+               CALL ctl_stop( 'Model not in input data in', &
+                  &           TRIM(cdfilenames(jj)) )
+               RETURN
+            ENDIF
+
+            IF ( (iextr > 0) .AND. (inpfiles(jj)%next /= iextr) ) THEN
+               CALL ctl_stop( 'Number of extra variables not consistent', &
+                  &           ' with previous files for this type in', &
+                  &           TRIM(cdfilenames(jj)) )
+            ELSE
+               iextr = inpfiles(jj)%next
+            ENDIF
+
+            ! Ignore model counterpart
+            iaddin = inpfiles(jj)%nadd
+            DO ji = 1, iaddin
+               IF ( TRIM(inpfiles(jj)%caddname(ji)) == 'Hx' ) THEN
+                  iaddin = iaddin - 1
+                  EXIT
+               ENDIF
+            END DO
+            IF ( ldmod .AND. ( inpfiles(jj)%nadd == iaddin ) ) THEN
+               CALL ctl_stop( 'Model not in input data', &
+                  &           TRIM(cdfilenames(jj)) )
+            ENDIF
+
+            IF ( (iadd > 0) .AND. (iaddin /= iadd) ) THEN
+               CALL ctl_stop( 'Number of additional variables not consistent', &
+                  &           ' with previous files for this type in', &
+                  &           TRIM(cdfilenames(jj)) )
+            ELSE
+               iadd = iaddin
             ENDIF
 
             IF ( jj == 1 ) THEN
-               ALLOCATE( clvars( inpfiles(jj)%nvar ) )
+               ALLOCATE( clvarsin( inpfiles(jj)%nvar ) )
+               ALLOCATE( cllongin( inpfiles(jj)%nvar ) )
+               ALLOCATE( clunitin( inpfiles(jj)%nvar ) )
+               ALLOCATE( clgridin( inpfiles(jj)%nvar ) )
                DO ji = 1, inpfiles(jj)%nvar
-                 clvars(ji) = inpfiles(jj)%cname(ji)
+                 clvarsin(ji) = inpfiles(jj)%cname(ji)
+                 cllongin(ji) = inpfiles(jj)%coblong(ji)
+                 clunitin(ji) = inpfiles(jj)%cobunit(ji)
+                 clgridin(ji) = inpfiles(jj)%cgrid(ji)
+                 IF ( clvarsin(ji) /= cdvars(ji) ) THEN
+                    CALL ctl_stop( 'Feedback file variables do not match', &
+                        &           ' expected variable names for this type' )
+                 ENDIF
                END DO
+               IF ( iadd > 0 ) THEN
+                  ALLOCATE( claddvarsin( iadd ) )
+                  ALLOCATE( claddlongin( iadd, inpfiles(jj)%nvar ) )
+                  ALLOCATE( claddunitin( iadd, inpfiles(jj)%nvar ) )
+                  jadd = 0
+                  DO ji = 1, inpfiles(jj)%nadd
+                    IF ( TRIM(inpfiles(jj)%caddname(ji)) /= 'Hx' ) THEN
+                       jadd = jadd + 1
+                       claddvarsin(jadd) = inpfiles(jj)%caddname(ji)
+                       DO jk = 1, inpfiles(jj)%nvar
+                          claddlongin(jadd,jk) = inpfiles(jj)%caddlong(ji,jk)
+                          claddunitin(jadd,jk) = inpfiles(jj)%caddunit(ji,jk)
+                       END DO
+                    ENDIF
+                  END DO
+               ENDIF
+               IF ( iextr > 0 ) THEN
+                  ALLOCATE( clextvarsin( iextr ) )
+                  ALLOCATE( clextlongin( iextr ) )
+                  ALLOCATE( clextunitin( iextr ) )
+                  DO ji = 1, iextr
+                    clextvarsin(ji) = inpfiles(jj)%cextname(ji)
+                    clextlongin(ji) = inpfiles(jj)%cextlong(ji)
+                    clextunitin(ji) = inpfiles(jj)%cextunit(ji)
+                  END DO
+               ENDIF
             ELSE
                DO ji = 1, inpfiles(jj)%nvar
-                  IF ( inpfiles(jj)%cname(ji) /= clvars(ji) ) THEN
+                  IF ( inpfiles(jj)%cname(ji) /= clvarsin(ji) ) THEN
                      CALL ctl_stop( 'Feedback file variables not consistent', &
-                        &           ' with previous files for this type' )
+                        &           ' with previous files for this type in', &
+                        &           TRIM(cdfilenames(jj)) )
                   ENDIF
                END DO
+               IF ( iadd > 0 ) THEN
+                  jadd = 0
+                  DO ji = 1, inpfiles(jj)%nadd
+                     IF ( TRIM(inpfiles(jj)%caddname(ji)) /= 'Hx' ) THEN
+                        jadd = jadd + 1
+                        IF ( inpfiles(jj)%caddname(ji) /= claddvarsin(jadd) ) THEN
+                           CALL ctl_stop( 'Feedback file additional variables not consistent', &
+                              &           ' with previous files for this type in', &
+                              &           TRIM(cdfilenames(jj)) )
+                        ENDIF
+                     ENDIF
+                  END DO
+               ENDIF
+               IF ( iextr > 0 ) THEN
+                  DO ji = 1, iextr
+                     IF ( inpfiles(jj)%cextname(ji) /= clextvarsin(ji) ) THEN
+                        CALL ctl_stop( 'Feedback file extra variables not consistent', &
+                           &           ' with previous files for this type in', &
+                           &           TRIM(cdfilenames(jj)) )
+                     ENDIF
+                  END DO
+               ENDIF
             ENDIF
 
@@ -308,6 +419,12 @@
             DO ji = 1, inpfiles(jj)%nobs
                IF ( BTEST(inpfiles(jj)%ioqc(ji),2 ) ) CYCLE
-               IF ( BTEST(inpfiles(jj)%ivqc(ji,1),2) .AND. &
-                  & BTEST(inpfiles(jj)%ivqc(ji,2),2) ) CYCLE
+               llcycle = .TRUE.
+               DO jvar = 1, kvars
+                  IF ( .NOT. ( BTEST(inpfiles(jj)%ivqc(ji,jvar),2) ) ) THEN
+                     llcycle = .FALSE.
+                     EXIT
+                  ENDIF
+               END DO
+               IF ( llcycle ) CYCLE
                IF ( ( inpfiles(jj)%ptim(ji) >  djulini(jj) ) .AND. &
                   & ( inpfiles(jj)%ptim(ji) <= djulend(jj) )       ) THEN
@@ -317,15 +434,18 @@
             ALLOCATE( zlam(inowin)  )
             ALLOCATE( zphi(inowin)  )
-            ALLOCATE( iobsi1(inowin) )
-            ALLOCATE( iobsj1(inowin) )
-            ALLOCATE( iproc1(inowin) )
-            ALLOCATE( iobsi2(inowin) )
-            ALLOCATE( iobsj2(inowin) )
-            ALLOCATE( iproc2(inowin) )
+            ALLOCATE( iobsi(inowin,kvars) )
+            ALLOCATE( iobsj(inowin,kvars) )
+            ALLOCATE( iproc(inowin,kvars) )
             inowin = 0
             DO ji = 1, inpfiles(jj)%nobs
                IF ( BTEST(inpfiles(jj)%ioqc(ji),2 ) ) CYCLE
-               IF ( BTEST(inpfiles(jj)%ivqc(ji,1),2) .AND. &
-                  & BTEST(inpfiles(jj)%ivqc(ji,2),2) ) CYCLE
+               llcycle = .TRUE.
+               DO jvar = 1, kvars
+                  IF ( .NOT. ( BTEST(inpfiles(jj)%ivqc(ji,jvar),2) ) ) THEN
+                     llcycle = .FALSE.
+                     EXIT
+                  ENDIF
+               END DO
+               IF ( llcycle ) CYCLE
                IF ( ( inpfiles(jj)%ptim(ji) >  djulini(jj) ) .AND. &
                   & ( inpfiles(jj)%ptim(ji) <= djulend(jj) )       ) THEN
@@ -336,44 +456,70 @@
             END DO
 
-            IF ( TRIM( inpfiles(jj)%cname(1) ) == 'POTM' ) THEN
-               CALL obs_grid_search( inowin, zlam, zphi, iobsi1, iobsj1, &
-                  &                  iproc1, 'T' )
-               iobsi2(:) = iobsi1(:)
-               iobsj2(:) = iobsj1(:)
-               iproc2(:) = iproc1(:)
-            ELSEIF ( TRIM( inpfiles(jj)%cname(1) ) == 'UVEL' ) THEN
-               CALL obs_grid_search( inowin, zlam, zphi, iobsi1, iobsj1, &
-                  &                  iproc1, 'U' )
-               CALL obs_grid_search( inowin, zlam, zphi, iobsi2, iobsj2, &
-                  &                  iproc2, 'V' )
-            ENDIF
+            ! Do grid search
+            ! Assume anything other than velocity is on T grid
+            ! Save resource by not repeating for the same grid
+            jind = 0
+            DO jvar = 1, kvars
+               IF ( TRIM(inpfiles(jj)%cname(jvar)) == cobsname_uvel ) THEN
+                  CALL obs_grid_search( inowin, zlam, zphi, iobsi(:,jvar), iobsj(:,jvar), &
+                     &                  iproc(:,jvar), 'U' )
+               ELSE IF ( TRIM(inpfiles(jj)%cname(jvar)) == cobsname_vvel ) THEN
+                  CALL obs_grid_search( inowin, zlam, zphi, iobsi(:,jvar), iobsj(:,jvar), &
+                     &                  iproc(:,jvar), 'V' )
+               ELSE
+                  IF ( jind > 0 ) THEN
+                     iobsi(:,jvar) = iobsi(:,jind)
+                     iobsj(:,jvar) = iobsj(:,jind)
+                     iproc(:,jvar) = iproc(:,jind)
+                  ELSE
+                     jind = jvar
+                     CALL obs_grid_search( inowin, zlam, zphi, iobsi(:,jvar), iobsj(:,jvar), &
+                        &                  iproc(:,jvar), 'T' )
+                  ENDIF
+               ENDIF
+            END DO
 
             inowin = 0
             DO ji = 1, inpfiles(jj)%nobs
                IF ( BTEST(inpfiles(jj)%ioqc(ji),2 ) ) CYCLE
-               IF ( BTEST(inpfiles(jj)%ivqc(ji,1),2) .AND. &
-                  & BTEST(inpfiles(jj)%ivqc(ji,2),2) ) CYCLE
+               llcycle = .TRUE.
+               DO jvar = 1, kvars
+                  IF ( .NOT. ( BTEST(inpfiles(jj)%ivqc(ji,jvar),2) ) ) THEN
+                     llcycle = .FALSE.
+                     EXIT
+                  ENDIF
+               END DO
+               IF ( llcycle ) CYCLE
                IF ( ( inpfiles(jj)%ptim(ji) >  djulini(jj) ) .AND. &
                   & ( inpfiles(jj)%ptim(ji) <= djulend(jj) )       ) THEN
                   inowin = inowin + 1
-                  inpfiles(jj)%iproc(ji,1) = iproc1(inowin)
-                  inpfiles(jj)%iobsi(ji,1) = iobsi1(inowin)
-                  inpfiles(jj)%iobsj(ji,1) = iobsj1(inowin)
-                  inpfiles(jj)%iproc(ji,2) = iproc2(inowin)
-                  inpfiles(jj)%iobsi(ji,2) = iobsi2(inowin)
-                  inpfiles(jj)%iobsj(ji,2) = iobsj2(inowin)
-                  IF ( inpfiles(jj)%iproc(ji,1) /= &
-                     & inpfiles(jj)%iproc(ji,2) ) THEN
-                     CALL ctl_stop( 'Error in obs_read_prof:', &
-                        & 'var1 and var2 observation on different processors')
+                  DO jvar = 1, kvars
+                     inpfiles(jj)%iproc(ji,jvar) = iproc(inowin,jvar)
+                     inpfiles(jj)%iobsi(ji,jvar) = iobsi(inowin,jvar)
+                     inpfiles(jj)%iobsj(ji,jvar) = iobsj(inowin,jvar)
+                  END DO
+                  IF ( kvars > 1 ) THEN
+                     DO jvar = 2, kvars
+                        IF ( inpfiles(jj)%iproc(ji,jvar) /= &
+                           & inpfiles(jj)%iproc(ji,1) ) THEN
+                           CALL ctl_stop( 'Error in obs_read_prof:', &
+                              & 'observation on different processors for different vars')
+                        ENDIF
+                     END DO
                   ENDIF
                ENDIF
             END DO
-            DEALLOCATE( zlam, zphi, iobsi1, iobsj1, iproc1, iobsi2, iobsj2, iproc2 )
+            DEALLOCATE( zlam, zphi, iobsi, iobsj, iproc )
 
             DO ji = 1, inpfiles(jj)%nobs
                IF ( BTEST(inpfiles(jj)%ioqc(ji),2 ) ) CYCLE
-               IF ( BTEST(inpfiles(jj)%ivqc(ji,1),2) .AND. &
-                  & BTEST(inpfiles(jj)%ivqc(ji,2),2) ) CYCLE
+               llcycle = .TRUE.
+               DO jvar = 1, kvars
+                  IF ( .NOT. ( BTEST(inpfiles(jj)%ivqc(ji,jvar),2) ) ) THEN
+                     llcycle = .FALSE.
+                     EXIT
+                  ENDIF
+               END DO
+               IF ( llcycle ) CYCLE
                IF ( ( inpfiles(jj)%ptim(ji) >  djulini(jj) ) .AND. &
                   & ( inpfiles(jj)%ptim(ji) <= djulend(jj) )       ) THEN
@@ -384,37 +530,29 @@
                   ENDIF
                   llvalprof = .FALSE.
-                  IF ( ldvar1 ) THEN
-                     loop_t_count : DO ij = 1,inpfiles(jj)%nlev
-                        IF ( inpfiles(jj)%pdep(ij,ji) >= 6000. ) &
-                           & CYCLE
-                        IF ( .NOT. BTEST(inpfiles(jj)%ivlqc(ij,ji,1),2) .AND. &
-                           & .NOT. BTEST(inpfiles(jj)%idqc(ij,ji),2) ) THEN
-                           ivar1t0 = ivar1t0 + 1
-                        ENDIF
-                     END DO loop_t_count
-                  ENDIF
-                  IF ( ldvar2 ) THEN
-                     loop_s_count : DO ij = 1,inpfiles(jj)%nlev
-                        IF ( inpfiles(jj)%pdep(ij,ji) >= 6000. ) &
-                           & CYCLE
-                        IF ( .NOT. BTEST(inpfiles(jj)%ivlqc(ij,ji,2),2) .AND. &
-                           & .NOT. BTEST(inpfiles(jj)%idqc(ij,ji),2) ) THEN
-                           ivar2t0 = ivar2t0 + 1
-                        ENDIF
-                     END DO loop_s_count
-                  ENDIF
-                  loop_p_count : DO ij = 1,inpfiles(jj)%nlev
+                  DO jvar = 1, kvars
+                     IF ( ldvar(jvar) ) THEN
+                        DO ij = 1,inpfiles(jj)%nlev
+                           IF ( inpfiles(jj)%pdep(ij,ji) >= 6000. ) &
+                              & CYCLE
+                           IF ( .NOT. BTEST(inpfiles(jj)%ivlqc(ij,ji,jvar),2) .AND. &
+                              & .NOT. BTEST(inpfiles(jj)%idqc(ij,ji),2) ) THEN
+                              ivart0(jvar) = ivart0(jvar) + 1
+                           ENDIF
+                        END DO
+                     ENDIF
+                  END DO
+                  DO ij = 1,inpfiles(jj)%nlev
                      IF ( inpfiles(jj)%pdep(ij,ji) >= 6000. ) &
                         & CYCLE
-                     IF ( ( .NOT. BTEST(inpfiles(jj)%ivlqc(ij,ji,1),2) .AND. &
-                        &   .NOT. BTEST(inpfiles(jj)%idqc(ij,ji),2) .AND. &
-                        &    ldvar1 ) .OR. &
-                        & ( .NOT. BTEST(inpfiles(jj)%ivlqc(ij,ji,2),2) .AND. &
-                        &   .NOT. BTEST(inpfiles(jj)%idqc(ij,ji),2) .AND. &
-                        &     ldvar2 ) ) THEN
-                        ip3dt = ip3dt + 1
-                        llvalprof = .TRUE.
-                     ENDIF
-                  END DO loop_p_count
+                     DO jvar = 1, kvars
+                        IF ( ( .NOT. BTEST(inpfiles(jj)%ivlqc(ij,ji,jvar),2) .AND. &
+                           &   .NOT. BTEST(inpfiles(jj)%idqc(ij,ji),2) .AND. &
+                           &    ldvar(jvar) ) ) THEN
+                           ip3dt = ip3dt + 1
+                           llvalprof = .TRUE.
+                           EXIT
+                        ENDIF
+                     END DO
+                  END DO
 
                   IF ( llvalprof ) iprof = iprof + 1
@@ -438,6 +576,12 @@
          DO ji = 1, inpfiles(jj)%nobs
             IF ( BTEST(inpfiles(jj)%ioqc(ji),2 ) ) CYCLE
-            IF ( BTEST(inpfiles(jj)%ivqc(ji,1),2) .AND. &
-               & BTEST(inpfiles(jj)%ivqc(ji,2),2) ) CYCLE
+            llcycle = .TRUE.
+            DO jvar = 1, kvars
+               IF ( .NOT. ( BTEST(inpfiles(jj)%ivqc(ji,jvar),2) ) ) THEN
+                  llcycle = .FALSE.
+                  EXIT
+               ENDIF
+            END DO
+            IF ( llcycle ) CYCLE
             IF ( ( inpfiles(jj)%ptim(ji) >  djulini(jj) ) .AND. &
                & ( inpfiles(jj)%ptim(ji) <= djulend(jj) )       ) THEN
@@ -453,6 +597,12 @@
          DO ji = 1, inpfiles(jj)%nobs
             IF ( BTEST(inpfiles(jj)%ioqc(ji),2 ) ) CYCLE
-            IF ( BTEST(inpfiles(jj)%ivqc(ji,1),2) .AND. &
-               & BTEST(inpfiles(jj)%ivqc(ji,2),2) ) CYCLE
+            llcycle = .TRUE.
+            DO jvar = 1, kvars
+               IF ( .NOT. ( BTEST(inpfiles(jj)%ivqc(ji,jvar),2) ) ) THEN
+                  llcycle = .FALSE.
+                  EXIT
+               ENDIF
+            END DO
+            IF ( llcycle ) CYCLE
             IF ( ( inpfiles(jj)%ptim(ji) >  djulini(jj) ) .AND. &
                & ( inpfiles(jj)%ptim(ji) <= djulend(jj) )       ) THEN
@@ -469,13 +619,11 @@
 
       iv3dt(:) = -1
-      IF (ldsatt) THEN
-         iv3dt(1) = ip3dt
-         iv3dt(2) = ip3dt
+      IF (ldallatall) THEN
+         iv3dt(:) = ip3dt
       ELSE
-         iv3dt(1) = ivar1t0
-         iv3dt(2) = ivar2t0
+         iv3dt(:) = ivart0(:)
       ENDIF
-      CALL obs_prof_alloc( profdata, kvars, kextr, iprof, iv3dt, &
-         &                 kstp, jpi, jpj, jpk )
+      CALL obs_prof_alloc( profdata, kvars, kadd+iadd, kextr+iextr, iprof, iv3dt, &
+         &                 ip3dt, kstp, jpi, jpj, jpk )
 
       ! * Read obs/positions, QC, all variable and assign to profdata
@@ -483,15 +631,24 @@
       profdata%nprof     = 0
       profdata%nvprot(:) = 0
-      profdata%cvars(:)  = clvars(:)
+      profdata%cvars(:)  = clvarsin(:)
+      profdata%clong(:)  = cllongin(:)
+      profdata%cunit(:)  = clunitin(:)
+      profdata%cgrid(:)  = clgridin(:)
+      IF ( iadd > 0 ) THEN
+         profdata%caddvars(kadd+1:)   = claddvarsin(:)
+         profdata%caddlong(kadd+1:,:) = claddlongin(:,:)
+         profdata%caddunit(kadd+1:,:) = claddunitin(:,:)
+      ENDIF
+      IF ( iextr > 0 ) THEN
+         profdata%cextvars(kextr+1:) = clextvarsin(:)
+         profdata%cextlong(kextr+1:) = clextlongin(:)
+         profdata%cextunit(kextr+1:) = clextunitin(:)
+      ENDIF
       iprof = 0
 
       ip3dt = 0
-      ivar1t = 0
-      ivar2t = 0
-      itypvar1   (:) = 0
-      itypvar1mpp(:) = 0
-
-      itypvar2   (:) = 0
-      itypvar2mpp(:) = 0
+      ivart(:) = 0
+      itypvar   (:,:) = 0
+      itypvarmpp(:,:) = 0
 
       ioserrcount = 0
@@ -501,7 +658,13 @@
          ji = iprofidx(iindx(jk))
 
-            IF ( BTEST(inpfiles(jj)%ioqc(ji),2 ) ) CYCLE
-            IF ( BTEST(inpfiles(jj)%ivqc(ji,1),2) .AND. &
-               & BTEST(inpfiles(jj)%ivqc(ji,2),2) ) CYCLE
+         IF ( BTEST(inpfiles(jj)%ioqc(ji),2 ) ) CYCLE
+         llcycle = .TRUE.
+         DO jvar = 1, kvars
+            IF ( .NOT. ( BTEST(inpfiles(jj)%ivqc(ji,jvar),2) ) ) THEN
+               llcycle = .FALSE.
+               EXIT
+            ENDIF
+         END DO
+         IF ( llcycle ) CYCLE
 
          IF ( ( inpfiles(jj)%ptim(ji) >  djulini(jj) ) .AND.  &
@@ -519,6 +682,12 @@
 
             IF ( BTEST(inpfiles(jj)%ioqc(ji),2 ) ) CYCLE
-            IF ( BTEST(inpfiles(jj)%ivqc(ji,1),2) .AND. &
-               & BTEST(inpfiles(jj)%ivqc(ji,2),2) ) CYCLE
+            llcycle = .TRUE.
+            DO jvar = 1, kvars
+               IF ( .NOT. ( BTEST(inpfiles(jj)%ivqc(ji,jvar),2) ) ) THEN
+                  llcycle = .FALSE.
+                  EXIT
+               ENDIF
+            END DO
+            IF ( llcycle ) CYCLE
 
             loop_prof : DO ij = 1, inpfiles(jj)%nlev
@@ -527,19 +696,13 @@
                   & CYCLE
 
-               IF ( .NOT. BTEST(inpfiles(jj)%ivlqc(ij,ji,1),2) .AND. &
-                  & .NOT. BTEST(inpfiles(jj)%idqc(ij,ji),2) ) THEN
-
-                  llvalprof = .TRUE. 
-                  EXIT loop_prof
-
-               ENDIF
-
-               IF ( .NOT. BTEST(inpfiles(jj)%ivlqc(ij,ji,2),2) .AND. &
-                  & .NOT. BTEST(inpfiles(jj)%idqc(ij,ji),2) ) THEN
-
-                  llvalprof = .TRUE. 
-                  EXIT loop_prof
-
-               ENDIF
+               DO jvar = 1, kvars
+                  IF ( .NOT. BTEST(inpfiles(jj)%ivlqc(ij,ji,jvar),2) .AND. &
+                     & .NOT. BTEST(inpfiles(jj)%idqc(ij,ji),2) ) THEN
+
+                     llvalprof = .TRUE. 
+                     EXIT loop_prof
+
+                  ENDIF
+               END DO
 
             END DO loop_prof
@@ -573,8 +736,8 @@
 
                ! Coordinate search parameters
-               profdata%mi  (iprof,1) = inpfiles(jj)%iobsi(ji,1)
-               profdata%mj  (iprof,1) = inpfiles(jj)%iobsj(ji,1)
-               profdata%mi  (iprof,2) = inpfiles(jj)%iobsi(ji,2)
-               profdata%mj  (iprof,2) = inpfiles(jj)%iobsj(ji,2)
+               DO jvar = 1, kvars
+                  profdata%mi  (iprof,jvar) = inpfiles(jj)%iobsi(ji,jvar)
+                  profdata%mj  (iprof,jvar) = inpfiles(jj)%iobsj(ji,jvar)
+               END DO
 
                ! Profile WMO number
@@ -614,139 +777,124 @@
                      & CYCLE
 
-                  IF (ldsatt) THEN
-
-                     IF ( ( .NOT. BTEST(inpfiles(jj)%ivlqc(ij,ji,1),2) .AND. &
-                        &   .NOT. BTEST(inpfiles(jj)%idqc(ij,ji),2) .AND. &
-                        &    ldvar1 ) .OR. &
-                        & ( .NOT. BTEST(inpfiles(jj)%ivlqc(ij,ji,2),2) .AND. &
-                        &   .NOT. BTEST(inpfiles(jj)%idqc(ij,ji),2) .AND. &
-                        &   ldvar2 ) ) THEN
-                        ip3dt = ip3dt + 1
-                     ELSE
-                        CYCLE
+                  IF ( ldallatall .OR. (iextr > 0) ) THEN
+
+                     DO jvar = 1, kvars
+                        IF ( ( .NOT. BTEST(inpfiles(jj)%ivlqc(ij,ji,jvar),2) .AND. &
+                           &   .NOT. BTEST(inpfiles(jj)%idqc(ij,ji),2) .AND. &
+                           &    ldvar(jvar) ) ) THEN
+                           ip3dt = ip3dt + 1
+                           EXIT
+                        ELSE IF ( jvar == kvars ) THEN
+                           CYCLE loop_p
+                        ENDIF
+                     END DO
+
+                  ENDIF
+
+                  DO jvar = 1, kvars
+                  
+                     IF ( ( .NOT. BTEST(inpfiles(jj)%ivlqc(ij,ji,jvar),2) .AND. &
+                       &   .NOT. BTEST(inpfiles(jj)%idqc(ij,ji),2) .AND. &
+                       &    ldvar(jvar) ) .OR. ldallatall ) THEN
+
+                        IF (ldallatall) THEN
+
+                           ivart(jvar) = ip3dt
+
+                        ELSE
+
+                           ivart(jvar) = ivart(jvar) + 1
+
+                        ENDIF
+
+                        ! Depth of jvar observation
+                        profdata%var(jvar)%vdep(ivart(jvar)) = &
+                           &                inpfiles(jj)%pdep(ij,ji)
+
+                        ! Depth of jvar observation QC
+                        profdata%var(jvar)%idqc(ivart(jvar)) = &
+                           &                inpfiles(jj)%idqc(ij,ji)
+
+                        ! Depth of jvar observation QC flags
+                        profdata%var(jvar)%idqcf(:,ivart(jvar)) = &
+                           &                inpfiles(jj)%idqcf(:,ij,ji)
+
+                        ! Profile index
+                        profdata%var(jvar)%nvpidx(ivart(jvar)) = iprof
+
+                        ! Vertical index in original profile
+                        profdata%var(jvar)%nvlidx(ivart(jvar)) = ij
+
+                        ! Profile jvar value
+                        IF ( .NOT. BTEST(inpfiles(jj)%ivlqc(ij,ji,jvar),2) .AND. &
+                           & .NOT. BTEST(inpfiles(jj)%idqc(ij,ji),2) ) THEN
+                           profdata%var(jvar)%vobs(ivart(jvar)) = &
+                              &                inpfiles(jj)%pob(ij,ji,jvar)
+                           ! Count number of profile var1 data as function of type
+                           itypvar( profdata%ntyp(iprof) + 1, jvar ) = &
+                              & itypvar( profdata%ntyp(iprof) + 1, jvar ) + 1
+                        ELSE
+                           profdata%var(jvar)%vobs(ivart(jvar)) = fbrmdi
+                        ENDIF
+
+                        ! Profile jvar qc
+                        profdata%var(jvar)%nvqc(ivart(jvar)) = &
+                           & inpfiles(jj)%ivlqc(ij,ji,jvar)
+
+                        ! Profile jvar qc flags
+                        profdata%var(jvar)%nvqcf(:,ivart(jvar)) = &
+                           & inpfiles(jj)%ivlqcf(:,ij,ji,jvar)
+
+                        ! Additional variables
+                        IF ( iadd > 0 ) THEN
+                           jadd2 = 0
+                           DO jadd = 1, inpfiles(jj)%nadd
+                              IF ( TRIM(inpfiles(jj)%caddname(jadd)) == 'Hx' ) THEN
+                                 IF ( ldmod ) THEN
+                                    profdata%var(jvar)%vmod(ivart(jvar)) = &
+                                       &                inpfiles(jj)%padd(ij,ji,jadd,jvar)
+                                 ENDIF
+                              ELSE
+                                 jadd2 = jadd2 + 1
+                                 profdata%var(jvar)%vadd(ivart(jvar),kadd+jadd2) = &
+                                    &                inpfiles(jj)%padd(ij,ji,jadd,jvar)
+                              ENDIF
+                           END DO
+                        ENDIF
+
                      ENDIF
-
-                  ENDIF
-
-                  IF ( ( .NOT. BTEST(inpfiles(jj)%ivlqc(ij,ji,1),2) .AND. &
-                    &   .NOT. BTEST(inpfiles(jj)%idqc(ij,ji),2) .AND. &
-                    &    ldvar1 ) .OR. ldsatt ) THEN
-
-                     IF (ldsatt) THEN
-
-                        ivar1t = ip3dt
-
-                     ELSE
-
-                        ivar1t = ivar1t + 1
-
-                     ENDIF
-
-                     ! Depth of var1 observation
-                     profdata%var(1)%vdep(ivar1t) = &
-                        &                inpfiles(jj)%pdep(ij,ji)
-
-                     ! Depth of var1 observation QC
-                     profdata%var(1)%idqc(ivar1t) = &
-                        &                inpfiles(jj)%idqc(ij,ji)
-
-                     ! Depth of var1 observation QC flags
-                     profdata%var(1)%idqcf(:,ivar1t) = &
-                        &                inpfiles(jj)%idqcf(:,ij,ji)
-
-                     ! Profile index
-                     profdata%var(1)%nvpidx(ivar1t) = iprof
-
-                     ! Vertical index in original profile
-                     profdata%var(1)%nvlidx(ivar1t) = ij
-
-                     ! Profile var1 value
-                     IF ( .NOT. BTEST(inpfiles(jj)%ivlqc(ij,ji,1),2) .AND. &
-                        & .NOT. BTEST(inpfiles(jj)%idqc(ij,ji),2) ) THEN
-                        profdata%var(1)%vobs(ivar1t) = &
-                           &                inpfiles(jj)%pob(ij,ji,1)
-                        IF ( ldmod ) THEN
-                           profdata%var(1)%vmod(ivar1t) = &
-                              &                inpfiles(jj)%padd(ij,ji,1,1)
+                  
+                  END DO
+                  
+                  ! Extra variables
+                  ! Special consideration for if the extra variable is called TEMP
+                  ! and there's a regular variable called POTM. These are in situ
+                  ! and potential temperature respectively, and need the same QC checks
+                  IF ( iextr > 0 ) THEN
+                     profdata%vext%nepidx(ip3dt) = iprof
+                     profdata%vext%nelidx(ip3dt) = ij
+                     DO jext = 1, iextr
+                        IF ( TRIM(inpfiles(jj)%cextname(jext)) == 'TEMP' ) THEN
+                           llpotm = .false.
+                           DO jvar = 1, kvars
+                              IF ( TRIM(inpfiles(jj)%cname(jvar)) == 'POTM' ) THEN
+                                 IF ( ( .NOT. BTEST(inpfiles(jj)%ivlqc(ij,ji,jvar),2) .AND. &
+                                    &   .NOT. BTEST(inpfiles(jj)%idqc(ij,ji),2) .AND. &
+                                    &    ldvar(jvar) ) ) THEN
+                                    profdata%vext%eobs(ip3dt,kextr+jext) = inpfiles(jj)%pext(ij,ji,jext)
+                                 ELSE
+                                    profdata%vext%eobs(ip3dt,kextr+jext) = fbrmdi
+                                 ENDIF
+                                 llpotm = .true.
+                                 EXIT
+                              ENDIF
+                           END DO
+                           IF ( .NOT. llpotm ) THEN
+                              profdata%vext%eobs(ip3dt,kextr+jext) = inpfiles(jj)%pext(ij,ji,jext)
+                           ENDIF
+                        ELSE
+                           profdata%vext%eobs(ip3dt,kextr+jext) = inpfiles(jj)%pext(ij,ji,jext)
                         ENDIF
-                        ! Count number of profile var1 data as function of type
-                        itypvar1( profdata%ntyp(iprof) + 1 ) = &
-                           & itypvar1( profdata%ntyp(iprof) + 1 ) + 1
-                     ELSE
-                        profdata%var(1)%vobs(ivar1t) = fbrmdi
-                     ENDIF
-
-                     ! Profile var1 qc
-                     profdata%var(1)%nvqc(ivar1t) = &
-                        & inpfiles(jj)%ivlqc(ij,ji,1)
-
-                     ! Profile var1 qc flags
-                     profdata%var(1)%nvqcf(:,ivar1t) = &
-                        & inpfiles(jj)%ivlqcf(:,ij,ji,1)
-
-                     ! Profile insitu T value
-                     IF ( TRIM( inpfiles(jj)%cname(1) ) == 'POTM' ) THEN
-                        profdata%var(1)%vext(ivar1t,1) = &
-                           &                inpfiles(jj)%pext(ij,ji,1)
-                     ENDIF
-
-                  ENDIF
-
-                  IF ( ( .NOT. BTEST(inpfiles(jj)%ivlqc(ij,ji,2),2) .AND. &
-                     &   .NOT. BTEST(inpfiles(jj)%idqc(ij,ji),2)    .AND. &
-                     &   ldvar2 ) .OR. ldsatt ) THEN
-
-                     IF (ldsatt) THEN
-
-                        ivar2t = ip3dt
-
-                     ELSE
-
-                        ivar2t = ivar2t + 1
-
-                     ENDIF
-
-                     ! Depth of var2 observation
-                     profdata%var(2)%vdep(ivar2t) = &
-                        &                inpfiles(jj)%pdep(ij,ji)
-
-                     ! Depth of var2 observation QC
-                     profdata%var(2)%idqc(ivar2t) = &
-                        &                inpfiles(jj)%idqc(ij,ji)
-
-                     ! Depth of var2 observation QC flags
-                     profdata%var(2)%idqcf(:,ivar2t) = &
-                        &                inpfiles(jj)%idqcf(:,ij,ji)
-
-                     ! Profile index
-                     profdata%var(2)%nvpidx(ivar2t) = iprof
-
-                     ! Vertical index in original profile
-                     profdata%var(2)%nvlidx(ivar2t) = ij
-
-                     ! Profile var2 value
-                  IF (  ( .NOT. BTEST(inpfiles(jj)%ivlqc(ij,ji,2),2) ) .AND. &
-                    &   ( .NOT. BTEST(inpfiles(jj)%idqc(ij,ji),2)    )  ) THEN
-                        profdata%var(2)%vobs(ivar2t) = &
-                           &                inpfiles(jj)%pob(ij,ji,2)
-                        IF ( ldmod ) THEN
-                           profdata%var(2)%vmod(ivar2t) = &
-                              &                inpfiles(jj)%padd(ij,ji,1,2)
-                        ENDIF
-                        ! Count number of profile var2 data as function of type
-                        itypvar2( profdata%ntyp(iprof) + 1 ) = &
-                           & itypvar2( profdata%ntyp(iprof) + 1 ) + 1
-                     ELSE
-                        profdata%var(2)%vobs(ivar2t) = fbrmdi
-                     ENDIF
-
-                     ! Profile var2 qc
-                     profdata%var(2)%nvqc(ivar2t) = &
-                        & inpfiles(jj)%ivlqc(ij,ji,2)
-
-                     ! Profile var2 qc flags
-                     profdata%var(2)%nvqcf(:,ivar2t) = &
-                        & inpfiles(jj)%ivlqcf(:,ij,ji,2)
-
+                     END DO
                   ENDIF
 
@@ -763,10 +911,12 @@
       !-----------------------------------------------------------------------
 
-      CALL obs_mpp_sum_integer ( ivar1t0, ivar1tmpp )
-      CALL obs_mpp_sum_integer ( ivar2t0, ivar2tmpp )
+      DO jvar = 1, kvars
+         CALL obs_mpp_sum_integer ( ivart0(jvar), ivartmpp(jvar) )
+      END DO
       CALL obs_mpp_sum_integer ( ip3dt,   ip3dtmpp  )
 
-      CALL obs_mpp_sum_integers( itypvar1, itypvar1mpp, ntyp1770 + 1 )
-      CALL obs_mpp_sum_integers( itypvar2, itypvar2mpp, ntyp1770 + 1 )
+      DO jvar = 1, kvars
+         CALL obs_mpp_sum_integers( itypvar(:,jvar), itypvarmpp(:,jvar), ntyp1770 + 1 )
+      END DO
 
       !-----------------------------------------------------------------------
@@ -778,50 +928,33 @@
          WRITE(numout,'(1X,A)') '------------'
          WRITE(numout,*) 
-         WRITE(numout,'(1X,A)') 'Profile data, '//TRIM( profdata%cvars(1) )
-         WRITE(numout,'(1X,A)') '------------------------'
-         DO ji = 0, ntyp1770
-            IF ( itypvar1mpp(ji+1) > 0 ) THEN
-               WRITE(numout,'(1X,A3,1X,A48,A3,I8)') ctypshort(ji), &
-                  & cwmonam1770(ji)(1:52),' = ', &
-                  & itypvar1mpp(ji+1)
-            ENDIF
+         DO jvar = 1, kvars
+            WRITE(numout,'(1X,A)') 'Profile data, '//TRIM( profdata%cvars(jvar) )
+            WRITE(numout,'(1X,A)') '------------------------'
+            DO ji = 0, ntyp1770
+               IF ( itypvarmpp(ji+1,jvar) > 0 ) THEN
+                  WRITE(numout,'(1X,A3,1X,A48,A3,I8)') ctypshort(ji), &
+                     & cwmonam1770(ji)(1:52),' = ', &
+                     & itypvarmpp(ji+1,jvar)
+               ENDIF
+            END DO
+            WRITE(numout,'(1X,A)') &
+               & '---------------------------------------------------------------'
+            WRITE(numout,'(1X,A55,I8)') &
+               & 'Total profile data for variable '//TRIM( profdata%cvars(jvar) )// &
+               & '             = ', ivartmpp(jvar)
+            WRITE(numout,'(1X,A)') &
+               & '---------------------------------------------------------------'
+            WRITE(numout,*) 
          END DO
-         WRITE(numout,'(1X,A)') &
-            & '---------------------------------------------------------------'
-         WRITE(numout,'(1X,A55,I8)') &
-            & 'Total profile data for variable '//TRIM( profdata%cvars(1) )// &
-            & '             = ', ivar1tmpp
-         WRITE(numout,'(1X,A)') &
-            & '---------------------------------------------------------------'
-         WRITE(numout,*) 
-         WRITE(numout,'(1X,A)') 'Profile data, '//TRIM( profdata%cvars(2) )
-         WRITE(numout,'(1X,A)') '------------------------'
-         DO ji = 0, ntyp1770
-            IF ( itypvar2mpp(ji+1) > 0 ) THEN
-               WRITE(numout,'(1X,A3,1X,A48,A3,I8)') ctypshort(ji), &
-                  & cwmonam1770(ji)(1:52),' = ', &
-                  & itypvar2mpp(ji+1)
-            ENDIF
+      ENDIF
+
+      IF (ldallatall) THEN
+         profdata%nvprot(:)    = ip3dt
+         profdata%nvprotmpp(:) = ip3dtmpp
+      ELSE
+         DO jvar = 1, kvars
+            profdata%nvprot(jvar)    = ivart(jvar)
+            profdata%nvprotmpp(jvar) = ivartmpp(jvar)
          END DO
-         WRITE(numout,'(1X,A)') &
-            & '---------------------------------------------------------------'
-         WRITE(numout,'(1X,A55,I8)') &
-            & 'Total profile data for variable '//TRIM( profdata%cvars(2) )// &
-            & '             = ', ivar2tmpp
-         WRITE(numout,'(1X,A)') &
-            & '---------------------------------------------------------------'
-         WRITE(numout,*) 
-      ENDIF
-
-      IF (ldsatt) THEN
-         profdata%nvprot(1)    = ip3dt
-         profdata%nvprot(2)    = ip3dt
-         profdata%nvprotmpp(1) = ip3dtmpp
-         profdata%nvprotmpp(2) = ip3dtmpp
-      ELSE
-         profdata%nvprot(1)    = ivar1t
-         profdata%nvprot(2)    = ivar2t
-         profdata%nvprotmpp(1) = ivar1tmpp
-         profdata%nvprotmpp(2) = ivar2tmpp
       ENDIF
       profdata%nprof        = iprof
@@ -830,14 +963,11 @@
       ! Model level search
       !-----------------------------------------------------------------------
-      IF ( ldvar1 ) THEN
-         CALL obs_level_search( jpk, gdept_1d, &
-            & profdata%nvprot(1), profdata%var(1)%vdep, &
-            & profdata%var(1)%mvk )
-      ENDIF
-      IF ( ldvar2 ) THEN
-         CALL obs_level_search( jpk, gdept_1d, &
-            & profdata%nvprot(2), profdata%var(2)%vdep, &
-            & profdata%var(2)%mvk )
-      ENDIF
+      DO jvar = 1, kvars
+         IF ( ldvar(jvar) ) THEN
+            CALL obs_level_search( jpk, gdept_1d, &
+               & profdata%nvprot(jvar), profdata%var(jvar)%vdep, &
+               & profdata%var(jvar)%mvk )
+         ENDIF
+      END DO
 
       !-----------------------------------------------------------------------
@@ -852,5 +982,12 @@
       ! Deallocate temporary data
       !-----------------------------------------------------------------------
-      DEALLOCATE( ifileidx, iprofidx, zdat, clvars )
+      DEALLOCATE( ifileidx, iprofidx, zdat, &
+         &        clvarsin, cllongin, clunitin, clgridin )
+      IF ( iadd > 0 ) THEN
+         DEALLOCATE( claddvarsin, claddlongin, claddunitin)
+      ENDIF
+      IF ( iextr > 0 ) THEN
+         DEALLOCATE( clextvarsin, clextlongin, clextunitin )
+      ENDIF
 
       !-----------------------------------------------------------------------
Index: NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_read_surf.F90
===================================================================
--- NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_read_surf.F90	(revision 15731)
+++ NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_read_surf.F90	(revision 15799)
@@ -22,4 +22,7 @@
    USE obs_fbm                  ! Feedback routines
    USE netcdf                   ! NetCDF library
+   USE obs_group_def, ONLY : &  ! Observation variable information
+      & cobsname_uvel, &
+      & cobsname_vvel
 
    IMPLICIT NONE
@@ -39,6 +42,7 @@
 
    SUBROUTINE obs_rea_surf( surfdata, knumfiles, cdfilenames, &
-      &                     kvars, kextr, kstp, ddobsini, ddobsend, &
-      &                     ldignmis, ldmod, ldnightav )
+      &                     kvars, kadd, kextr, kstp, ddobsini, ddobsend, &
+      &                     ptime_mean_period, ld_time_mean_bkg, &
+      &                     ldignmis, ldmod, ldnightav, cdvars )
       !!---------------------------------------------------------------------
       !!
@@ -61,24 +65,47 @@
       !! * Arguments
       TYPE(obs_surf), INTENT(INOUT) :: &
-         & surfdata                     ! Surface data to be read
-      INTEGER, INTENT(IN) :: knumfiles  ! Number of corio format files to read
+         & surfdata                             ! Surface data to be read
+      INTEGER,  INTENT(IN) :: knumfiles         ! Number of corio format files to read
       CHARACTER(LEN=128), INTENT(IN) :: &
-         & cdfilenames(knumfiles)       ! File names to read in
-      INTEGER, INTENT(IN) :: kvars      ! Number of variables in surfdata
-      INTEGER, INTENT(IN) :: kextr      ! Number of extra fields for each var
-      INTEGER, INTENT(IN) :: kstp       ! Ocean time-step index
-      LOGICAL, INTENT(IN) :: ldignmis   ! Ignore missing files
-      LOGICAL, INTENT(IN) :: ldmod      ! Initialize model from input data
-      LOGICAL, INTENT(IN) :: ldnightav  ! Observations represent a night-time average
-      REAL(dp), INTENT(IN) :: ddobsini   ! Obs. ini time in YYYYMMDD.HHMMSS
-      REAL(dp), INTENT(IN) :: ddobsend   ! Obs. end time in YYYYMMDD.HHMMSS
+         & cdfilenames(knumfiles)               ! File names to read in
+      INTEGER,  INTENT(IN) :: kvars             ! Number of variables in surfdata
+      INTEGER,  INTENT(IN) :: kadd              ! Number of additional fields
+                                                !   in addition to those in the input file(s)
+      INTEGER,  INTENT(IN) :: kextr             ! Number of extra fields
+                                                !   in addition to those in the input file(s)
+      INTEGER,  INTENT(IN) :: kstp              ! Ocean time-step index
+      REAL(dp), INTENT(IN) :: ddobsini          ! Obs. ini time in YYYYMMDD.HHMMSS
+      REAL(dp), INTENT(IN) :: ddobsend          ! Obs. end time in YYYYMMDD.HHMMSS
+      REAL(wp), INTENT(IN) :: ptime_mean_period ! Averaging period in hours
+      LOGICAL,  INTENT(IN) :: ld_time_mean_bkg  ! Will reset times to end of averaging period
+      LOGICAL,  INTENT(IN) :: ldignmis          ! Ignore missing files
+      LOGICAL,  INTENT(IN) :: ldmod             ! Initialize model from input data
+      LOGICAL,  INTENT(IN) :: ldnightav         ! Observations represent a night-time average
+      CHARACTER(len=8), DIMENSION(kvars), INTENT(IN) :: cdvars  ! Expected variable names
 
       !! * Local declarations
       CHARACTER(LEN=11), PARAMETER :: cpname='obs_rea_surf'
       CHARACTER(len=8) :: clrefdate
-      CHARACTER(len=8), DIMENSION(:), ALLOCATABLE :: clvars
+      CHARACTER(len=ilenname), DIMENSION(:),   ALLOCATABLE :: clvarsin
+      CHARACTER(len=ilenlong), DIMENSION(:),   ALLOCATABLE :: cllongin
+      CHARACTER(len=ilenunit), DIMENSION(:),   ALLOCATABLE :: clunitin
+      CHARACTER(len=ilengrid), DIMENSION(:),   ALLOCATABLE :: clgridin
+      CHARACTER(len=ilenname), DIMENSION(:),   ALLOCATABLE :: claddvarsin
+      CHARACTER(len=ilenlong), DIMENSION(:,:), ALLOCATABLE :: claddlongin
+      CHARACTER(len=ilenunit), DIMENSION(:,:), ALLOCATABLE :: claddunitin
+      CHARACTER(len=ilenname), DIMENSION(:),   ALLOCATABLE :: clextvarsin
+      CHARACTER(len=ilenlong), DIMENSION(:),   ALLOCATABLE :: clextlongin
+      CHARACTER(len=ilenunit), DIMENSION(:),   ALLOCATABLE :: clextunitin
       INTEGER :: ji
       INTEGER :: jj
       INTEGER :: jk
+      INTEGER :: jind
+      INTEGER :: jvar
+      INTEGER :: jext
+      INTEGER :: jadd
+      INTEGER :: jadd2
+      INTEGER :: iadd
+      INTEGER :: iaddin
+      INTEGER :: iextr
       INTEGER :: iflag
       INTEGER :: inobf
@@ -102,8 +129,9 @@
          & ityp, &
          & itypmpp
-      INTEGER, DIMENSION(:), ALLOCATABLE :: &
+      INTEGER, DIMENSION(:,:), ALLOCATABLE :: &
          & iobsi,    &
          & iobsj,    &
-         & iproc,    &
+         & iproc
+      INTEGER, DIMENSION(:), ALLOCATABLE :: &
          & iindx,    &
          & ifileidx, &
@@ -120,4 +148,5 @@
       TYPE(obfbdata), POINTER, DIMENSION(:) :: &
          & inpfiles
+      CHARACTER(LEN=256) :: cout1  ! Diagnostic output line
 
       ! Local initialization
@@ -131,4 +160,7 @@
 
       ALLOCATE( inpfiles(inobf) )
+
+      iadd  = 0
+      iextr = 0
 
       surf_files : DO jj = 1, inobf
@@ -178,24 +210,120 @@
                &                ldgrid = .TRUE. )
 
+            IF ( inpfiles(jj)%nvar /= kvars ) THEN
+               CALL ctl_stop( 'Feedback format error: ', &
+                  &           ' unexpected number of vars in feedback file', &
+                  &           TRIM(cdfilenames(jj)) )
+            ENDIF
+
             IF ( ldmod .AND. ( inpfiles(jj)%nadd == 0 ) ) THEN
-               CALL ctl_stop( 'Model not in input data' )
+               CALL ctl_stop( 'Model not in input data in', &
+                  &           TRIM(cdfilenames(jj)) )
                RETURN
             ENDIF
 
+            IF ( (iextr > 0) .AND. (inpfiles(jj)%next /= iextr) ) THEN
+               CALL ctl_stop( 'Number of extra variables not consistent', &
+                  &           ' with previous files for this type in', &
+                  &           TRIM(cdfilenames(jj)) )
+            ELSE
+               iextr = inpfiles(jj)%next
+            ENDIF
+
+            ! Ignore model counterpart
+            iaddin = inpfiles(jj)%nadd
+            DO ji = 1, iaddin
+               IF ( TRIM(inpfiles(jj)%caddname(ji)) == 'Hx' ) THEN
+                  iaddin = iaddin - 1
+                  EXIT
+               ENDIF
+            END DO
+            IF ( ldmod .AND. ( inpfiles(jj)%nadd == iaddin ) ) THEN
+               CALL ctl_stop( 'Model not in input data', &
+                  &           TRIM(cdfilenames(jj)) )
+            ENDIF
+
+            IF ( (iadd > 0) .AND. (iaddin /= iadd) ) THEN
+               CALL ctl_stop( 'Number of additional variables not consistent', &
+                  &           ' with previous files for this type in', &
+                  &           TRIM(cdfilenames(jj)) )
+            ELSE
+               iadd = iaddin
+            ENDIF
+
             IF ( jj == 1 ) THEN
-               ALLOCATE( clvars( inpfiles(jj)%nvar ) )
+               ALLOCATE( clvarsin( inpfiles(jj)%nvar ) )
+               ALLOCATE( cllongin( inpfiles(jj)%nvar ) )
+               ALLOCATE( clunitin( inpfiles(jj)%nvar ) )
+               ALLOCATE( clgridin( inpfiles(jj)%nvar ) )
                DO ji = 1, inpfiles(jj)%nvar
-                 clvars(ji) = inpfiles(jj)%cname(ji)
+                 clvarsin(ji) = inpfiles(jj)%cname(ji)
+                 cllongin(ji) = inpfiles(jj)%coblong(ji)
+                 clunitin(ji) = inpfiles(jj)%cobunit(ji)
+                 clgridin(ji) = inpfiles(jj)%cgrid(ji)
+                 IF ( clvarsin(ji) /= cdvars(ji) ) THEN
+                    CALL ctl_stop( 'Feedback file variables do not match', &
+                        &           ' expected variable names for this type' )
+                 ENDIF
                END DO
+               IF ( iadd > 0 ) THEN
+                  ALLOCATE( claddvarsin( iadd ) )
+                  ALLOCATE( claddlongin( iadd, inpfiles(jj)%nvar ) )
+                  ALLOCATE( claddunitin( iadd, inpfiles(jj)%nvar ) )
+                  jadd = 0
+                  DO ji = 1, inpfiles(jj)%nadd
+                    IF ( TRIM(inpfiles(jj)%caddname(ji)) /= 'Hx' ) THEN
+                       jadd = jadd + 1
+                       claddvarsin(jadd) = inpfiles(jj)%caddname(ji)
+                       DO jk = 1, inpfiles(jj)%nvar
+                          claddlongin(jadd,jk) = inpfiles(jj)%caddlong(ji,jk)
+                          claddunitin(jadd,jk) = inpfiles(jj)%caddunit(ji,jk)
+                       END DO
+                    ENDIF
+                  END DO
+               ENDIF
+               IF ( iextr > 0 ) THEN
+                  ALLOCATE( clextvarsin( iextr ) )
+                  ALLOCATE( clextlongin( iextr ) )
+                  ALLOCATE( clextunitin( iextr ) )
+                  DO ji = 1, iextr
+                    clextvarsin(ji) = inpfiles(jj)%cextname(ji)
+                    clextlongin(ji) = inpfiles(jj)%cextlong(ji)
+                    clextunitin(ji) = inpfiles(jj)%cextunit(ji)
+                  END DO
+               ENDIF
             ELSE
                DO ji = 1, inpfiles(jj)%nvar
-                  IF ( inpfiles(jj)%cname(ji) /= clvars(ji) ) THEN
+                  IF ( inpfiles(jj)%cname(ji) /= clvarsin(ji) ) THEN
                      CALL ctl_stop( 'Feedback file variables not consistent', &
-                        &           ' with previous files for this type' )
+                        &           ' with previous files for this type in', &
+                        &           TRIM(cdfilenames(jj)) )
                   ENDIF
                END DO
-            ENDIF
-
-            IF (lwp) WRITE(numout,*)'Observation file contains ',inpfiles(jj)%nobs,' observations'
+               IF ( iadd > 0 ) THEN
+                  jadd = 0
+                  DO ji = 1, inpfiles(jj)%nadd
+                     IF ( TRIM(inpfiles(jj)%caddname(ji)) /= 'Hx' ) THEN
+                        jadd = jadd + 1
+                        IF ( inpfiles(jj)%caddname(ji) /= claddvarsin(jadd) ) THEN
+                           CALL ctl_stop( 'Feedback file additional variables not consistent', &
+                              &           ' with previous files for this type in', &
+                              &           TRIM(cdfilenames(jj)) )
+                        ENDIF
+                     ENDIF
+                  END DO
+               ENDIF
+               IF ( iextr > 0 ) THEN
+                  DO ji = 1, iextr
+                     IF ( inpfiles(jj)%cextname(ji) /= clextvarsin(ji) ) THEN
+                        CALL ctl_stop( 'Feedback file extra variables not consistent', &
+                           &           ' with previous files for this type in', &
+                           &           TRIM(cdfilenames(jj)) )
+                     ENDIF
+                  END DO
+               ENDIF
+
+            ENDIF
+
+            IF (lwp) WRITE(numout,*) 'Observation file contains ', inpfiles(jj)%nobs, ' observations'
 
             !------------------------------------------------------------------
@@ -247,8 +375,21 @@
 
             IF ( inpfiles(jj)%nobs > 0 ) THEN
-               inpfiles(jj)%iproc = -1
-               inpfiles(jj)%iobsi = -1
-               inpfiles(jj)%iobsj = -1
-            ENDIF
+               inpfiles(jj)%iproc(:,:) = -1
+               inpfiles(jj)%iobsi(:,:) = -1
+               inpfiles(jj)%iobsj(:,:) = -1
+            ENDIF
+
+            ! If observations are representing a time mean then set the time
+            ! of the obs to the end of that meaning period relative to the start of the run
+            IF ( ld_time_mean_bkg ) THEN
+               DO ji = 1, inpfiles(jj)%nobs
+                  ! Only do this for obs within time window
+                  IF ( ( inpfiles(jj)%ptim(ji) >  djulini(jj) ) .AND. &
+                     & ( inpfiles(jj)%ptim(ji) <= djulend(jj) ) ) THEN
+                     inpfiles(jj)%ptim(ji) = djulini(jj) + (ptime_mean_period/24.0)
+                  ENDIF
+               END DO
+            ENDIF
+
             inowin = 0
             DO ji = 1, inpfiles(jj)%nobs
@@ -258,9 +399,9 @@
                ENDIF
             END DO
-            ALLOCATE( zlam(inowin)  )
-            ALLOCATE( zphi(inowin)  )
-            ALLOCATE( iobsi(inowin) )
-            ALLOCATE( iobsj(inowin) )
-            ALLOCATE( iproc(inowin) )
+            ALLOCATE( zlam (inowin)       )
+            ALLOCATE( zphi (inowin)       )
+            ALLOCATE( iobsi(inowin,kvars) )
+            ALLOCATE( iobsj(inowin,kvars) )
+            ALLOCATE( iproc(inowin,kvars) )
             inowin = 0
             DO ji = 1, inpfiles(jj)%nobs
@@ -273,5 +414,27 @@
             END DO
 
-            CALL obs_grid_search( inowin, zlam, zphi, iobsi, iobsj, iproc, 'T' )
+            ! Do grid search
+            ! Assume anything other than velocity is on T grid
+            ! Save resource by not repeating for the same grid
+            jind = 0
+            DO jvar = 1, kvars
+               IF ( TRIM(inpfiles(jj)%cname(jvar)) == cobsname_uvel ) THEN
+                  CALL obs_grid_search( inowin, zlam, zphi, iobsi(:,jvar), iobsj(:,jvar), &
+                     &                  iproc(:,jvar), 'U' )
+               ELSE IF ( TRIM(inpfiles(jj)%cname(jvar)) == cobsname_vvel ) THEN
+                  CALL obs_grid_search( inowin, zlam, zphi, iobsi(:,jvar), iobsj(:,jvar), &
+                     &                  iproc(:,jvar), 'V' )
+               ELSE
+                  IF ( jind > 0 ) THEN
+                     iobsi(:,jvar) = iobsi(:,jind)
+                     iobsj(:,jvar) = iobsj(:,jind)
+                     iproc(:,jvar) = iproc(:,jind)
+                  ELSE
+                     jind = jvar
+                     CALL obs_grid_search( inowin, zlam, zphi, iobsi(:,jvar), iobsj(:,jvar), &
+                        &                  iproc(:,jvar), 'T' )
+                  ENDIF
+               ENDIF
+            END DO
 
             inowin = 0
@@ -280,7 +443,9 @@
                   & ( inpfiles(jj)%ptim(ji) <= djulend(jj) )       ) THEN
                   inowin = inowin + 1
-                  inpfiles(jj)%iproc(ji,1) = iproc(inowin)
-                  inpfiles(jj)%iobsi(ji,1) = iobsi(inowin)
-                  inpfiles(jj)%iobsj(ji,1) = iobsj(inowin)
+                  DO jvar = 1, kvars
+                     inpfiles(jj)%iproc(ji,jvar) = iproc(inowin,jvar)
+                     inpfiles(jj)%iobsi(ji,jvar) = iobsi(inowin,jvar)
+                     inpfiles(jj)%iobsj(ji,jvar) = iobsj(inowin,jvar)
+                  END DO
                ENDIF
             END DO
@@ -341,5 +506,5 @@
          &               iindx   )
 
-      CALL obs_surf_alloc( surfdata, iobs, kvars, kextr, kstp, jpi, jpj )
+      CALL obs_surf_alloc( surfdata, iobs, kvars, kadd+iadd, kextr+iextr, kstp, jpi, jpj )
 
       ! Read obs/positions, QC, all variable and assign to surfdata
@@ -347,5 +512,18 @@
       iobs = 0
 
-      surfdata%cvars(:)  = clvars(:)
+      surfdata%cvars(:)  = clvarsin(:)
+      surfdata%clong(:)  = cllongin(:)
+      surfdata%cunit(:)  = clunitin(:)
+      surfdata%cgrid(:)  = clgridin(:)
+      IF ( iadd > 0 ) THEN
+         surfdata%caddvars(kadd+1:)   = claddvarsin(:)
+         surfdata%caddlong(kadd+1:,:) = claddlongin(:,:)
+         surfdata%caddunit(kadd+1:,:) = claddunitin(:,:)
+      ENDIF
+      IF ( iextr > 0 ) THEN
+         surfdata%cextvars(kextr+1:) = clextvarsin(:)
+         surfdata%cextlong(kextr+1:) = clextlongin(:)
+         surfdata%cextunit(kextr+1:) = clextunitin(:)
+      ENDIF
 
       ityp   (:) = 0
@@ -395,6 +573,8 @@
 
                ! Coordinate search parameters
-               surfdata%mi  (iobs) = inpfiles(jj)%iobsi(ji,1)
-               surfdata%mj  (iobs) = inpfiles(jj)%iobsj(ji,1)
+               DO jvar = 1, kvars
+                  surfdata%mi(iobs,jvar) = inpfiles(jj)%iobsi(ji,jvar)
+                  surfdata%mj(iobs,jvar) = inpfiles(jj)%iobsj(ji,jvar)
+               END DO
 
                ! WMO number
@@ -415,6 +595,6 @@
                   ityp(itype+1) = ityp(itype+1) + 1
                ELSE
-                  IF(lwp)WRITE(numout,*)'WARNING:Increase jpsurfmaxtype in ',&
-                     &                  cpname
+                  IF(lwp)WRITE(numout,*) 'WARNING: Increase jpsurfmaxtype in ', &
+                     &                   cpname
                ENDIF
 
@@ -423,21 +603,36 @@
                surfdata%nsfil(iobs) = iindx(jk)
 
-               ! QC flags
-               surfdata%nqc(iobs) = inpfiles(jj)%ivqc(ji,1)
-
-               ! Observed value
-               surfdata%robs(iobs,1) = inpfiles(jj)%pob(1,ji,1)
-
-
-               ! Model and MDT is set to fbrmdi unless read from file
-               IF ( ldmod ) THEN
-                  surfdata%rmod(iobs,1) = inpfiles(jj)%padd(1,ji,1,1)
-                  IF ( TRIM(surfdata%cvars(1)) == 'SLA' ) THEN
-                     surfdata%rext(iobs,1) = inpfiles(jj)%padd(1,ji,2,1)
-                     surfdata%rext(iobs,2) = inpfiles(jj)%pext(1,ji,1)
+               DO jvar = 1, kvars
+
+                  ! QC flags
+                  surfdata%nqc(iobs) = inpfiles(jj)%ivqc(ji,jvar)
+
+                  ! Observed value
+                  surfdata%robs(iobs,jvar) = inpfiles(jj)%pob(1,ji,jvar)
+
+                  ! Additional variables
+                  surfdata%rmod(iobs,jvar) = fbrmdi
+                  IF ( iadd > 0 ) THEN
+                     jadd2 = 0
+                     DO jadd = 1, inpfiles(jj)%nadd
+                        IF ( TRIM(inpfiles(jj)%caddname(jadd)) == 'Hx' ) THEN
+                           IF ( ldmod ) THEN
+                              surfdata%rmod(iobs,jvar) = inpfiles(jj)%padd(1,ji,jadd,jvar)
+                           ENDIF
+                        ELSE
+                           jadd2 = jadd2 + 1
+                           surfdata%radd(iobs,kadd+jadd2,jvar) = &
+                              &                inpfiles(jj)%padd(1,ji,jadd,jvar)
+                        ENDIF
+                     END DO
                   ENDIF
-                ELSE
-                  surfdata%rmod(iobs,1) = fbrmdi
-                  IF ( TRIM(surfdata%cvars(1)) == 'SLA' ) surfdata%rext(iobs,:) = fbrmdi
+
+               END DO
+                  
+               ! Extra variables
+               IF ( iextr > 0 ) THEN
+                  DO jext = 1, iextr
+                     surfdata%rext(iobs,kextr+jext) = inpfiles(jj)%pext(1,ji,jext)
+                  END DO
                ENDIF
             ENDIF
@@ -457,11 +652,18 @@
       !-----------------------------------------------------------------------
       IF (lwp) THEN
-
+         DO jvar = 1, surfdata%nvar       
+            IF ( jvar == 1 ) THEN
+               cout1=TRIM(surfdata%cvars(1))                  
+            ELSE
+               WRITE(cout1,'(A,A1,A)') TRIM(cout1), '/', TRIM(surfdata%cvars(jvar))            
+            ENDIF
+         END DO
+ 
          WRITE(numout,*)
-         WRITE(numout,'(1X,A)')TRIM( surfdata%cvars(1) )//' data'
+         WRITE(numout,'(1X,A)')TRIM( cout1 )//' data'
          WRITE(numout,'(1X,A)')'--------------'
          DO jj = 1,8
             IF ( itypmpp(jj) > 0 ) THEN
-               WRITE(numout,'(1X,A4,I4,A3,I10)')'Type ', jj,' = ',itypmpp(jj)
+               WRITE(numout,'(1X,A4,I4,A3,I10)') 'Type ', jj, ' = ', itypmpp(jj)
             ENDIF
          END DO
@@ -469,5 +671,5 @@
             & '---------------------------------------------------------------'
          WRITE(numout,'(1X,A,I8)') &
-            & 'Total data for variable '//TRIM( surfdata%cvars(1) )// &
+            & 'Total data for variable '//TRIM( cout1 )// &
             & '           = ', iobsmpp
          WRITE(numout,'(1X,A)') &
@@ -480,5 +682,12 @@
       ! Deallocate temporary data
       !-----------------------------------------------------------------------
-      DEALLOCATE( ifileidx, isurfidx, zdat, clvars )
+      DEALLOCATE( ifileidx, isurfidx, zdat, clvarsin, &
+         &        cllongin, clunitin, clgridin )
+      IF ( iadd > 0 ) THEN
+         DEALLOCATE( claddvarsin, claddlongin, claddunitin)
+      ENDIF
+      IF ( iextr > 0 ) THEN
+         DEALLOCATE( clextvarsin, clextlongin, clextunitin )
+      ENDIF
 
       !-----------------------------------------------------------------------
Index: NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_readmdt.F90
===================================================================
--- NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_readmdt.F90	(revision 15731)
+++ NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_readmdt.F90	(revision 15799)
@@ -31,9 +31,4 @@
    
    PUBLIC   obs_rea_mdt     ! called by dia_obs_init
-   PUBLIC   obs_offset_mdt  ! called by obs_rea_mdt
-
-   INTEGER , PUBLIC :: nn_msshc    = 1         ! MDT correction scheme
-   REAL(wp), PUBLIC :: rn_mdtcorr   = 1.61_wp  ! User specified MDT correction
-   REAL(wp), PUBLIC :: rn_mdtcutoff = 65.0_wp  ! MDT cutoff for computed correction
 
    !!----------------------------------------------------------------------
@@ -44,5 +39,6 @@
 CONTAINS
 
-   SUBROUTINE obs_rea_mdt( sladata, k2dint )
+   SUBROUTINE obs_rea_mdt( sladata, k2dint, kmdt, nn_msshc, rn_mdtcorr, &
+                           rn_mdtcutoff )
       !!---------------------------------------------------------------------
       !!
@@ -57,6 +53,10 @@
       USE iom
       !
-      TYPE(obs_surf), INTENT(inout) ::   sladata   ! SLA data
-      INTEGER       , INTENT(in)    ::   k2dint    ! ?
+      TYPE(obs_surf), INTENT(inout) :: sladata      ! SLA data
+      INTEGER       , INTENT(in)    :: k2dint       ! Interpolation type
+      INTEGER       , INTENT(in)    :: kmdt         ! Index of MDT extra var
+      INTEGER       , INTENT(in)    :: nn_msshc     ! MDT correction scheme
+      REAL(wp)      , INTENT(in)    :: rn_mdtcorr   ! User specified MDT correction
+      REAL(wp)      , INTENT(in)    :: rn_mdtcutoff ! MDT cutoff for computed correction
       !
       CHARACTER(LEN=12), PARAMETER ::   cpname  = 'obs_rea_mdt'
@@ -105,9 +105,11 @@
 
       ! Remove the offset between the MDT used with the sla and the model MDT
-      IF( nn_msshc == 1 .OR. nn_msshc == 2 ) &
-         & CALL obs_offset_mdt( jpi, jpj, z_mdt, zfill )
-
-      ! Intepolate the MDT already on the model grid at the observation point
-  
+      IF( nn_msshc == 1 .OR. nn_msshc == 2 ) THEN
+         CALL obs_offset_mdt( jpi, jpj, z_mdt, zfill, nn_msshc, &
+            &                 rn_mdtcorr, rn_mdtcutoff )
+      ENDIF
+
+      ! Interpolate the MDT already on the model grid at the observation point
+
       ALLOCATE( &
          & igrdi(2,2,sladata%nsurf), &
@@ -118,5 +120,5 @@
          & zmdtl(2,2,sladata%nsurf)  &
          & )
-         
+
       DO jobs = 1, sladata%nsurf
 
@@ -147,12 +149,12 @@
             
          CALL obs_int_h2d( 1, 1, zweig, zmdtl(:,:,jobs),  zext )
- 
-         sladata%rext(jobs,2) = zext(1)
+
+         sladata%rext(jobs,kmdt) = zext(1)
 
 ! mark any masked data with a QC flag
          IF( zobsmask(1) == 0 )   sladata%nqc(jobs) = IBSET(sladata%nqc(jobs),15)
 
-         END DO
-         
+      END DO
+
       DEALLOCATE( &
          & igrdi, &
@@ -169,5 +171,6 @@
 
 
-   SUBROUTINE obs_offset_mdt( kpi, kpj, mdt, zfill )
+   SUBROUTINE obs_offset_mdt( kpi, kpj, mdt, zfill, nn_msshc, rn_mdtcorr, &
+                              rn_mdtcutoff )
       !!---------------------------------------------------------------------
       !!
@@ -183,6 +186,9 @@
       !!----------------------------------------------------------------------
       INTEGER, INTENT(IN) ::  kpi, kpj
-      REAL(wp), DIMENSION(kpi,kpj), INTENT(INOUT) ::   mdt     ! MDT used on the model grid
-      REAL(wp)                    , INTENT(IN   ) ::   zfill 
+      REAL(wp), DIMENSION(kpi,kpj), INTENT(INOUT) :: mdt          ! MDT used on the model grid
+      REAL(wp)                    , INTENT(IN   ) :: zfill        ! Fill value
+      INTEGER                     , INTENT(IN   ) :: nn_msshc     ! MDT correction scheme
+      REAL(wp)                    , INTENT(IN   ) :: rn_mdtcorr   ! User specified MDT correction
+      REAL(wp)                    , INTENT(IN   ) :: rn_mdtcutoff ! MDT cutoff for computed correction
       ! 
       INTEGER  :: ji, jj
@@ -246,9 +252,9 @@
          WRITE(numout,*) '               zcorr         = ', zcorr
          WRITE(numout,*) '               nn_msshc        = ', nn_msshc
+
+         IF ( nn_msshc == 0 ) WRITE(numout,*) '           MSSH correction is not applied'
+         IF ( nn_msshc == 1 ) WRITE(numout,*) '           MSSH correction is applied'
+         IF ( nn_msshc == 2 ) WRITE(numout,*) '           User defined MSSH correction' 
       ENDIF
-
-      IF ( nn_msshc == 0 ) WRITE(numout,*) '           MSSH correction is not applied'
-      IF ( nn_msshc == 1 ) WRITE(numout,*) '           MSSH correction is applied'
-      IF ( nn_msshc == 2 ) WRITE(numout,*) '           User defined MSSH correction' 
 
       !
Index: NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_readsnowdepth.F90
===================================================================
--- NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_readsnowdepth.F90	(revision 15799)
+++ NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_readsnowdepth.F90	(revision 15799)
@@ -0,0 +1,146 @@
+MODULE obs_readsnowdepth
+   !!======================================================================
+   !!                       ***  MODULE obs_readsnowdepth  ***
+   !! Observation diagnostics: Get the snow depth for freeboard conversion to thickness
+   !!======================================================================
+   !! History :      ! 2018-10 (E. Fiedler) Initial version
+   !!----------------------------------------------------------------------
+
+   !!----------------------------------------------------------------------
+   !!   obs_rea_snowdepth    : Driver for reading MDT
+   !!----------------------------------------------------------------------
+   USE par_kind         ! Precision variables
+   USE par_oce          ! Domain parameters
+   USE in_out_manager   ! I/O manager
+   USE obs_surf_def     ! Surface observation definitions
+   USE obs_inter_sup    ! Interpolation support routines
+   USE obs_inter_h2d    ! 2D interpolation
+   USE obs_utils        ! Various observation tools
+   USE iom_nf90         ! IOM NetCDF
+   USE netcdf           ! NetCDF library
+   USE lib_mpp          ! MPP library
+   USE dom_oce, ONLY : &                  ! Domain variables
+      &                    tmask, tmask_i, e1t, e2t, gphit, glamt
+   USE obs_const, ONLY :   obfillflt      ! Fillvalue
+
+   IMPLICIT NONE
+   PRIVATE
+   
+   PUBLIC   obs_rea_snowdepth     ! called by dia_obs
+
+   !!----------------------------------------------------------------------
+   !! NEMO/OPA 3.3 , NEMO Consortium (2010)
+   !! $Id$
+   !! Software governed by the CeCILL licence     (NEMOGCM/NEMO_CeCILL.txt)
+   !!----------------------------------------------------------------------
+CONTAINS
+
+   SUBROUTINE obs_rea_snowdepth( fbddata, k2dint, ksnow, thick_s )
+      !!---------------------------------------------------------------------
+      !!
+      !!                   *** ROUTINE obs_rea_snowdepth ***
+      !!
+      !! ** Purpose : Get snowdepth at observation points
+      !!
+      !! ** Method  : 
+      !!
+      !! ** Action  : 
+      !!----------------------------------------------------------------------
+      USE iom
+      !
+      TYPE(obs_surf), INTENT(inout)  ::   fbddata   ! Sea ice freeboard data
+      INTEGER       , INTENT(in)     ::   k2dint    ! ?
+      INTEGER       , INTENT(in)    ::    ksnow     ! Index of snow thickness extra var
+      REAL(wp), INTENT(IN), DIMENSION(jpi,jpj) :: thick_s ! Model snow depth
+     
+      CHARACTER(LEN=12), PARAMETER ::   cpname  = 'obs_rea_snowdepth'
+
+      INTEGER ::   jobs                ! Obs loop variable
+      INTEGER ::   jpi_thick_s, jpj_thick_s      ! Number of grid point in lat/lon for the snow depth
+      INTEGER ::   iico, ijco          ! Grid point indices
+
+      !
+      REAL(wp), DIMENSION(1)     ::   zext, zobsmask
+      REAL(wp), DIMENSION(2,2,1) ::   zweig
+      !
+      REAL(wp), DIMENSION(:,:,:), ALLOCATABLE ::   zmask, z_thick_s_l, zglam, zgphi
+      INTEGER , DIMENSION(:,:,:), ALLOCATABLE ::   igrdi, igrdj
+      !
+      REAL(wp), DIMENSION(jpi,jpj) ::  z_thick_s, thick_s_mask
+         
+      REAL(wp) :: zlam, zphi, zfill, zinfill    ! local scalar
+      !!----------------------------------------------------------------------
+
+      IF(lwp)WRITE(numout,*) 
+      IF(lwp)WRITE(numout,*) ' obs_rea_snowdepth : Get model snow depth for freeboard conversion to sea ice thickness'
+      IF(lwp)WRITE(numout,*) ' ------------- '
+      CALL FLUSH(numout)
+
+      ! Get ice thickness information
+      z_thick_s = thick_s
+
+      ! Setup mask based on tmask
+      thick_s_mask(:,:) = tmask(:,:,1)
+
+      ! Interpolate the snow depth already on the model grid at the observation point
+  
+      ALLOCATE( &
+         & igrdi(2,2,fbddata%nsurf), &
+         & igrdj(2,2,fbddata%nsurf), &
+         & zglam(2,2,fbddata%nsurf), &
+         & zgphi(2,2,fbddata%nsurf), &
+         & zmask(2,2,fbddata%nsurf), &
+         & z_thick_s_l(2,2,fbddata%nsurf)  &
+         & )
+         
+      DO jobs = 1, fbddata%nsurf
+
+         igrdi(1,1,jobs) = fbddata%mi(jobs)-1
+         igrdj(1,1,jobs) = fbddata%mj(jobs)-1
+         igrdi(1,2,jobs) = fbddata%mi(jobs)-1
+         igrdj(1,2,jobs) = fbddata%mj(jobs)
+         igrdi(2,1,jobs) = fbddata%mi(jobs)
+         igrdj(2,1,jobs) = fbddata%mj(jobs)-1
+         igrdi(2,2,jobs) = fbddata%mi(jobs)
+         igrdj(2,2,jobs) = fbddata%mj(jobs)
+
+      END DO
+
+      CALL obs_int_comm_2d( 2, 2, fbddata%nsurf, jpi, jpj, igrdi, igrdj, glamt  , zglam )
+      CALL obs_int_comm_2d( 2, 2, fbddata%nsurf, jpi, jpj, igrdi, igrdj, gphit  , zgphi )
+      CALL obs_int_comm_2d( 2, 2, fbddata%nsurf, jpi, jpj, igrdi, igrdj, thick_s_mask, zmask )
+      CALL obs_int_comm_2d( 2, 2, fbddata%nsurf, jpi, jpj, igrdi, igrdj, z_thick_s  , z_thick_s_l )
+
+      DO jobs = 1, fbddata%nsurf
+            
+         zlam = fbddata%rlam(jobs)
+         zphi = fbddata%rphi(jobs)
+
+         CALL obs_int_h2d_init( 1, 1, k2dint, zlam, zphi,         &
+            &                   zglam(:,:,jobs), zgphi(:,:,jobs), &
+            &                   zmask(:,:,jobs), zweig, zobsmask )
+            
+         CALL obs_int_h2d( 1, 1, zweig, z_thick_s_l(:,:,jobs),  zext )
+ 
+         fbddata%rext(jobs,ksnow) = zext(1)
+
+! mark any masked data with a QC flag
+         IF( zobsmask(1) == 0 )   fbddata%nqc(jobs) = IBSET(fbddata%nqc(jobs),15)
+
+         END DO
+         
+      DEALLOCATE( &
+         & igrdi, &
+         & igrdj, &
+         & zglam, &
+         & zgphi, &
+         & zmask, &
+         & z_thick_s_l  &
+         & )
+
+      IF(lwp)WRITE(numout,*) ' ------------- '
+      !
+   END SUBROUTINE obs_rea_snowdepth
+   
+   !!======================================================================
+END MODULE obs_readsnowdepth
Index: NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_rot_vel.F90
===================================================================
--- NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_rot_vel.F90	(revision 15731)
+++ NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_rot_vel.F90	(revision 15799)
@@ -16,4 +16,5 @@
    USE obs_utils                ! For error handling
    USE obs_profiles_def         ! Profile definitions
+   USE obs_surf_def             ! Surface definitions
    USE obs_inter_h2d            ! Horizontal interpolation
    USE obs_inter_sup            ! MPP support routines for interpolation
@@ -26,5 +27,6 @@
    PRIVATE
 
-   PUBLIC obs_rotvel            ! Rotate the observations
+   PUBLIC obs_rotvel_pro        ! Rotate the profile velocity observations
+   PUBLIC obs_rotvel_surf       ! Rotate the surface velocity observations
 
    !!----------------------------------------------------------------------
@@ -36,8 +38,8 @@
 CONTAINS
 
-   SUBROUTINE obs_rotvel( profdata, k2dint, pu, pv )
+   SUBROUTINE obs_rotvel_pro( profdata, k2dint, kuvar, kvvar, pu, pv )
       !!---------------------------------------------------------------------
       !!
-      !!                   *** ROUTINE obs_rea_pro_dri ***
+      !!                   *** ROUTINE obs_rotvel_pro ***
       !!
       !! ** Purpose : Rotate velocity data into N-S,E-W directorions
@@ -57,5 +59,7 @@
       !! * Arguments
       TYPE(obs_prof), INTENT(INOUT) :: profdata    ! Profile data to be read
-      INTEGER, INTENT(IN) :: k2dint     ! Horizontal interpolation methed
+      INTEGER, INTENT(IN) :: k2dint     ! Horizontal interpolation method
+      INTEGER, INTENT(IN) :: kuvar      ! Index of U velocity
+      INTEGER, INTENT(IN) :: kvvar      ! Index of V velocity
       REAL(wp), DIMENSION(*) :: &
          & pu, &
@@ -185,17 +189,17 @@
          zsin = 0.5_wp * ( zsinu(1) + zsinv(1) )
          
-         IF ( ( profdata%npvsta(ji,1) /= profdata%npvsta(ji,2) ) .OR. &
-            & ( profdata%npvend(ji,1) /= profdata%npvend(ji,2) ) ) THEN
+         IF ( ( profdata%npvsta(ji,kuvar) /= profdata%npvsta(ji,kvvar) ) .OR. &
+            & ( profdata%npvend(ji,kuvar) /= profdata%npvend(ji,kvvar) ) ) THEN
             CALL fatal_error( 'Different number of U and V observations '// &
                'in a profile in obs_rotvel', __LINE__ )
          ENDIF
 
-         DO jk = profdata%npvsta(ji,1), profdata%npvend(ji,1)
-            IF ( ( profdata%var(1)%vmod(jk) /= fbrmdi ) .AND. &
-               & ( profdata%var(2)%vmod(jk) /= fbrmdi ) ) THEN
-               pu(jk) = profdata%var(1)%vmod(jk) * zcos - &
-                  &     profdata%var(2)%vmod(jk) * zsin
-               pv(jk) = profdata%var(2)%vmod(jk) * zcos + &
-                  &     profdata%var(1)%vmod(jk) * zsin
+         DO jk = profdata%npvsta(ji,kuvar), profdata%npvend(ji,kuvar)
+            IF ( ( profdata%var(kuvar)%vmod(jk) /= fbrmdi ) .AND. &
+               & ( profdata%var(kvvar)%vmod(jk) /= fbrmdi ) ) THEN
+               pu(jk) = profdata%var(kuvar)%vmod(jk) * zcos - &
+                  &     profdata%var(kvvar)%vmod(jk) * zsin
+               pv(jk) = profdata%var(kvvar)%vmod(jk) * zcos + &
+                  &     profdata%var(kuvar)%vmod(jk) * zsin
             ELSE
                pu(jk) = fbrmdi
@@ -224,5 +228,188 @@
          & )
 
-   END SUBROUTINE obs_rotvel
+   END SUBROUTINE obs_rotvel_pro
+
+   SUBROUTINE obs_rotvel_surf( surfdata, k2dint, kuvar, kvvar, pu, pv )
+      !!---------------------------------------------------------------------
+      !!
+      !!                   *** ROUTINE obs_rotvel_surf ***
+      !!
+      !! ** Purpose : Rotate surface velocity data into N-S,E-W directorions
+      !!
+      !! ** Method  : Interpolation of geo2ocean coefficients on U,V grid
+      !!              to observation point followed by a similar computations
+      !!              as in geo2ocean.
+      !!
+      !! ** Action  : Review if there is a better way to do this.
+      !!
+      !! References : 
+      !!
+      !! History :  
+      !!      ! :  2009-02 (K. Mogensen) : New routine
+      !!----------------------------------------------------------------------
+      !! * Modules used
+      !! * Arguments
+      TYPE(obs_surf), INTENT(INOUT) :: surfdata    ! Surface data to be read
+      INTEGER, INTENT(IN) :: k2dint     ! Horizontal interpolation method
+      INTEGER, INTENT(IN) :: kuvar      ! Index of U velocity
+      INTEGER, INTENT(IN) :: kvvar      ! Index of V velocity
+      REAL(wp), DIMENSION(*) :: &
+         & pu, &
+         & pv
+      !! * Local declarations
+      REAL(wp), DIMENSION(2,2,1) :: zweig
+      REAL(wp), DIMENSION(:,:,:), ALLOCATABLE :: &
+         & zmasku, &
+         & zmaskv, &
+         & zcoslu, &
+         & zsinlu, &
+         & zcoslv, &
+         & zsinlv, &
+         & zglamu, &
+         & zgphiu, &
+         & zglamv, &
+         & zgphiv
+      REAL(wp), DIMENSION(1) :: &
+         & zsinu, &
+         & zcosu, &
+         & zsinv, &
+         & zcosv
+      REAL(wp) :: zsin
+      REAL(wp) :: zcos
+      REAL(wp), DIMENSION(1) :: zobsmask
+      REAL(wp), DIMENSION(jpi,jpj) :: zsingu,zcosgu,zsingv,zcosgv
+      INTEGER, DIMENSION(:,:,:), ALLOCATABLE :: &
+         & igrdiu, &
+         & igrdju, &
+         & igrdiv, &
+         & igrdjv
+      INTEGER :: ji
+      INTEGER :: jk
+
+      !-----------------------------------------------------------------------
+      ! Allocate data for message parsing and interpolation
+      !-----------------------------------------------------------------------
+
+      ALLOCATE( &
+         & igrdiu(2,2,surfdata%nsurf), &
+         & igrdju(2,2,surfdata%nsurf), &
+         & zglamu(2,2,surfdata%nsurf), &
+         & zgphiu(2,2,surfdata%nsurf), &
+         & zmasku(2,2,surfdata%nsurf), &
+         & zcoslu(2,2,surfdata%nsurf), &
+         & zsinlu(2,2,surfdata%nsurf), &
+         & igrdiv(2,2,surfdata%nsurf), &
+         & igrdjv(2,2,surfdata%nsurf), &
+         & zglamv(2,2,surfdata%nsurf), &
+         & zgphiv(2,2,surfdata%nsurf), &
+         & zmaskv(2,2,surfdata%nsurf), &
+         & zcoslv(2,2,surfdata%nsurf), &
+         & zsinlv(2,2,surfdata%nsurf)  &
+         & )
+
+      !-----------------------------------------------------------------------
+      ! Receive the angles on the U and V grids.
+      !-----------------------------------------------------------------------
+
+      CALL obs_rot( zsingu, zcosgu, zsingv, zcosgv )
+
+      DO ji = 1, surfdata%nsurf
+         igrdiu(1,1,ji) = surfdata%mi(ji,1)-1
+         igrdju(1,1,ji) = surfdata%mj(ji,1)-1
+         igrdiu(1,2,ji) = surfdata%mi(ji,1)-1
+         igrdju(1,2,ji) = surfdata%mj(ji,1)
+         igrdiu(2,1,ji) = surfdata%mi(ji,1)
+         igrdju(2,1,ji) = surfdata%mj(ji,1)-1
+         igrdiu(2,2,ji) = surfdata%mi(ji,1)
+         igrdju(2,2,ji) = surfdata%mj(ji,1)
+         igrdiv(1,1,ji) = surfdata%mi(ji,2)-1
+         igrdjv(1,1,ji) = surfdata%mj(ji,2)-1
+         igrdiv(1,2,ji) = surfdata%mi(ji,2)-1
+         igrdjv(1,2,ji) = surfdata%mj(ji,2)
+         igrdiv(2,1,ji) = surfdata%mi(ji,2)
+         igrdjv(2,1,ji) = surfdata%mj(ji,2)-1
+         igrdiv(2,2,ji) = surfdata%mi(ji,2)
+         igrdjv(2,2,ji) = surfdata%mj(ji,2)
+      END DO
+
+      CALL obs_int_comm_2d( 2, 2, surfdata%nsurf, jpi, jpj, igrdiu, igrdju, &
+         &                  glamu, zglamu )
+      CALL obs_int_comm_2d( 2, 2, surfdata%nsurf, jpi, jpj, igrdiu, igrdju, &
+         &                  gphiu, zgphiu )
+      CALL obs_int_comm_2d( 2, 2, surfdata%nsurf, jpi, jpj, igrdiu, igrdju, &
+         &                  umask(:,:,1), zmasku )
+      CALL obs_int_comm_2d( 2, 2, surfdata%nsurf, jpi, jpj, igrdiu, igrdju, &
+         &                  zsingu, zsinlu )
+      CALL obs_int_comm_2d( 2, 2, surfdata%nsurf, jpi, jpj, igrdiu, igrdju, &
+         &                  zcosgu, zcoslu )
+      CALL obs_int_comm_2d( 2, 2, surfdata%nsurf, jpi, jpj, igrdiv, igrdjv, &
+         &                  glamv, zglamv )
+      CALL obs_int_comm_2d( 2, 2, surfdata%nsurf, jpi, jpj, igrdiv, igrdjv, &
+         &                  gphiv, zgphiv )
+      CALL obs_int_comm_2d( 2, 2, surfdata%nsurf, jpi, jpj, igrdiv, igrdjv, &
+         &                  vmask(:,:,1), zmaskv )
+      CALL obs_int_comm_2d( 2, 2, surfdata%nsurf, jpi, jpj, igrdiv, igrdjv, &
+         &                  zsingv, zsinlv )
+      CALL obs_int_comm_2d( 2, 2, surfdata%nsurf, jpi, jpj, igrdiv, igrdjv, &
+         &                  zcosgv, zcoslv )
+
+      DO ji = 1, surfdata%nsurf
+            
+         CALL obs_int_h2d_init( 1, 1, k2dint, &
+            &                   surfdata%rlam(ji), surfdata%rphi(ji), &
+            &                   zglamu(:,:,ji), zgphiu(:,:,ji), &
+            &                   zmasku(:,:,ji), zweig, zobsmask )
+         
+         CALL obs_int_h2d( 1, 1, zweig, zsinlu(:,:,ji),  zsinu )
+
+         CALL obs_int_h2d( 1, 1, zweig, zcoslu(:,:,ji),  zcosu )
+
+         CALL obs_int_h2d_init( 1, 1, k2dint, &
+            &                   surfdata%rlam(ji), surfdata%rphi(ji), &
+            &                   zglamv(:,:,ji), zgphiv(:,:,ji), &
+            &                   zmaskv(:,:,ji), zweig, zobsmask )
+         
+         CALL obs_int_h2d( 1, 1, zweig, zsinlv(:,:,ji),  zsinv )
+
+         CALL obs_int_h2d( 1, 1, zweig, zcoslv(:,:,ji),  zcosv )
+
+         ! Assume that the angle at observation point is the 
+         ! mean of u and v cosines/sines
+
+         zcos = 0.5_wp * ( zcosu(1) + zcosv(1) )
+         zsin = 0.5_wp * ( zsinu(1) + zsinv(1) )
+
+         IF ( ( surfdata%rmod(ji,kuvar) /= fbrmdi ) .AND. &
+            & ( surfdata%rmod(ji,kvvar) /= fbrmdi ) ) THEN
+            pu(ji) = surfdata%rmod(ji,kuvar) * zcos - &
+               &     surfdata%rmod(ji,kvvar) * zsin
+            pv(ji) = surfdata%rmod(ji,kvvar) * zcos + &
+               &     surfdata%rmod(ji,kuvar) * zsin
+         ELSE
+            pu(ji) = fbrmdi
+            pv(ji) = fbrmdi
+         ENDIF
+
+
+      END DO
+      
+      DEALLOCATE( &
+         & igrdiu, &
+         & igrdju, &
+         & zglamu, &
+         & zgphiu, &
+         & zmasku, &
+         & zcoslu, &
+         & zsinlu, &
+         & igrdiv, &
+         & igrdjv, &
+         & zglamv, &
+         & zgphiv, &
+         & zmaskv, &
+         & zcoslv, &
+         & zsinlv  &
+         & )
+
+   END SUBROUTINE obs_rotvel_surf
 
 END MODULE obs_rot_vel
Index: NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_sstbias.F90
===================================================================
--- NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_sstbias.F90	(revision 15731)
+++ 	(revision )
@@ -1,243 +1,0 @@
-MODULE obs_sstbias
-   !!======================================================================
-   !!                       ***  MODULE obs_sstbias  ***
-   !! Observation diagnostics: Read the bias for SST data
-   !!======================================================================
-   !!----------------------------------------------------------------------
-   !!   obs_app_sstbias : Driver for reading and applying the SST bias
-   !!----------------------------------------------------------------------
-   !! * Modules used   
-   USE par_kind, ONLY : &       ! Precision variables
-      & wp, &
-      & dp, &
-      & sp
-   USE par_oce, ONLY : &        ! Domain parameters
-      & jpi, &
-      & jpj, &
-      & jpim1
-   USE in_out_manager, ONLY : & ! I/O manager
-      & lwp,    &
-      & numout 
-   USE obs_surf_def             ! Surface observation definitions
-   USE dom_oce, ONLY : &        ! Domain variables
-      & tmask, &
-      & tmask_i, &
-      & e1t,   &
-      & e2t,   &
-      & gphit, &
-      & glamt
-   USE oce, ONLY : &           ! Model variables
-      & sshn
-   USE obs_inter_h2d
-   USE obs_utils               ! Various observation tools
-   USE obs_inter_sup
-   IMPLICIT NONE
-   !! * Routine accessibility
-   PRIVATE
-   PUBLIC obs_app_sstbias     ! Read the altimeter bias
-CONTAINS
-   SUBROUTINE obs_app_sstbias( sstdata, k2dint, knumtypes, &
-                               cl_bias_files )
-      !!---------------------------------------------------------------------
-      !!
-      !!                   *** ROUTINE obs_app_sstbias ***
-      !!
-      !! ** Purpose : Read SST bias data from files and apply correction to
-      !!             observations
-      !!
-      !! ** Method  :
-      !!
-      !! ** Action  :
-      !!
-      !! References :
-      !!
-      !! History : 
-      !!      ! :  2014-08 (J. While) Bias correction code for SST obs,
-      !!      !                      based on obs_rea_altbias
-      !!----------------------------------------------------------------------
-      !! * Modules used
-      USE iom
-      USE netcdf
-      !! * Arguments
-
-      TYPE(obs_surf), INTENT(INOUT) :: sstdata       ! SST data
-      INTEGER, INTENT(IN) :: k2dint
-      INTEGER, INTENT(IN) :: knumtypes !number of bias types to read in
-      CHARACTER(LEN=128), DIMENSION(knumtypes), INTENT(IN) :: &
-                          cl_bias_files !List of files to read
-      !! * Local declarations
-      INTEGER :: jobs         ! Obs loop variable
-      INTEGER :: jpisstbias   ! Number of grid point in latitude for the bias
-      INTEGER :: jpjsstbias   ! Number of grid point in longitude for the bias
-      INTEGER :: iico         ! Grid point indices
-      INTEGER :: ijco
-      INTEGER :: jt
-      INTEGER :: i_nx_id      ! Index to read the NetCDF file
-      INTEGER :: i_ny_id      !
-      INTEGER :: i_file_id    !
-      INTEGER :: i_var_id
-      INTEGER, DIMENSION(knumtypes) :: &
-         & ibiastypes             ! Array of the bias types in each file
-      REAL(wp), DIMENSION(jpi,jpj,knumtypes) :: & 
-         & z_sstbias              ! Array to store the SST bias values
-      REAL(wp), DIMENSION(jpi,jpj) :: & 
-         & z_sstbias_2d           ! Array to store the SST bias values   
-      REAL(wp), DIMENSION(1) :: &
-         & zext, &
-         & zobsmask
-      REAL(wp), DIMENSION(2,2,1) :: &
-         & zweig
-      REAL(wp), DIMENSION(:,:,:), ALLOCATABLE :: &
-         & zmask, &
-         & zglam, &
-         & zgphi
-      REAL(wp), DIMENSION(:,:,:), ALLOCATABLE :: &
-         & zmask_tmp, &
-         & zglam_tmp, &
-         & zgphi_tmp   
-      REAL(wp), ALLOCATABLE, DIMENSION(:,:,:) ::  zbias   
-      REAL(wp) :: zlam
-      REAL(wp) :: zphi
-      INTEGER, DIMENSION(:,:,:), ALLOCATABLE :: &
-         & igrdi, &
-         & igrdj
-      INTEGER, DIMENSION(:,:,:), ALLOCATABLE :: &
-         & igrdi_tmp, &
-         & igrdj_tmp   
-      INTEGER :: numsstbias
-      INTEGER(KIND=NF90_INT) :: ifile_source
-     
-      INTEGER :: incfile
-      INTEGER :: jtype
-      INTEGER :: iret 
-      INTEGER :: inumtype
-      IF(lwp)WRITE(numout,*) 
-      IF(lwp)WRITE(numout,*) 'obs_rea_sstbias : '
-      IF(lwp)WRITE(numout,*) '----------------- '
-      IF(lwp)WRITE(numout,*) 'Read SST bias '
-      ! Open and read the files
-      z_sstbias(:,:,:)=0.0_wp
-      DO jtype = 1, knumtypes
-     
-         numsstbias=0
-         IF(lwp)WRITE(numout,*) 'Opening ',cl_bias_files(jtype)
-         CALL iom_open( cl_bias_files(jtype), numsstbias, ldstop=.FALSE. )       
-         IF (numsstbias > 0) THEN
-     
-            !Read the bias type from the file
-            !No IOM get attribute command at time of writing, 
-            !so have to use NETCDF
-            !routines directly - should be upgraded in the future
-            iret=NF90_OPEN(TRIM(cl_bias_files(jtype)), NF90_NOWRITE, incfile)
-            iret=NF90_GET_ATT( incfile, NF90_GLOBAL, "SST_source", &
-                              ifile_source )
-            ibiastypes(jtype) = ifile_source                 
-            iret=NF90_CLOSE(incfile)       
-           
-            IF ( iret /= 0  ) CALL ctl_stop( &
-               'obs_rea_sstbias : Cannot read bias type from file '// &
-               cl_bias_files(jtype) )
-            ! Get the SST bias data
-            CALL iom_get( numsstbias, jpdom_data, 'tn', z_sstbias_2d(:,:), 1 )
-            z_sstbias(:,:,jtype) = z_sstbias_2d(:,:)       
-            ! Close the file
-            CALL iom_close(numsstbias)       
-         ELSE
-            CALL ctl_stop('obs_read_sstbias: File '// & 
-                           TRIM( cl_bias_files(jtype) )//' Not found')
-         ENDIF
-      END DO
-           
-      ! Interpolate the bias already on the model grid at the observation point
-      ALLOCATE( &
-         & igrdi(2,2,sstdata%nsurf), &
-         & igrdj(2,2,sstdata%nsurf), &
-         & zglam(2,2,sstdata%nsurf), &
-         & zgphi(2,2,sstdata%nsurf), &
-         & zmask(2,2,sstdata%nsurf)  )
-       
-      DO jobs = 1, sstdata%nsurf 
-         igrdi(1,1,jobs) = sstdata%mi(jobs)-1
-         igrdj(1,1,jobs) = sstdata%mj(jobs)-1
-         igrdi(1,2,jobs) = sstdata%mi(jobs)-1
-         igrdj(1,2,jobs) = sstdata%mj(jobs)
-         igrdi(2,1,jobs) = sstdata%mi(jobs)
-         igrdj(2,1,jobs) = sstdata%mj(jobs)-1
-         igrdi(2,2,jobs) = sstdata%mi(jobs)
-         igrdj(2,2,jobs) = sstdata%mj(jobs)
-      END DO
-      CALL obs_int_comm_2d( 2, 2, sstdata%nsurf, jpi, jpj, &
-         &                  igrdi, igrdj, glamt, zglam )
-      CALL obs_int_comm_2d( 2, 2, sstdata%nsurf, jpi, jpj, &
-         &                  igrdi, igrdj, gphit, zgphi )
-      CALL obs_int_comm_2d( 2, 2, sstdata%nsurf, jpi, jpj, &
-         &                  igrdi, igrdj, tmask(:,:,1), zmask )
-      DO jtype = 1, knumtypes
-         
-         !Find the number observations of type and allocate tempory arrays
-         inumtype = COUNT( sstdata%ntyp(:) == ibiastypes(jtype) )
-         ALLOCATE( &
-            & igrdi_tmp(2,2,inumtype), &
-            & igrdj_tmp(2,2,inumtype), &
-            & zglam_tmp(2,2,inumtype), &
-            & zgphi_tmp(2,2,inumtype), &
-            & zmask_tmp(2,2,inumtype), &
-            & zbias( 2,2,inumtype ) )
-         jt=1
-         DO jobs = 1, sstdata%nsurf 
-            IF ( sstdata%ntyp(jobs) == ibiastypes(jtype) ) THEN
-               igrdi_tmp(:,:,jt) = igrdi(:,:,jobs) 
-               igrdj_tmp(:,:,jt) = igrdj(:,:,jobs)
-               zglam_tmp(:,:,jt) = zglam(:,:,jobs)
-               zgphi_tmp(:,:,jt) = zgphi(:,:,jobs)
-               zmask_tmp(:,:,jt) = zmask(:,:,jobs)
-               jt = jt +1
-            ENDIF
-         END DO
-                         
-         CALL obs_int_comm_2d( 2, 2, inumtype, jpi, jpj, &
-               &           igrdi_tmp(:,:,:), igrdj_tmp(:,:,:), &
-               &           z_sstbias(:,:,jtype), zbias(:,:,:) )
-         jt=1
-         DO jobs = 1, sstdata%nsurf
-            IF ( sstdata%ntyp(jobs) == ibiastypes(jtype) ) THEN
-               zlam = sstdata%rlam(jobs)
-               zphi = sstdata%rphi(jobs)
-               iico = sstdata%mi(jobs)
-               ijco = sstdata%mj(jobs)         
-               CALL obs_int_h2d_init( 1, 1, k2dint, zlam, zphi,         &
-                  &                   zglam_tmp(:,:,jt), &
-                  &                   zgphi_tmp(:,:,jt), &
-                  &                   zmask_tmp(:,:,jt), zweig, zobsmask )
-               CALL obs_int_h2d( 1, 1, zweig, zbias(:,:,jt),  zext )
-               ! adjust sst with bias field
-               sstdata%robs(jobs,1) = sstdata%robs(jobs,1) - zext(1)
-               jt=jt+1
-            ENDIF
-         END DO 
-               
-         !Deallocate arrays
-         DEALLOCATE( &
-         & igrdi_tmp, &
-         & igrdj_tmp, &
-         & zglam_tmp, &
-         & zgphi_tmp, &
-         & zmask_tmp, &
-         & zbias )           
-      END DO
-      DEALLOCATE( &
-         & igrdi, &
-         & igrdj, &
-         & zglam, &
-         & zgphi, &
-         & zmask )
-
-      IF(lwp) THEN
-         WRITE(numout,*) " "
-         WRITE(numout,*) "SST bias correction applied successfully"
-         WRITE(numout,*) "Obs types: ",ibiastypes(:), &
-                              " Have all been bias corrected\n"
-      ENDIF
-   END SUBROUTINE obs_app_sstbias
- 
-END MODULE obs_sstbias
Index: NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_surf_def.F90
===================================================================
--- NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_surf_def.F90	(revision 15731)
+++ NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_surf_def.F90	(revision 15799)
@@ -23,4 +23,5 @@
    USE obs_mpp, ONLY : &  ! MPP tools 
       obs_mpp_sum_integer
+   USE obs_fbm            ! Obs feedback format
 
    IMPLICIT NONE
@@ -45,4 +46,5 @@
       INTEGER :: nsurfmpp   !: Global number of surface data within window
       INTEGER :: nvar       !: Number of variables at observation points
+      INTEGER :: nadd       !: Number of additional fields at observation points
       INTEGER :: nextra     !: Number of extra fields at observation points
       INTEGER :: nstp       !: Number of time steps
@@ -55,6 +57,4 @@
 
       INTEGER, POINTER, DIMENSION(:) :: &
-         & mi,   &        !: i-th grid coord. for interpolating to surface observation
-         & mj,   &        !: j-th grid coord. for interpolating to surface observation
          & mt,   &        !: time record number for gridded data
          & nsidx,&        !: Surface observation number
@@ -69,8 +69,31 @@
          & ntyp           !: Type of surface observation product
 
-      CHARACTER(len=8), POINTER, DIMENSION(:) :: &
-         & cvars          !: Variable names
-
-      CHARACTER(LEN=8), POINTER, DIMENSION(:) :: &
+      INTEGER, POINTER, DIMENSION(:,:) :: &
+         & mi,   &        !: i-th grid coord. for interpolating to surface observation
+         & mj             !: j-th grid coord. for interpolating to surface observation
+
+      CHARACTER(len=ilenname), POINTER, DIMENSION(:) :: &
+         & cvars,    &    !: Variable names
+         & cextvars, &    !: Extra variable names
+         & caddvars       !: Additional variable names
+
+      CHARACTER(len=ilenlong), POINTER, DIMENSION(:) :: &
+         & clong,    &    !: Variable long names
+         & cextlong       !: Extra variable long names
+
+      CHARACTER(len=ilenlong), POINTER, DIMENSION(:,:) :: &
+         & caddlong       !: Additional variable long names
+
+      CHARACTER(len=ilenunit), POINTER, DIMENSION(:) :: &
+         & cunit,    &    !: Variable units
+         & cextunit       !: Extra variable units
+
+      CHARACTER(len=ilenunit), POINTER, DIMENSION(:,:) :: &
+         & caddunit       !: Additional variable units
+
+      CHARACTER(len=ilengrid), POINTER, DIMENSION(:) :: &
+         & cgrid          !: Variable grids
+
+      CHARACTER(LEN=ilenwmo), POINTER, DIMENSION(:) :: &
          & cwmo           !: WMO indentifier
          
@@ -86,5 +109,8 @@
          & rext           !: Extra fields interpolated to observation points
 
-      REAL(KIND=wp), POINTER, DIMENSION(:,:) :: &
+      REAL(KIND=wp), POINTER, DIMENSION(:,:,:) :: &
+         & radd           !: Additional fields interpolated to observation points
+
+      REAL(KIND=wp), POINTER, DIMENSION(:,:,:) :: &
          & vdmean         !: Time averaged of model field
 
@@ -121,5 +147,5 @@
 CONTAINS
    
-   SUBROUTINE obs_surf_alloc( surf, ksurf, kvar, kextra, kstp, kpi, kpj )
+   SUBROUTINE obs_surf_alloc( surf, ksurf, kvar, kadd, kextra, kstp, kpi, kpj )
       !!----------------------------------------------------------------------
       !!                     ***  ROUTINE obs_surf_alloc  ***
@@ -136,4 +162,5 @@
       INTEGER, INTENT(IN) :: ksurf   ! Number of surface observations
       INTEGER, INTENT(IN) :: kvar    ! Number of surface variables
+      INTEGER, INTENT(IN) :: kadd    ! Number of additional fields at observation points
       INTEGER, INTENT(IN) :: kextra  ! Number of extra fields at observation points
       INTEGER, INTENT(IN) :: kstp    ! Number of time steps
@@ -143,5 +170,5 @@
       !!* Local variables
       INTEGER :: ji
-      INTEGER :: jvar
+      INTEGER :: jvar, jadd, jext
 
       ! Set bookkeeping variables
@@ -149,4 +176,5 @@
       surf%nsurf    = ksurf
       surf%nsurfmpp = 0
+      surf%nadd     = kadd
       surf%nextra   = kextra
       surf%nvar     = kvar
@@ -158,9 +186,40 @@
 
       ALLOCATE( &
-         & surf%cvars(kvar)    &
+         & surf%cvars(kvar), &
+         & surf%clong(kvar), &
+         & surf%cunit(kvar), &
+         & surf%cgrid(kvar)  &
          & )
 
       DO jvar = 1, kvar
          surf%cvars(jvar) = "NotSet"
+         surf%clong(jvar) = "NotSet"
+         surf%cunit(jvar) = "NotSet"
+         surf%cgrid(jvar) = ""
+      END DO
+
+      ! Allocate additional/extra variable metadata
+
+      ALLOCATE( &
+         & surf%caddvars(kadd),      &
+         & surf%caddlong(kadd,kvar), &
+         & surf%caddunit(kadd,kvar), &
+         & surf%cextvars(kextra),    &
+         & surf%cextlong(kextra),    &
+         & surf%cextunit(kextra)     &
+         )
+         
+      DO jadd = 1, kadd
+         surf%caddvars(jadd) = "NotSet"
+         DO jvar = 1, kvar
+            surf%caddlong(jadd,jvar) = "NotSet"
+            surf%caddunit(jadd,jvar) = "NotSet"
+         END DO
+      END DO
+         
+      DO jext = 1, kextra
+         surf%cextvars(jext) = "NotSet"
+         surf%cextlong(jext) = "NotSet"
+         surf%cextunit(jext) = "NotSet"
       END DO
       
@@ -168,6 +227,4 @@
 
       ALLOCATE( &
-         & surf%mi(ksurf),      &
-         & surf%mj(ksurf),      &
          & surf%mt(ksurf),      &
          & surf%nsidx(ksurf),   &
@@ -187,4 +244,9 @@
          & )
 
+      ALLOCATE( &
+         & surf%mi(ksurf,kvar), &
+         & surf%mj(ksurf,kvar)  &
+         & )
+
       surf%mt(:) = -1
 
@@ -205,4 +267,12 @@
       surf%rext(:,:) = 0.0_wp 
 
+      ! Allocate arrays of number of additional fields at observation points
+
+      ALLOCATE( & 
+         & surf%radd(ksurf,kadd,kvar) &
+         & )
+
+      surf%radd(:,:,:) = 0.0_wp 
+
       ! Allocate arrays of number of time step size
 
@@ -215,5 +285,5 @@
 
       ALLOCATE( &
-         & surf%vdmean(kpi,kpj) &
+         & surf%vdmean(kpi,kpj,kvar) &
          & )
 
@@ -291,4 +361,10 @@
          & )
 
+      ! Deallocate arrays of number of additional fields at observation points
+
+      DEALLOCATE( & 
+         & surf%radd &
+         & )
+
       ! Deallocate arrays of size number of grid points size times
       ! number of variables
@@ -308,6 +384,20 @@
 
       DEALLOCATE( &
-         & surf%cvars     &
-         & )
+         & surf%cvars, &
+         & surf%clong, &
+         & surf%cunit, &
+         & surf%cgrid  &
+         & )
+
+      ! Dellocate additional/extra variables metadata
+
+      DEALLOCATE( &
+         & surf%caddvars, &
+         & surf%caddlong, &
+         & surf%caddunit, &
+         & surf%cextvars, &
+         & surf%cextlong, &
+         & surf%cextunit  &
+         )
 
    END SUBROUTINE obs_surf_dealloc
@@ -343,4 +433,5 @@
       INTEGER :: ji
       INTEGER :: jk
+      INTEGER :: jadd
       LOGICAL, DIMENSION(:), ALLOCATABLE :: llvalid
 
@@ -361,5 +452,5 @@
 
       IF ( lallocate ) THEN
-         CALL obs_surf_alloc( newsurf,  insurf, surf%nvar, &
+         CALL obs_surf_alloc( newsurf,  insurf, surf%nvar, surf%nadd, &
             & surf%nextra, surf%nstp, surf%npi, surf%npj )
       ENDIF
@@ -388,6 +479,6 @@
             insurf = insurf + 1
 
-            newsurf%mi(insurf)    = surf%mi(ji)
-            newsurf%mj(insurf)    = surf%mj(ji)
+            newsurf%mi(insurf,:)  = surf%mi(ji,:)
+            newsurf%mj(insurf,:)  = surf%mj(ji,:)
             newsurf%mt(insurf)    = surf%mt(ji)
             newsurf%nsidx(insurf) = surf%nsidx(ji)
@@ -410,4 +501,8 @@
                newsurf%rmod(insurf,jk)  = surf%rmod(ji,jk)
                
+               DO jadd = 1, surf%nadd
+                  newsurf%radd(insurf,jadd,jk) = surf%radd(ji,jadd,jk)
+               END DO
+               
             END DO
 
@@ -433,6 +528,15 @@
       ! Set book keeping variables which do not depend on number of obs.
 
-      newsurf%nstp     = surf%nstp
-      newsurf%cvars(:) = surf%cvars(:)
+      newsurf%nstp          = surf%nstp
+      newsurf%cvars(:)      = surf%cvars(:)
+      newsurf%clong(:)      = surf%clong(:)
+      newsurf%cunit(:)      = surf%cunit(:)
+      newsurf%cgrid(:)      = surf%cgrid(:)
+      newsurf%caddvars(:)   = surf%caddvars(:)
+      newsurf%caddlong(:,:) = surf%caddlong(:,:)
+      newsurf%caddunit(:,:) = surf%caddunit(:,:)
+      newsurf%cextvars(:)   = surf%cextvars(:)
+      newsurf%cextlong(:)   = surf%cextlong(:)
+      newsurf%cextunit(:)   = surf%cextunit(:)
       
       ! Set gridded stuff
@@ -470,4 +574,5 @@
       INTEGER :: jj
       INTEGER :: jk
+      INTEGER :: jadd
 
       ! Copy data from surf to old surf
@@ -475,8 +580,8 @@
       DO ji = 1, surf%nsurf
 
-         jj=surf%nsind(ji)
-
-         oldsurf%mi(jj)    = surf%mi(ji)
-         oldsurf%mj(jj)    = surf%mj(ji)
+         jj = surf%nsind(ji)
+
+         oldsurf%mi(jj,:)  = surf%mi(ji,:)
+         oldsurf%mj(jj,:)  = surf%mj(ji,:)
          oldsurf%mt(jj)    = surf%mt(ji)
          oldsurf%nsidx(jj) = surf%nsidx(ji)
@@ -500,8 +605,12 @@
          DO ji = 1, surf%nsurf
             
-            jj=surf%nsind(ji)
+            jj = surf%nsind(ji)
 
             oldsurf%robs(jj,jk)  = surf%robs(ji,jk)
             oldsurf%rmod(jj,jk)  = surf%rmod(ji,jk)
+               
+            DO jadd = 1, surf%nadd
+               oldsurf%radd(jj,jadd,jk) = surf%radd(ji,jadd,jk)
+            END DO
 
          END DO
@@ -513,5 +622,5 @@
          DO ji = 1, surf%nsurf
             
-            jj=surf%nsind(ji)
+            jj = surf%nsind(ji)
 
             oldsurf%rext(jj,jk)  = surf%rext(ji,jk)
Index: NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_write.F90
===================================================================
--- NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_write.F90	(revision 15731)
+++ NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/OBS/obs_write.F90	(revision 15799)
@@ -54,5 +54,5 @@
 CONTAINS
 
-   SUBROUTINE obs_wri_prof( profdata, padd, pext )
+   SUBROUTINE obs_wri_prof( profdata, clfiletype, padd, pext )
       !!-----------------------------------------------------------------------
       !!
@@ -77,13 +77,20 @@
       !! * Arguments
       TYPE(obs_prof), INTENT(INOUT) :: profdata      ! Full set of profile data
-      TYPE(obswriinfo), OPTIONAL :: padd             ! Additional info for each variable
-      TYPE(obswriinfo), OPTIONAL :: pext             ! Extra info
+      CHARACTER(LEN=25), INTENT(IN) :: clfiletype    ! Base name for file name
+      TYPE(obswriinfo), OPTIONAL    :: padd          ! Additional info for each variable
+      TYPE(obswriinfo), OPTIONAL    :: pext          ! Extra info
 
       !! * Local declarations
       TYPE(obfbdata) :: fbdata
       CHARACTER(LEN=40) :: clfname
-      CHARACTER(LEN=10) :: clfiletype
+      CHARACTER(LEN=ilenlong) :: cllongname  ! Long name of variable
+      CHARACTER(LEN=ilenunit) :: clunits     ! Units of variable
+      CHARACTER(LEN=ilengrid) :: clgrid      ! Grid of variable
+      CHARACTER(LEN=12) :: clfmt            ! writing format
+      INTEGER :: idg                        ! number of digits
       INTEGER :: ilevel
       INTEGER :: jvar
+      INTEGER :: jvar2
+      INTEGER :: jsal
       INTEGER :: jo
       INTEGER :: jk
@@ -111,79 +118,41 @@
       ! Find maximum level
       ilevel = 0
-      DO jvar = 1, 2
+      DO jvar = 1, profdata%nvar
          ilevel = MAX( ilevel, MAXVAL( profdata%var(jvar)%nvlidx(:) ) )
       END DO
 
-      SELECT CASE ( TRIM(profdata%cvars(1)) )
-      CASE('POTM')
-
-         clfiletype='profb'
-         CALL alloc_obfbdata( fbdata, 2, profdata%nprof, ilevel, &
-            &                 1 + iadd, 1 + iext, .TRUE. )
-         fbdata%cname(1)      = profdata%cvars(1)
-         fbdata%cname(2)      = profdata%cvars(2)
-         fbdata%coblong(1)    = 'Potential temperature'
-         fbdata%coblong(2)    = 'Practical salinity'
-         fbdata%cobunit(1)    = 'Degrees centigrade'
-         fbdata%cobunit(2)    = 'PSU'
-         fbdata%cextname(1)   = 'TEMP'
-         fbdata%cextlong(1)   = 'Insitu temperature'
-         fbdata%cextunit(1)   = 'Degrees centigrade'
-         fbdata%caddlong(1,1) = 'Model interpolated potential temperature'
-         fbdata%caddlong(1,2) = 'Model interpolated practical salinity'
-         fbdata%caddunit(1,1) = 'Degrees centigrade'
-         fbdata%caddunit(1,2) = 'PSU'
-         fbdata%cgrid(:)      = 'T'
-         DO je = 1, iext
-            fbdata%cextname(1+je) = pext%cdname(je)
-            fbdata%cextlong(1+je) = pext%cdlong(je,1)
-            fbdata%cextunit(1+je) = pext%cdunit(je,1)
-         END DO
-         DO ja = 1, iadd
-            fbdata%caddname(1+ja) = padd%cdname(ja)
-            DO jvar = 1, 2
+      CALL alloc_obfbdata( fbdata, profdata%nvar, profdata%nprof, ilevel, &
+            &                 1 + iadd, iext, .TRUE. )
+      fbdata%caddname(1)   = 'Hx'
+      DO jvar = 1, profdata%nvar
+         fbdata%cname(jvar)      = profdata%cvars(jvar)
+         fbdata%coblong(jvar)    = profdata%clong(jvar)
+         fbdata%cobunit(jvar)    = profdata%cunit(jvar)
+         fbdata%cgrid(jvar)      = profdata%cgrid(jvar)
+         fbdata%caddlong(1,jvar) = 'Model interpolated ' // TRIM(profdata%clong(jvar))
+         fbdata%caddunit(1,jvar) = profdata%cunit(jvar)
+         IF (iadd > 0) THEN
+            DO ja = 1, iadd
+               fbdata%caddname(1+ja) = padd%cdname(ja)
                fbdata%caddlong(1+ja,jvar) = padd%cdlong(ja,jvar)
                fbdata%caddunit(1+ja,jvar) = padd%cdunit(ja,jvar)
             END DO
-         END DO
-
-      CASE('UVEL')
-
-         clfiletype='velfb'
-         CALL alloc_obfbdata( fbdata, 2, profdata%nprof, ilevel, 1, 0, .TRUE. )
-         fbdata%cname(1)      = profdata%cvars(1)
-         fbdata%cname(2)      = profdata%cvars(2)
-         fbdata%coblong(1)    = 'Zonal velocity'
-         fbdata%coblong(2)    = 'Meridional velocity'
-         fbdata%cobunit(1)    = 'm/s'
-         fbdata%cobunit(2)    = 'm/s'
-         DO je = 1, iext
-            fbdata%cextname(je) = pext%cdname(je)
-            fbdata%cextlong(je) = pext%cdlong(je,1)
-            fbdata%cextunit(je) = pext%cdunit(je,1)
-         END DO
-         fbdata%caddlong(1,1) = 'Model interpolated zonal velocity'
-         fbdata%caddlong(1,2) = 'Model interpolated meridional velocity'
-         fbdata%caddunit(1,1) = 'm/s'
-         fbdata%caddunit(1,2) = 'm/s'
-         fbdata%cgrid(1)      = 'U' 
-         fbdata%cgrid(2)      = 'V'
-         DO ja = 1, iadd
-            fbdata%caddname(1+ja) = padd%cdname(ja)
-            fbdata%caddlong(1+ja,1) = padd%cdlong(ja,1)
-            fbdata%caddunit(1+ja,1) = padd%cdunit(ja,1)
-         END DO
-
-      END SELECT
-
-      fbdata%caddname(1)   = 'Hx'
-
-      WRITE(clfname, FMT="(A,'_fdbk_',I4.4,'.nc')") TRIM(clfiletype), nproc
+         ENDIF
+         IF (iext > 0) THEN
+            DO je = 1, iext
+               fbdata%cextname(je) = pext%cdname(je)
+               fbdata%cextlong(je) = pext%cdlong(je,1)
+               fbdata%cextunit(je) = pext%cdunit(je,1)
+            END DO
+         ENDIF
+      END DO
+
+      WRITE(clfname, FMT="(A,'fb_fdbk_',I4.4,'.nc')") TRIM(clfiletype), nproc
 
       IF(lwp) THEN
          WRITE(numout,*)
-         WRITE(numout,*)'obs_wri_prof :'
-         WRITE(numout,*)'~~~~~~~~~~~~~'
-         WRITE(numout,*)'Writing '//TRIM(clfiletype)//' feedback file : ',TRIM(clfname)
+         WRITE(numout,*) 'obs_wri_prof :'
+         WRITE(numout,*) '~~~~~~~~~~~~~'
+         WRITE(numout,*) 'Writing '//TRIM(clfiletype)//' feedback file : ', TRIM(clfname)
       ENDIF
 
@@ -228,5 +197,5 @@
             &           krefdate = 19500101 )
          ! Reform the profiles arrays for output
-         DO jvar = 1, 2
+         DO jvar = 1, profdata%nvar
             DO jk = profdata%npvsta(jo,jvar), profdata%npvend(jo,jvar)
                ik = profdata%var(jvar)%nvlidx(jk)
@@ -247,38 +216,60 @@
                ENDIF
                fbdata%iobsk(ik,jo,jvar)  = profdata%var(jvar)%mvk(jk)
-               DO ja = 1, iadd
-                  fbdata%padd(ik,jo,1+ja,jvar) = &
-                     & profdata%var(jvar)%vext(jk,padd%ipoint(ja))
+               IF (iadd > 0) THEN
+                  DO ja = 1, iadd
+                     fbdata%padd(ik,jo,1+ja,jvar) = &
+                        & profdata%var(jvar)%vadd(jk,padd%ipoint(ja))
+                  END DO
+               ENDIF
+            END DO
+         END DO
+         IF (iext > 0) THEN
+            DO jk = profdata%npvstaext(jo), profdata%npvendext(jo)
+               ik = profdata%vext%nelidx(jk)
+               DO je = 1, iext
+                  fbdata%pext(ik,jo,je) = &
+                     & profdata%vext%eobs(jk,pext%ipoint(je))
                END DO
-               DO je = 1, iext
-                  fbdata%pext(ik,jo,1+je) = &
-                     & profdata%var(jvar)%vext(jk,pext%ipoint(je))
-               END DO
-               IF ( ( jvar == 1 ) .AND. &
-                  & ( TRIM(profdata%cvars(1)) == 'POTM' ) ) THEN
-                  fbdata%pext(ik,jo,1) = profdata%var(jvar)%vext(jk,1)
-               ENDIF 
-            END DO
-         END DO
+            END DO
+         ENDIF
       END DO
 
-      IF ( TRIM(profdata%cvars(1)) == 'POTM' ) THEN
-         ! Convert insitu temperature to potential temperature using the model
-         ! salinity if no potential temperature
-         DO jo = 1, fbdata%nobs
-            IF ( fbdata%pphi(jo) < 9999.0 ) THEN
-               DO jk = 1, fbdata%nlev
-                  IF ( ( fbdata%pob(jk,jo,1) >= 9999.0 ) .AND. &
-                     & ( fbdata%pdep(jk,jo) < 9999.0 ) .AND. &
-                     & ( fbdata%padd(jk,jo,1,2) < 9999.0 ) .AND. &
-                     & ( fbdata%pext(jk,jo,1) < 9999.0 ) ) THEN
-                     zpres = dep_to_p( REAL(fbdata%pdep(jk,jo),wp), &
-                        &              REAL(fbdata%pphi(jo),wp) )
-                     fbdata%pob(jk,jo,1) = potemp( &
-                        &                     REAL(fbdata%padd(jk,jo,1,2), wp),  &
-                        &                     REAL(fbdata%pext(jk,jo,1), wp), &
-                        &                     zpres, 0.0_wp )
+      ! Convert insitu temperature to potential temperature using the model
+      ! salinity if no potential temperature
+      IF (iext > 0) THEN
+         DO jvar = 1, profdata%nvar
+            IF ( TRIM(profdata%cvars(jvar)) == 'POTM' ) THEN
+               jsal = 0
+               DO jvar2 = 1, profdata%nvar
+                  IF ( TRIM(profdata%cvars(jvar2)) == 'PSAL' ) THEN
+                     jsal = jvar2
+                     EXIT
                   ENDIF
                END DO
+               IF (jsal > 0) THEN
+                  DO je = 1, iext
+                     IF ( TRIM(fbdata%cextname(je)) == 'TEMP' ) THEN
+                        DO jo = 1, fbdata%nobs
+                           IF ( fbdata%pphi(jo) < 9999.0 ) THEN
+                              DO jk = 1, fbdata%nlev
+                                 IF ( ( fbdata%pob(jk,jo,jvar)   >= 9999.0 ) .AND. &
+                                    & ( fbdata%pdep(jk,jo)        < 9999.0 ) .AND. &
+                                    & ( fbdata%padd(jk,jo,1,jsal) < 9999.0 ) .AND. &
+                                    & ( fbdata%pext(jk,jo,je)     < 9999.0 ) ) THEN
+                                    zpres = dep_to_p( REAL(fbdata%pdep(jk,jo),wp), &
+                                       &              REAL(fbdata%pphi(jo),wp) )
+                                    fbdata%pob(jk,jo,jvar) = potemp( &
+                                       &                     REAL(fbdata%padd(jk,jo,1,jsal), wp), &
+                                       &                     REAL(fbdata%pext(jk,jo,je), wp),     &
+                                       &                     zpres, 0.0_wp )
+                                 ENDIF
+                              END DO
+                           ENDIF
+                        END DO
+                        EXIT
+                     ENDIF
+                  END DO
+               ENDIF
+               EXIT
             ENDIF
          END DO
@@ -295,5 +286,5 @@
    END SUBROUTINE obs_wri_prof
 
-   SUBROUTINE obs_wri_surf( surfdata, padd, pext )
+   SUBROUTINE obs_wri_surf( surfdata, clfiletype, padd, pext )
       !!-----------------------------------------------------------------------
       !!
@@ -315,16 +306,20 @@
 
       !! * Arguments
-      TYPE(obs_surf), INTENT(INOUT) :: surfdata         ! Full set of surface data
-      TYPE(obswriinfo), OPTIONAL :: padd               ! Additional info for each variable
-      TYPE(obswriinfo), OPTIONAL :: pext               ! Extra info
+      TYPE(obs_surf), INTENT(INOUT) :: surfdata      ! Full set of surface data
+      CHARACTER(LEN=25), INTENT(IN) :: clfiletype    ! Base name for file name
+      TYPE(obswriinfo), OPTIONAL    :: padd          ! Additional info for each variable
+      TYPE(obswriinfo), OPTIONAL    :: pext          ! Extra info
 
       !! * Local declarations
       TYPE(obfbdata) :: fbdata
       CHARACTER(LEN=40) :: clfname         ! netCDF filename
-      CHARACTER(LEN=10) :: clfiletype
+      CHARACTER(LEN=ilenlong) :: cllongname  ! Long name of variable
+      CHARACTER(LEN=ilenunit) :: clunits     ! Units of variable
+      CHARACTER(LEN=ilengrid) :: clgrid      ! Grid of variable
       CHARACTER(LEN=12), PARAMETER :: cpname = 'obs_wri_surf'
       INTEGER :: jo
       INTEGER :: ja
       INTEGER :: je
+      INTEGER :: jvar
       INTEGER :: iadd
       INTEGER :: iext
@@ -344,118 +339,37 @@
       CALL init_obfbdata( fbdata )
 
-      SELECT CASE ( TRIM(surfdata%cvars(1)) )
-      CASE('SLA')
-
-         CALL alloc_obfbdata( fbdata, 1, surfdata%nsurf, 1, &
-            &                 2 + iadd, 1 + iext, .TRUE. )
-
-         clfiletype = 'slafb'
-         fbdata%cname(1)      = surfdata%cvars(1)
-         fbdata%coblong(1)    = 'Sea level anomaly'
-         fbdata%cobunit(1)    = 'Metres'
-         fbdata%cextname(1)   = 'MDT'
-         fbdata%cextlong(1)   = 'Mean dynamic topography'
-         fbdata%cextunit(1)   = 'Metres'
-         DO je = 1, iext
-            fbdata%cextname(je) = pext%cdname(je)
-            fbdata%cextlong(je) = pext%cdlong(je,1)
-            fbdata%cextunit(je) = pext%cdunit(je,1)
-         END DO
-         fbdata%caddlong(1,1) = 'Model interpolated SSH - MDT'
-         fbdata%caddunit(1,1) = 'Metres' 
-         fbdata%caddname(2)   = 'SSH'
-         fbdata%caddlong(2,1) = 'Model Sea surface height'
-         fbdata%caddunit(2,1) = 'Metres'
-         fbdata%cgrid(1)      = 'T'
-         DO ja = 1, iadd
-            fbdata%caddname(2+ja) = padd%cdname(ja)
-            fbdata%caddlong(2+ja,1) = padd%cdlong(ja,1)
-            fbdata%caddunit(2+ja,1) = padd%cdunit(ja,1)
-         END DO
-
-      CASE('SST')
-
-         CALL alloc_obfbdata( fbdata, 1, surfdata%nsurf, 1, &
+      CALL alloc_obfbdata( fbdata, surfdata%nvar, surfdata%nsurf, 1, &
             &                 1 + iadd, iext, .TRUE. )
-
-         clfiletype = 'sstfb'
-         fbdata%cname(1)      = surfdata%cvars(1)
-         fbdata%coblong(1)    = 'Sea surface temperature'
-         fbdata%cobunit(1)    = 'Degree centigrade'
-         DO je = 1, iext
-            fbdata%cextname(je) = pext%cdname(je)
-            fbdata%cextlong(je) = pext%cdlong(je,1)
-            fbdata%cextunit(je) = pext%cdunit(je,1)
-         END DO
-         fbdata%caddlong(1,1) = 'Model interpolated SST'
-         fbdata%caddunit(1,1) = 'Degree centigrade'
-         fbdata%cgrid(1)      = 'T'
-         DO ja = 1, iadd
-            fbdata%caddname(1+ja) = padd%cdname(ja)
-            fbdata%caddlong(1+ja,1) = padd%cdlong(ja,1)
-            fbdata%caddunit(1+ja,1) = padd%cdunit(ja,1)
-         END DO
-
-      CASE('ICECONC')
-
-         CALL alloc_obfbdata( fbdata, 1, surfdata%nsurf, 1, &
-            &                 1 + iadd, iext, .TRUE. )
-
-         clfiletype = 'sicfb'
-         fbdata%cname(1)      = surfdata%cvars(1)
-         fbdata%coblong(1)    = 'Sea ice'
-         fbdata%cobunit(1)    = 'Fraction'
-         DO je = 1, iext
-            fbdata%cextname(je) = pext%cdname(je)
-            fbdata%cextlong(je) = pext%cdlong(je,1)
-            fbdata%cextunit(je) = pext%cdunit(je,1)
-         END DO
-         fbdata%caddlong(1,1) = 'Model interpolated ICE'
-         fbdata%caddunit(1,1) = 'Fraction'
-         fbdata%cgrid(1)      = 'T'
-         DO ja = 1, iadd
-            fbdata%caddname(1+ja) = padd%cdname(ja)
-            fbdata%caddlong(1+ja,1) = padd%cdlong(ja,1)
-            fbdata%caddunit(1+ja,1) = padd%cdunit(ja,1)
-         END DO
-
-      CASE('SSS')
-
-         CALL alloc_obfbdata( fbdata, 1, surfdata%nsurf, 1, &
-            &                 1 + iadd, iext, .TRUE. )
-
-         clfiletype = 'sssfb'
-         fbdata%cname(1)      = surfdata%cvars(1)
-         fbdata%coblong(1)    = 'Sea surface salinity'
-         fbdata%cobunit(1)    = 'psu'
-         DO je = 1, iext
-            fbdata%cextname(je) = pext%cdname(je)
-            fbdata%cextlong(je) = pext%cdlong(je,1)
-            fbdata%cextunit(je) = pext%cdunit(je,1)
-         END DO
-         fbdata%caddlong(1,1) = 'Model interpolated SSS'
-         fbdata%caddunit(1,1) = 'psu'
-         fbdata%cgrid(1)      = 'T'
-         DO ja = 1, iadd
-            fbdata%caddname(1+ja) = padd%cdname(ja)
-            fbdata%caddlong(1+ja,1) = padd%cdlong(ja,1)
-            fbdata%caddunit(1+ja,1) = padd%cdunit(ja,1)
-         END DO
-
-      CASE DEFAULT
-
-         CALL ctl_stop( 'Unknown observation type '//TRIM(surfdata%cvars(1))//' in obs_wri_surf' )
-
-      END SELECT
-
       fbdata%caddname(1)   = 'Hx'
-
-      WRITE(clfname, FMT="(A,'_fdbk_',I4.4,'.nc')") TRIM(clfiletype), nproc
+      DO jvar = 1, surfdata%nvar
+         fbdata%cname(jvar)      = surfdata%cvars(jvar)
+         fbdata%coblong(jvar)    = surfdata%clong(jvar)
+         fbdata%cobunit(jvar)    = surfdata%cunit(jvar)
+         fbdata%cgrid(jvar)      = surfdata%cgrid(jvar)
+         fbdata%caddlong(1,jvar) = 'Model interpolated ' // TRIM(surfdata%clong(jvar))
+         fbdata%caddunit(1,jvar) = surfdata%cunit(jvar)
+         IF (iadd > 0) THEN
+            DO ja = 1, iadd
+               fbdata%caddname(1+ja) = padd%cdname(ja)
+               fbdata%caddlong(1+ja,jvar) = padd%cdlong(ja,jvar)
+               fbdata%caddunit(1+ja,jvar) = padd%cdunit(ja,jvar)
+            END DO
+         ENDIF
+         IF (iext > 0) THEN
+            DO je = 1, iext
+               fbdata%cextname(je) = pext%cdname(je)
+               fbdata%cextlong(je) = pext%cdlong(je,1)
+               fbdata%cextunit(je) = pext%cdunit(je,1)
+            END DO
+         ENDIF
+      END DO
+
+      WRITE(clfname, FMT="(A,'fb_fdbk_',I4.4,'.nc')") TRIM(clfiletype), nproc
 
       IF(lwp) THEN
          WRITE(numout,*)
-         WRITE(numout,*)'obs_wri_surf :'
-         WRITE(numout,*)'~~~~~~~~~~~~~'
-         WRITE(numout,*)'Writing '//TRIM(surfdata%cvars(1))//' feedback file : ',TRIM(clfname)
+         WRITE(numout,*) 'obs_wri_surf :'
+         WRITE(numout,*) '~~~~~~~~~~~~~'
+         WRITE(numout,*) 'Writing '//TRIM(surfdata%cvars(1))//' feedback file : ', TRIM(clfname)
       ENDIF
 
@@ -484,11 +398,13 @@
          fbdata%cdwmo(jo)     = surfdata%cwmo(jo)
          fbdata%kindex(jo)    = surfdata%nsfil(jo)
-         IF (ln_grid_global) THEN
-            fbdata%iobsi(jo,1) = surfdata%mi(jo)
-            fbdata%iobsj(jo,1) = surfdata%mj(jo)
-         ELSE
-            fbdata%iobsi(jo,1) = mig(surfdata%mi(jo))
-            fbdata%iobsj(jo,1) = mjg(surfdata%mj(jo))
-         ENDIF
+         DO jvar = 1, surfdata%nvar
+            IF (ln_grid_global) THEN
+               fbdata%iobsi(jo,jvar) = surfdata%mi(jo,jvar)
+               fbdata%iobsj(jo,jvar) = surfdata%mj(jo,jvar)
+            ELSE
+               fbdata%iobsi(jo,jvar) = mig(surfdata%mi(jo,jvar))
+               fbdata%iobsj(jo,jvar) = mjg(surfdata%mj(jo,jvar))
+            ENDIF
+         END DO
          CALL greg2jul( 0, &
             &           surfdata%nmin(jo), &
@@ -498,33 +414,37 @@
             &           surfdata%nyea(jo), &
             &           fbdata%ptim(jo),   &
-            &           krefdate = 19500101 )
-         fbdata%padd(1,jo,1,1) = surfdata%rmod(jo,1)
-         IF ( TRIM(surfdata%cvars(1)) == 'SLA' ) fbdata%padd(1,jo,2,1) = surfdata%rext(jo,1)
-         fbdata%pob(1,jo,1)    = surfdata%robs(jo,1) 
+            &           krefdate = 19500101 ) 
          fbdata%pdep(1,jo)     = 0.0
          fbdata%idqc(1,jo)     = 0
          fbdata%idqcf(:,1,jo)  = 0
-         IF ( surfdata%nqc(jo) > 255 ) THEN
-            fbdata%ivqc(jo,1)       = 4
-            fbdata%ivlqc(1,jo,1)    = 4
-            fbdata%ivlqcf(1,1,jo,1) = 0
+         DO jvar = 1, surfdata%nvar
+            fbdata%padd(1,jo,1,jvar) = surfdata%rmod(jo,jvar)
+            fbdata%pob(1,jo,jvar)    = surfdata%robs(jo,jvar)
+            IF ( surfdata%nqc(jo) > 255 ) THEN
+               fbdata%ivqc(jo,jvar)       = 4
+               fbdata%ivlqc(1,jo,jvar)    = 4
+               fbdata%ivlqcf(1,1,jo,jvar) = 0
 !$AGRIF_DO_NOT_TREAT
-            fbdata%ivlqcf(2,1,jo,1) = IAND(surfdata%nqc(jo),b'0000000011111111')
+               fbdata%ivlqcf(2,1,jo,jvar) = IAND(surfdata%nqc(jo),b'0000000011111111')
 !$AGRIF_END_DO_NOT_TREAT
-         ELSE
-            fbdata%ivqc(jo,1)       = surfdata%nqc(jo)
-            fbdata%ivlqc(1,jo,1)    = surfdata%nqc(jo)
-            fbdata%ivlqcf(:,1,jo,1) = 0
-         ENDIF
-         fbdata%iobsk(1,jo,1)  = 0
-         IF ( TRIM(surfdata%cvars(1)) == 'SLA' ) fbdata%pext(1,jo,1) = surfdata%rext(jo,2)
-         DO ja = 1, iadd
-            fbdata%padd(1,jo,2+ja,1) = &
-               & surfdata%rext(jo,padd%ipoint(ja))
+            ELSE
+               fbdata%ivqc(jo,jvar)       = surfdata%nqc(jo)
+               fbdata%ivlqc(1,jo,jvar)    = surfdata%nqc(jo)
+               fbdata%ivlqcf(:,1,jo,jvar) = 0
+            ENDIF
+            fbdata%iobsk(1,jo,jvar)  = 0
+            IF (iadd > 0) THEN
+               DO ja = 1, iadd
+                  fbdata%padd(1,jo,1+ja,jvar) = &
+                     & surfdata%radd(jo,padd%ipoint(ja),jvar)
+               END DO
+            ENDIF
          END DO
-         DO je = 1, iext
-            fbdata%pext(1,jo,1+je) = &
-               & surfdata%rext(jo,pext%ipoint(je))
-         END DO
+         IF (iext > 0) THEN
+            DO je = 1, iext
+               fbdata%pext(1,jo,je) = &
+                  & surfdata%rext(jo,pext%ipoint(je))
+            END DO
+         ENDIF
       END DO
 
@@ -574,7 +494,7 @@
 
       DO jvar = 1, fbdata%nvar
-         zsumx=0.0_wp
-         zsumx2=0.0_wp
-         inumgoodobs=0
+         zsumx = 0.0_wp
+         zsumx2 = 0.0_wp
+         inumgoodobs = 0
          DO jo = 1, fbdata%nobs
             DO jk = 1, fbdata%nlev
@@ -583,8 +503,8 @@
                   & ( fbdata%padd(jk,jo,1,jvar) < 9999.0 ) ) THEN
 
-                  zomb=fbdata%pob(jk, jo, jvar)-fbdata%padd(jk, jo, 1, jvar)
-                  zsumx=zsumx+zomb
-                  zsumx2=zsumx2+zomb**2
-                  inumgoodobs=inumgoodobs+1
+                  zomb = fbdata%pob(jk, jo, jvar)-fbdata%padd(jk, jo, 1, jvar)
+                  zsumx = zsumx + zomb
+                  zsumx2 = zsumx2 + zomb**2
+                  inumgoodobs = inumgoodobs + 1
                ENDIF
             ENDDO
@@ -596,7 +516,9 @@
 
          IF (lwp) THEN
-            WRITE(numout,*) 'Type: ',fbdata%cname(jvar),'  Total number of good observations: ',inumgoodobsmpp 
-            WRITE(numout,*) 'Overall mean obs minus model of the good observations: ',zsumx/inumgoodobsmpp
-            WRITE(numout,*) 'Overall RMS obs minus model of the good observations: ',sqrt( zsumx2/inumgoodobsmpp )
+            WRITE(numout,*) 'Type: ', fbdata%cname(jvar), '  Total number of good observations: ', inumgoodobsmpp
+            IF ( inumgoodobsmpp > 0 ) THEN
+               WRITE(numout,*) 'Overall mean obs minus model of the good observations: ', zsumx/inumgoodobsmpp
+               WRITE(numout,*) 'Overall RMS obs minus model of the good observations: ', sqrt( zsumx2/inumgoodobsmpp )
+            ENDIF
             WRITE(numout,*) ''
          ENDIF
Index: NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/TRA/tradmp.F90
===================================================================
--- NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/TRA/tradmp.F90	(revision 15731)
+++ NEMO/branches/UKMO/NEMO_4.0.4_FOAM_package/src/OCE/TRA/tradmp.F90	(revision 15799)
@@ -50,4 +50,6 @@
    !
    REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:,:) ::   resto    !: restoring coeff. on T and S (s-1)
+   REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:,:) ::   tclim    !: temperature climatology on each time step(Celcius)
+   REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:,:) ::   sclim    !: salinity climatology on each time step (psu)
 
    !! * Substitutions
@@ -64,5 +66,7 @@
       !!                ***  FUNCTION tra_dmp_alloc  ***
       !!----------------------------------------------------------------------
-      ALLOCATE( resto(jpi,jpj,jpk), STAT= tra_dmp_alloc )
+      ALLOCATE( resto(jpi,jpj,jpk), &
+         &      tclim(jpi,jpj,jpk), &
+         &      sclim(jpi,jpj,jpk), STAT= tra_dmp_alloc )
       !
       CALL mpp_sum ( 'tradmp', tra_dmp_alloc )
@@ -106,4 +110,7 @@
       CALL dta_tsd( kt, zts_dta )            ! read and interpolates T-S data at kt
       !
+      tclim(:,:,:) = zts_dta(:,:,:,jp_tem)
+      sclim(:,:,:) = zts_dta(:,:,:,jp_sal)
+      !
       SELECT CASE ( nn_zdmp )     !==  type of damping  ==!
       !
