Repository: NOAA-EMC/GSI
Pull request #844: Adding Metop-SG-a1 Microwave Sounder (MWS) in GSI
Author: login: jianjunj
Labels: name: enhancement
description: New feature or request
Created: 2025-03-18T16:06:45Z | Merged: 2025-05-06T18:08:31Z

Set the procedure to assimilate future Metop-SG-a1 MWS radiance data. The Metop-SG-a1 satellite will be launched in fall 2025. MWS is similar to the ATMS instrument except that there are 24 channels in its radiance data. Therefore, all those observation processings such as reading, data selection, and quality control of MWS are mimics of those for ATMS. The significant changes include a new reader "read_mws.f90", and new subroutine "mws_spatial_average_mod.f90" to conduct spatial average.   A new "mws_beamwidth.txt" is required to  conduct spatial average and is added in GSI-fix.  An issue is in https://github.com/NOAA-EMC/GDASApp/issues/1455

<!-- List any dependencies that are required for this change. -->
It depends on a branch:
https://github.com/jianjunj/GSI-fix/tree/feature/initial_metop-sg-a1_mws

**Type of change**

Please delete options that are not relevant.

- [X] New feature (non-breaking change which adds functionality)

**How Has This Been Tested?**
I tested these update with proxy MWS data on Orion:
/work2/noaa/da/jianjun/obs_data/gdas.20240219/00/atmos//gdas.t00z.mws.tm00.bufr_d
Test results are in /work2/noaa/da/jianjun/ufoeval/GSIobserver_new/hercules/2024021900
Note, MWS are assimilated passively without thinning or bias correction in my test. A diagnost file is saved as 
/work2/noaa/da/jianjun/ufoeval/GSIobserver_new/hercules/2024021900/diags/diag_mws_metop-sg-a1_ges.2024021900.nc4

**Provide instructions so we can reproduce**
1) The proxy BUFR data need to be copied over.  The date is 9/12/2007. However, any date before 01/01/2025 is ignored by the new mws reader.
2) Need CRTM coefficient data for MWS observations:
  /work2/noaa/da/jianjun/crtm/crtm.coefficients/mws_metop-sg-a1.TauCoeff.bin 
  /work2/noaa/da/jianjun/crtm/crtm.coefficients/mws_metop-sg-a1.SpcCoeff.bin
3) Need bias correction coefficients in 
/work2/noaa/da/jianjun/restarts/gdas.20240218/18/analysis/atmos/gdas.t18z.abias
/work2/noaa/da/jianjun/restarts/gdas.20240218/18/analysis/atmos/gdas.t18z.abias_pc 
4) Need checkout the branch https://github.com/jianjunj/GSI-fix/tree/feature/initial_metop-sg-a1_mws. to have updated
"cloudy_radiance_info.txt", "global_scaninfo.txt", and "global_satinfo.txt", and a new file "mws_beamwidth.txt".

**Please also list any relevant details for your test configuration**
A test was conducted to run GSI only in /work2/noaa/da/jianjun/git/GSI_forked/ush/run_observer/ on Orion.  Specific changes can be seen by:
xxdiff /work2/noaa/da/jianjun/git/GSI_forked/ush/run_observer/gsi_observer.sh.0  /work2/noaa/da/jianjun/git/GSI_forked/ush/run_observer/gsi_observer.sh

**Checklist**

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my own code
- [x] I have commented my code, particularly in hard-to-understand areas
- [x] New and existing tests pass with my changes
- [ ] Any dependent changes have been merged and published

All ctests passed without any proxy MWS data:
ctest1.log:1/1 Test#1: global_4denvar ...................   Passed  3934.27 sec
ctest2.log:1/1 Test#2: rtma .............................   Passed  2768.58 sec
ctest3.log:1/1 Test#3: rrfs_3denvar_rdasens .............   Passed  1391.24 sec
ctest4.log:1/1 Test#4: hafs_4denvar_glbens ..............   Passed  3446.39 sec
ctest5.log:1/1 Test#5: hafs_3denvar_hybens ..............   Passed  3389.92 sec
ctest6.log:1/1 Test#6: global_enkf ......................   Passed  1932.70 sec



Diff:
diff --git a/fix b/fix
index e042f8bf8..4b6c86fb8 160000
--- a/fix
+++ b/fix
@@ -1 +1 @@
-Subproject commit e042f8bf80c6b3341ece8b92c098ab8c63dd2267
+Subproject commit 4b6c86fb84ae0629cfa409368d92ed444ed12195
diff --git a/regression/global_4denvar.sh b/regression/global_4denvar.sh
index 945200eb6..bbbc20f15 100755
--- a/regression/global_4denvar.sh
+++ b/regression/global_4denvar.sh
@@ -127,6 +127,7 @@ insituinfo=$fixgsi/global_insituinfo.txt
 errtable=$fixgsi/prepobs_errtable.global
 aeroinfo=$fixgsi/global_aeroinfo.txt
 atmsbeaminfo=$fixgsi/atms_beamwidth.txt
+mwsbeaminfo=$fixgsi/mws_beamwidth.txt
 cloudyinfo=$fixgsi/cloudy_radiance_info.txt
 cris_clddet=$fixgsi/CRIS_CLDDET.NL
 iasi_clddet=$fixgsi/IASI_CLDDET.NL
@@ -170,6 +171,7 @@ $ncp $insituinfo ./insituinfo
 $ncp $errtable ./errtable
 $ncp $aeroinfo ./aeroinfo
 $ncp $atmsbeaminfo ./atms_beamwidth.txt
+$ncp $mwsbeaminfo ./mws_beamwidth.txt
 $ncp $cloudyinfo   ./cloudy_radiance_info.txt
 $ncp $cris_clddet ./CRIS_CLDDET.NL
 $ncp $iasi_clddet ./IASI_CLDDET.NL
@@ -264,6 +266,7 @@ $nln $datobs/${prefix_obs}.amubdb.${suffix}        ./amsubbufr_db
 $nln $datobs/${prefix_obs}.atms.${suffix}          ./atmsbufr
 $nln $datobs/${prefix_obs}.atmsdb.${suffix}        ./atmsbufr_db
 $nln $datobs/${prefix_obs}.esatms.${suffix}        ./atmsbufrears
+$nln $datobs/${prefix_obs}.mws.${suffix}           ./mwsbufr
 
 # Do not process
 ## $nln $datobs/${prefix_obs}.amsre.${suffix}      ./amsrebufr
diff --git a/regression/regression_namelists.sh b/regression/regression_namelists.sh
index 561a91b3e..455ea81aa 100755
--- a/regression/regression_namelists.sh
+++ b/regression/regression_namelists.sh
@@ -188,6 +188,7 @@ OBS_INPUT::
    ompsnpbufr     ompsnp      n21         ompsnp_n21          0.0     0     0
    ompstcbufr     ompstc8     n21         ompstc8_n21         0.0     2     0
    gomebufr       gome        metop-c     gome_metop-c        0.0     2     0
+   mwsbufr        mws         metop-sg-a1 mws_metop-sg-a1     0.0     1     0
 ::
   &SUPEROB_RADAR
    $SUPERRAD   
@@ -472,6 +473,7 @@ OBS_INPUT::
    larcInGSI      larccld     null      larccld              1.0     0     0
    abibufr        abi         g18       abi_g18              0.0     2     0
    abibufr        abi         g19       abi_g19              0.0     2     0
+   mwsbufr        mws         metop-sg-a1 mws_metop-sg-a1    0.0     1     0
 ::
  &SUPEROB_RADAR
    del_azimuth=5.,del_elev=.25,del_range=5000.,del_time=.5,elev_angle_max=5.,minnum=50,range_max=100000., l2superob_only=.false.,
@@ -1063,6 +1065,7 @@ export gsi_namelist="
    sattypes_rad(78)= 'atms_n21',      dsis(78)= 'atms_n21',
    sattypes_rad(79)= 'cris-fsr_n21',  dsis(79)= 'cris-fsr_n21',
    sattypes_rad(80)= 'abi_g19',       dsis(80)= 'abi_g19',
+   sattypes_rad(81)= 'mws_metop-sg-a1', dsis(81)= 'mws_metop-sg-a1',
   $SATOBS_ENKF
  /
  &ozobs_enkf
diff --git a/regression/regression_namelists_db.sh b/regression/regression_namelists_db.sh
index 2563f86b3..f5e2765f1 100755
--- a/regression/regression_namelists_db.sh
+++ b/regression/regression_namelists_db.sh
@@ -169,6 +169,7 @@ OBS_INPUT::
    mhsbufr        mhs         metop-c     mhs_metop-c         0.0     1     1
    iasibufr       iasi        metop-c     iasi_metop-c        0.0     1     1
    ompslpbufr     ompslp      npp         ompslp_npp          0.0     1     1
+   mwsbufr        mws         metop-sg-a1 mws_metop-sg-a1     0.0     1     0
 ::
   &SUPEROB_RADAR
    $SUPERRAD
diff --git a/regression/rrfs_3denvar_rdasens.sh b/regression/rrfs_3denvar_rdasens.sh
index b00047ec6..c153643c9 100755
--- a/regression/rrfs_3denvar_rdasens.sh
+++ b/regression/rrfs_3denvar_rdasens.sh
@@ -260,6 +260,10 @@ sed -i "s/hh/${HH}/"     coupler.res
   obs_files_source[${obs_number}]=${obspath_tmp}/${obsfileprefix}.t${HH}z.sevcsr.tm00.bufr_d
   obs_files_target[${obs_number}]=sevcsr
 
+  obs_number=${#obs_files_source[@]}
+  obs_files_source[${obs_number}]=${obspath_tmp}/${obsfileprefix}.t${HH}z.mws.tm00.bufr_d
+  obs_files_target[${obs_number}]=mwsbufr
+
 obs_number=${#obs_files_source[@]}
 for (( i=0; i<${obs_number}; i++ ));
 do
@@ -289,6 +293,7 @@ SATINFO=${fixgsi}/global_satinfo.txt
 OZINFO=${fixgsi}/global_ozinfo.txt
 PCPINFO=${fixgsi}/global_pcpinfo.txt
 ATMS_BEAMWIDTH=${fixgsi}/atms_beamwidth.txt
+MWS_BEAMWIDTH=${fixgsi}/mws_beamwidth.txt
 
 # Fixed fields
 cp ${ANAVINFO} anavinfo
@@ -299,6 +304,7 @@ cp $OZINFO     ozinfo
 cp $PCPINFO    pcpinfo
 cp $OBERROR    errtable
 cp $ATMS_BEAMWIDTH atms_beamwidth.txt
+cp $MWS_BEAMWIDTH mws_beamwidth.txt
 cp ${HYBENSINFO} hybens_info
 
 cp ${obspath_tmp}/gsd_sfcobs_provider.txt gsd_sfcobs_provider.txt
diff --git a/src/enkf/readozobs.f90 b/src/enkf/readozobs.f90
index efebb0085..8bf968697 100644
--- a/src/enkf/readozobs.f90
+++ b/src/enkf/readozobs.f90
@@ -64,7 +64,7 @@ subroutine get_num_ozobs_bin(obspath,datestring,num_obs_tot,num_obs_totdiag,id)
     integer(i_kind) :: nlevsoz  ! number of levels (layer amounts + total column) per obs   
     character(20) :: isis     ! sensor/instrument/satellite id
     character(10) :: obstype  !  type of ozone obs
-    character(10) :: dplat    ! sat sensor
+    character(len=11) :: dplat    ! sat sensor
     real(r_single), allocatable, dimension(:) :: err,grs,pob
     real(r_single),allocatable,dimension(:,:)::diagbuf
     real(r_single),allocatable,dimension(:,:,:)::rdiagbuf
@@ -304,7 +304,7 @@ subroutine get_ozobs_data_bin(obspath, datestring, nobs_max, nobs_maxdiag, hx_me
   integer(i_kind) :: nlevsoz  ! number of levels (layer amounts + total column) per obs   
   character(20) :: isis,isis2        ! sensor/instrument/satellite id
   character(10) :: obstype,obstype2  !  type of ozone obs
-  character(10) :: dplat,dplat2      ! sat sensor
+  character(len=11) :: dplat,dplat2      ! sat sensor
   integer(i_kind) nob, nobdiag, n, ios, nsat, k
   integer(i_kind) iunit,jiter,ii,ireal,iint,irdim1,idate,ioff0
   integer(i_kind) iunit2,jiter2,ii2,ireal2,iint2,irdim12,idate2,ioff02,nlevsoz2
@@ -831,7 +831,7 @@ subroutine write_ozobs_data_bin(obspath, datestring, nobs_max, nobs_maxdiag, x_f
   integer(i_kind) :: nlevsoz  ! number of levels (layer amounts + total column) per obs
   character(20) :: isis     ! sensor/instrument/satellite id
   character(10) :: obstype  !  type of ozone obs
-  character(10) :: dplat    ! sat sensor
+  character(len=11) :: dplat    ! sat sensor
   integer(i_kind) iunit,jiter,ii,ireal,iint,irdim1,idate,nob,nobdiag,n,ios,nsat,k,ipe,ioff0
   integer(i_kind) iunit2
 
diff --git a/src/enkf/readsatobs.f90 b/src/enkf/readsatobs.f90
index df0534fc9..7440b21f4 100644
--- a/src/enkf/readsatobs.f90
+++ b/src/enkf/readsatobs.f90
@@ -1061,7 +1061,7 @@ subroutine write_satobs_data(obspath, datestring, nobs_max, nobs_maxdiag, x_fit,
   integer(i_kind),   intent(in) :: nobs_max, nobs_maxdiag
   real(r_single),  dimension(nobs_max),     intent(in) :: x_fit, x_sprd
   integer(i_kind), dimension(nobs_maxdiag), intent(in) :: x_used
-  character(len=10), intent(in) :: id, id2, gesid2
+  character(len=*), intent(in) :: id, id2, gesid2
 
 
   if (netcdf_diag) then
@@ -1083,7 +1083,7 @@ subroutine write_satobs_data_bin(obspath, datestring, nobs_max, nobs_maxdiag, x_
   integer(i_kind),   intent(in) :: nobs_max, nobs_maxdiag
   real(r_single),  dimension(nobs_max),     intent(in) :: x_fit, x_sprd
   integer(i_kind), dimension(nobs_maxdiag), intent(in) :: x_used
-  character(len=10), intent(in) :: id, id2, gesid2
+  character(len=*), intent(in) :: id, id2, gesid2
 
   character*500 obsfile,obsfile2
   character(len=4) pe_name
@@ -1093,7 +1093,8 @@ subroutine write_satobs_data_bin(obspath, datestring, nobs_max, nobs_maxdiag, x_
   integer(i_kind) iunit,iunit2,iflag,nobs, nobsdiag,n,nsat,ipe,i,jpchstart
   logical fexist,init_pass
 
-  character(len=10):: satid,sentype
+  character(len=10):: sentype
+  character(len=11):: satid
   character(len=20):: sensat
 
   integer(i_kind):: jiter,nchanl,npred,ianldate,ireal,ipchan,iextra,jextra
@@ -1272,7 +1273,7 @@ subroutine write_satobs_data_nc(obspath, datestring, nobs_max, nobs_maxdiag, &
   integer(i_kind),   intent(in) :: nobs_max, nobs_maxdiag
   real(r_single),  dimension(nobs_max),     intent(in) :: x_fit, x_sprd
   integer(i_kind), dimension(nobs_maxdiag), intent(in) :: x_used
-  character(len=10), intent(in) :: id, gesid
+  character(len=*), intent(in) :: id, gesid
 
   character*500 obsfile, obsfile2
   character(len=4) pe_name
diff --git a/src/gsi/atms_spatial_average_mod.f90 b/src/gsi/atms_spatial_average_mod.f90
index 639bb8c99..e691098b2 100644
--- a/src/gsi/atms_spatial_average_mod.f90
+++ b/src/gsi/atms_spatial_average_mod.f90
@@ -16,6 +16,7 @@ Module ATMS_Spatial_Average_Mod
   use kinds, only: r_kind,r_double,i_kind
 
   implicit none     
+  public :: MODIFY_BEAMWIDTH_atms
 
 
 ! Declare module level parameters
@@ -37,6 +38,8 @@ SUBROUTINE ATMS_Spatial_Average(Num_Obs, NChanl, FOV, Time, BT_InOut, &
     integer(i_kind) ,intent(  out) :: Error_Status
 
     ! Declare local parameters
+    INTEGER(I_KIND), PARAMETER :: nxmax_atms=128  !Max number of spots per scan line
+    INTEGER(I_KIND), PARAMETER :: nymax_atms=8192 !Max number of lines. Allows 6hrs of ATMS.
     integer(i_kind), parameter :: atms1c_h_wmosatid=224
     integer(i_kind), parameter :: lninfile=15
     integer(i_kind), parameter :: max_fov=96
@@ -168,7 +171,7 @@ SUBROUTINE ATMS_Spatial_Average(Num_Obs, NChanl, FOV, Time, BT_InOut, &
        ! (otherwise bt_inout just keeps the same value):
        do i=1,nchannels
           if (channelnumber(i) == ichan) then
-             CALL MODIFY_BEAMWIDTH ( max_fov, max_scan, bt_image(:,:,ichan), &
+             CALL MODIFY_BEAMWIDTH_atms ( nxmax_atms, nymax_atms, max_fov, max_scan, bt_image(:,:,ichan), &
                   sampling_dist, beamwidth(i), newwidth(i), &
                   cutoff(i), nxaverage(i), nyaverage(i), &
                   qc_dist(i), MinBT(Ichan), MaxBT(IChan), IOS)
@@ -201,7 +204,7 @@ END Subroutine ATMS_Spatial_Average
 
 
 
-SUBROUTINE MODIFY_BEAMWIDTH ( nx, ny, image, sampling_dist,& 
+SUBROUTINE MODIFY_BEAMWIDTH_atms (nxmax, nymax, nx, ny, image, sampling_dist,& 
      beamwidth, newwidth, mtfcutoff, nxaverage, nyaverage, qc_dist, &
      Minval, MaxVal, Error)
      
@@ -247,11 +250,9 @@ SUBROUTINE MODIFY_BEAMWIDTH ( nx, ny, image, sampling_dist,&
 
 
       IMPLICIT NONE
-! Parameters
-      INTEGER(I_KIND), PARAMETER :: nxmax=128  !Max number of spots per scan line
-      INTEGER(I_KIND), PARAMETER :: nymax=8192 !Max number of lines. Allows 6hrs of ATMS.
-
 ! Arguments
+      INTEGER(I_KIND), INTENT(IN)  :: nxmax  !Max number of spots per scan line
+      INTEGER(I_KIND), INTENT(IN)  :: nymax  !Max number of lines. Allows 6hrs of ATMS or MWS
       INTEGER(I_KIND), INTENT(IN)  :: nx, ny         !Size of image
       REAL(R_KIND), INTENT(INOUT)  :: image(nx,ny)   !BT or radiance image
       REAL(R_KIND), INTENT(IN)     :: sampling_dist  !typically degrees
@@ -512,7 +513,7 @@ SUBROUTINE MODIFY_BEAMWIDTH ( nx, ny, image, sampling_dist,&
      DEALLOCATE(gooddata_map)
 
      RETURN
-   END SUBROUTINE MODIFY_BEAMWIDTH
+   END SUBROUTINE MODIFY_BEAMWIDTH_atms
 
 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 !
diff --git a/src/gsi/clw_mod.f90 b/src/gsi/clw_mod.f90
index 9d16ad64e..78f07e898 100644
--- a/src/gsi/clw_mod.f90
+++ b/src/gsi/clw_mod.f90
@@ -44,7 +44,7 @@ module clw_mod
 
 
  subroutine calc_clw(nadir,tb_obs,tsim,ich,nchanl,no85GHz,amsua,ssmi,ssmis,amsre,atms, &   
-          amsr2,gmi,saphir,tsavg5,sfc_speed,zasat,clw,tpwc,gwp,kraintype,ierrret)
+          mws,amsr2,gmi,saphir,tsavg5,sfc_speed,zasat,clw,tpwc,gwp,kraintype,ierrret)
 !$$$  subprogram documentation block
 !                .      .    .                                       .
 ! subprogram:   calc_clw    estimates cloud liquid water for micro. QC
@@ -81,6 +81,7 @@ subroutine calc_clw(nadir,tb_obs,tsim,ich,nchanl,no85GHz,amsua,ssmi,ssmis,amsre,
 !     ssmis     - flag for ssmis data
 !     amsre     - flag for amsre data
 !     atms      - flag for atms data
+!     mws       - flag for mws data
 !     amsr2     - flag for amsr2 data
 !     gmi       - flag for gmi data
 !     saphir    - flag for saphir data
@@ -108,6 +109,7 @@ subroutine calc_clw(nadir,tb_obs,tsim,ich,nchanl,no85GHz,amsua,ssmi,ssmis,amsre,
   real(r_kind),dimension(nchanl)    ,intent(in   ) :: tb_obs,tsim
   integer(i_kind),dimension(nchanl) ,intent(in   ) :: ich
   logical                           ,intent(in   ) :: no85GHz,amsre,ssmi,ssmis,amsua,atms,amsr2,gmi,saphir
+  logical                           ,intent(in   ) :: mws
   real(r_kind)                      ,intent(in   ) :: tsavg5,sfc_speed,zasat
   real(r_kind)                      ,intent(  out) :: clw,tpwc,gwp
   integer(i_kind)                   ,intent(  out) :: kraintype,ierrret
@@ -121,8 +123,13 @@ subroutine calc_clw(nadir,tb_obs,tsim,ich,nchanl,no85GHz,amsua,ssmi,ssmis,amsre,
 ! Declare local variables
   real(r_kind) tbcx1,tbcx2
 
+  clw = zero
+  tpwc = zero
+  gwp = zero
+  kraintype = 0
+  ierrret = 0
 
-  if (amsua .or. atms) then
+  if (amsua .or. atms .or. mws) then
 
      clw = zero
     ! We want to reject sea ice points that may be frozen.  The sea freezes
@@ -1986,12 +1993,17 @@ subroutine ret_amsua(tb_obs,nchanl,tsavg5,zasat,clwp_amsua,ierrret,scat)
      else if (nchanl == 22) then
 !       ATMS
         tb890 = tb_obs(16)
+     else if (nchanl == 24) then
+!       MWS (Metop-SG)
+        tb890 = tb_obs(17)
      endif
      if (tb890 > zero) then
         scat=-113.2_r_kind+(2.41_r_kind-0.0049_r_kind*tb_obs(1))*tb_obs(1)  &
              +0.454_r_kind*tb_obs(2)-tb890
+        scat=max(zero,scat)
+     else
+        scat=zero
      endif
-     scat=max(zero,scat)
   end if
 
 end subroutine ret_amsua
diff --git a/src/gsi/gsi_files.cmake b/src/gsi/gsi_files.cmake
index 5c5c4ec5a..efb498d88 100644
--- a/src/gsi/gsi_files.cmake
+++ b/src/gsi/gsi_files.cmake
@@ -409,6 +409,7 @@ mpimod.F90
 mpl_allreduce.F90
 mpl_bcast.f90
 mrmsmod.f90
+mws_spatial_average_mod.f90
 native_endianness.f90
 ncepgfs_ghg.f90
 ncepgfs_io.f90
@@ -504,6 +505,7 @@ read_lag.f90
 read_lidar.f90
 read_mitm_mxtm.f90
 read_modsbufr.f90
+read_mws.f90
 read_nasa_larc.f90
 read_nsstbufr.f90
 read_obs.F90
diff --git a/src/gsi/gsi_obOperTypeManager.F90 b/src/gsi/gsi_obOperTypeManager.F90
index 36d2ce0bc..dc1519707 100644
--- a/src/gsi/gsi_obOperTypeManager.F90
+++ b/src/gsi/gsi_obOperTypeManager.F90
@@ -301,7 +301,7 @@ function dtype2index_(dtype) result(index_)
     case("ompslp"   ); index_= iobOper_o3l
     case("ompslpuv" ); index_= iobOper_o3l
     case("ompslpvis"); index_= iobOper_o3l
-    case("ompslpnc" ); index_= iobOper_o3l     
+    case("ompslpnc" ); index_= iobOper_o3l
 
   case("gpsbend","[gpsbendoper]"); index_= iobOper_gpsbend
     case("gps_bnd"); index_= iobOper_gpsbend
@@ -362,6 +362,7 @@ function dtype2index_(dtype) result(index_)
     case("avhrr"  ); index_= iobOper_rad
     case("metimage" ); index_= iobOper_rad
     case("viirs-m"  ); index_= iobOper_rad
+    case("mws"  ); index_= iobOper_rad
 
   case("tcp"    ,"[tcpoper]"    ); index_= iobOper_tcp
 
diff --git a/src/gsi/mws_spatial_average_mod.f90 b/src/gsi/mws_spatial_average_mod.f90
new file mode 100644
index 000000000..2618e61f6
--- /dev/null
+++ b/src/gsi/mws_spatial_average_mod.f90
@@ -0,0 +1,205 @@
+Module mws_spatial_average_mod
+!
+!
+! abstract:  This routine reads BUFR format MWS radiance 
+!            (brightness temperature) files, spaatially 
+!            averages the data using the AAPP averaging routines
+!            and writes the data back into BUFR format
+!
+!
+!
+! Program history log:
+!    2025-01-01   j.jin   - Modified from ATMS_Spatial_Average_Mod
+! 
+
+  use kinds, only: r_kind,r_double,i_kind
+  use ATMS_Spatial_Average_Mod, only: MODIFY_BEAMWIDTH_atms
+  implicit none     
+
+
+! Declare module level parameters
+  real(r_double), parameter    :: Missing_Value=1.e11_r_double
+
+CONTAINS 
+
+  SUBROUTINE mws_spatial_average(Num_Obs, NChanl, FOV, Time, BT_InOut, &
+       Scanline, Error_Status)
+
+    IMPLICIT NONE
+    
+    ! Declare passed variables
+    integer(i_kind) ,intent(in   ) :: Num_Obs, NChanl
+    integer(i_kind) ,intent(in   ) :: Fov(num_obs)
+    real(r_kind)    ,intent(in   ) :: Time(Num_Obs)
+    real(r_kind)    ,intent(inout) :: BT_InOut(NChanl,Num_Obs)
+    integer(i_kind) ,intent(  out) :: Scanline(Num_Obs)
+    integer(i_kind) ,intent(  out) :: Error_Status
+
+    ! Declare local parameters
+    INTEGER(I_KIND), PARAMETER :: nxmax_mws=128  !Max number of spots per scan line
+    INTEGER(I_KIND), PARAMETER :: nymax_mws=9600 !Max number of lines. Allows 6hrs of MWS.
+                                                 !MWS conducts a scan every 2.254 second.
+    integer(i_kind), parameter :: mws1c_h_wmosatid=24
+    integer(i_kind), parameter :: lninfile=15
+    integer(i_kind), parameter :: max_fov=95
+    real(r_kind), parameter    :: Scan_Interval = 2.254_r_kind ! second
+    ! Maximum number of channels 
+    integer(i_kind), parameter :: MaxChans = 24
+    ! Minimum allowed BT as a function of channel number
+    real(r_kind), parameter :: MinBT(MaxChans) = &
+         (/ 120.0_r_kind, 120.0_r_kind, 190.0_r_kind, 200.0_r_kind, &
+            200.0_r_kind, 200.0_r_kind, 200.0_r_kind, 200.0_r_kind, &
+            190.0_r_kind, 190.0_r_kind, 180.0_r_kind, 180.0_r_kind, &
+            180.0_r_kind, 190.0_r_kind, 200.0_r_kind, 200.0_r_kind, &
+            120.0_r_kind, 120.0_r_kind, 120.0_r_kind, 150.0_r_kind, &
+            170.0_r_kind, 180.0_r_kind, 190.0_r_kind, 190.0_r_kind /)
+    ! Maximum allowed BT as a function of channel number
+    real(r_kind), parameter :: MaxBT(MaxChans) = &
+         (/ 320.0_r_kind, 320.0_r_kind, 300.0_r_kind, 300.0_r_kind, &
+            300.0_r_kind, 270.0_r_kind, 270.0_r_kind, 250.0_r_kind, &
+            240.0_r_kind, 240.0_r_kind, 250.0_r_kind, 250.0_r_kind, &
+            270.0_r_kind, 280.0_r_kind, 290.0_r_kind, 300.0_r_kind, &
+            320.0_r_kind, 320.0_r_kind, 300.0_r_kind, 300.0_r_kind, &
+            300.0_r_kind, 300.0_r_kind, 300.0_r_kind, 300.0_r_kind /)
+    
+
+    ! Declare local variables
+    character(30) :: Cline
+
+    integer(i_kind) :: i, iscan, ifov, ichan, nchannels, wmosatid, version
+    integer(i_kind) :: ios, max_scan, mintime
+    integer(i_kind) :: nxaverage(nchanl), nyaverage(nchanl)
+    integer(i_Kind) :: channelnumber(nchanl),qc_dist(nchanl)
+    integer(i_kind), ALLOCATABLE ::  scanline_back(:,:)
+
+    real(r_kind) :: sampling_dist, beamwidth(nchanl) 
+    real(r_kind) :: newwidth(nchanl), cutoff(nchanl),err(nchanl)
+    real(r_kind), allocatable, target :: bt_image(:,:,:)
+
+    Error_Status=0
+
+    IF (NChanl > MaxChans) THEN
+       WRITE(0,*) 'Unexpected number of MWS channels: ',nchanl
+       Error_Status = 1
+       RETURN
+    END IF
+
+    ! Read the beamwidth requirements
+    OPEN(lninfile,file='mws_beamwidth.txt',form='formatted',status='old', &
+         iostat=ios)
+    IF (ios /= 0) THEN
+       WRITE(*,*) 'Unable to open mws_beamwidth.txt'
+       Error_Status=1
+       RETURN
+    ENDIF
+    wmosatid=999
+    read(lninfile,'(a30)',iostat=ios) Cline
+    DO WHILE (wmosatid /= mws1c_h_wmosatid .AND. ios == 0)
+       DO WHILE (Cline(1:1) == '#')
+          read(lninfile,'(a30)') Cline
+       ENDDO
+       READ(Cline,*) wmosatid
+       
+       read(lninfile,'(a30)') Cline
+       DO WHILE (Cline(1:1) == '#')
+          read(lninfile,'(a30)') Cline
+       ENDDO
+       READ(Cline,*) version
+       
+       read(lninfile,'(a30)') Cline
+       DO WHILE (Cline(1:1) == '#')
+          read(lninfile,'(a30)') Cline
+       ENDDO
+       READ(Cline,*) sampling_dist
+       
+       read(lninfile,'(a30)') Cline
+       DO WHILE (Cline(1:1) == '#')
+          read(lninfile,'(a30)') Cline
+       ENDDO
+       READ(Cline,*) nchannels
+      
+       read(lninfile,'(a30)') Cline
+       if (nchannels > 0) then 
+          DO ichan=1,nchannels
+             read(lninfile,'(a30)') Cline
+             DO WHILE (Cline(1:1) == '#')
+                read(lninfile,'(a30)') Cline
+             ENDDO
+             READ(Cline,*) channelnumber(ichan),beamwidth(ichan), &
+                  newwidth(ichan),cutoff(ichan),nxaverage(ichan), &
+                  nyaverage(ichan), qc_dist(ichan)
+          ENDDO
+       end if
+       read(lninfile,'(a30)',iostat=ios) Cline
+    ENDDO
+    IF (wmosatid /= mws1c_h_wmosatid) THEN
+       WRITE(*,*) 'MWS_Spatial_Averaging: sat id not matched in mws_beamwidth.dat'
+       Error_Status=1
+       RETURN
+    ENDIF
+    CLOSE(lninfile)
+  
+
+    ! Determine scanline from time
+    MinTime = MINVAL(Time)
+    Scanline(:)   = NINT((Time(1:Num_Obs)-MinTime)/Scan_Interval)+1
+    Max_Scan=MAXVAL(Scanline)
+    
+    ALLOCATE(BT_Image(Max_FOV,Max_Scan,nchanl))
+    ALLOCATE(Scanline_Back(Max_FOV,Max_Scan))
+    BT_Image(:,:,:) = 1000.0_r_kind
+    
+    ScanLine_Back(:,:) = -1
+    DO I=1,Num_Obs
+       bt_image(FOV(I),Scanline(I),:)=bt_inout(:,I)
+       Scanline_Back(FOV(I),Scanline(I))=I
+    END DO
+
+!$omp parallel do schedule(dynamic,1) private(i,ichan,iscan,ios,ifov)
+    DO IChan=1,nchanl
+    
+       err(ichan)=0
+   
+       ! Set all scan positions to missing in a scanline if one is missing
+       do iscan=1,max_scan
+          if (ANY(bt_image(:,iscan,ichan) > 500.0_r_kind)) &
+             bt_image(:,iscan,ichan)=1000.0_r_kind
+       enddo
+
+       ! If the channel number is present in the channelnumber array we should process it 
+       ! (otherwise bt_inout just keeps the same value):
+       do i=1,nchannels
+          if (channelnumber(i) == ichan) then
+             CALL MODIFY_BEAMWIDTH_atms ( nxmax_mws,nymax_mws, max_fov, max_scan, bt_image(:,:,ichan), &
+                  sampling_dist, beamwidth(i), newwidth(i), &
+                  cutoff(i), nxaverage(i), nyaverage(i), &
+                  qc_dist(i), MinBT(Ichan), MaxBT(IChan), IOS)
+
+             IF (IOS == 0) THEN
+                do iscan=1,max_scan
+                   do ifov=1,max_fov
+                      IF (Scanline_Back(IFov, IScan) > 0) &
+                        bt_inout(ichan,Scanline_Back(IFov, IScan)) = &
+                        BT_Image(ifov,iscan,ichan)
+                   end do
+                end do
+             ELSE
+                err(ichan)=1
+             END IF
+          end if
+       end do
+    END DO
+
+    do ichan=1,nchanl
+      if(err(ichan) >= 1)then
+         error_status = 1
+         return
+      end if
+    end do
+
+    DEALLOCATE(BT_Image, Scanline_Back)
+    
+END Subroutine mws_spatial_average
+
+
+END MODULE mws_spatial_average_mod
diff --git a/src/gsi/obs_para.f90 b/src/gsi/obs_para.f90
index 869efa5e7..0bcb894c0 100644
--- a/src/gsi/obs_para.f90
+++ b/src/gsi/obs_para.f90
@@ -120,7 +120,7 @@ subroutine obs_para(ndata,mype)
         nsat1(is)= nobs_sub(mm1,is)
         if(mm1 == 1 .and. (print_verbose .or. print_obs_para))then
            write(6,1000)dtype(is),dplat(is),(nobs_sub(ii,is),ii=1,npe)
-1000       format('OBS_PARA: ',2A10,8I10,/,(10X,10I10))
+1000       format('OBS_PARA: ',A10,A11,8I10,/,(10X,10I10))
         end if
 
         ! Simple logic to organize which tasks do and do not have obs. 
diff --git a/src/gsi/qcmod.f90 b/src/gsi/qcmod.f90
index abd75108c..9edf6561c 100644
--- a/src/gsi/qcmod.f90
+++ b/src/gsi/qcmod.f90
@@ -3151,6 +3151,8 @@ subroutine qc_amsua(nchanl,is,ndat,nsig,npred,sea,land,ice,snow,mixed,luse,   &
   integer(i_kind) :: ich238, ich314, ich503, ich528, ich536 ! set chan indices
   integer(i_kind) :: ich544, ich549, ich890                 ! for amsua/atms
   logical         :: latms, latms_surfaceqc
+  logical         :: lmws = .false.
+  integer(i_kind) :: ich164, ich183a
 
 
   if (nchanl == 22) then
@@ -3163,6 +3165,20 @@ subroutine qc_amsua(nchanl,is,ndat,nsig,npred,sea,land,ice,snow,mixed,luse,   &
       ich544 =  7
       ich549 =  8
       ich890 = 16
+      ich164 = 17
+      ich183a= 22
+  else if (nchanl == 24) then
+      lmws   = .true.    ! If there are 24 channels passed along, it's mws
+      ich238 =  1
+      ich314 =  2
+      ich503 =  3
+      ich528 =  4
+      ich536 =  6
+      ich544 =  8
+      ich549 =  9
+      ich890 = 17
+      ich164 = 18
+      ich183a= 23
   else
       latms = .false.   ! If \= 16 channels (should be 15), it's amsua  
       ich238 =  1
@@ -3226,7 +3242,7 @@ subroutine qc_amsua(nchanl,is,ndat,nsig,npred,sea,land,ice,snow,mixed,luse,   &
 ! a) Mixed surfaces (to minimise and possible issues with re-mapping the FOVs)
 ! b) Snow and Ice (as the empirical model for these surfaces in CRTM is not 
 !                  available for ATMS).
-  latms_surfaceqc = (latms .AND. .NOT.(sea .OR. land))
+  latms_surfaceqc = ((latms .or. lmws) .AND. .NOT.(sea .OR. land))
 
 
 ! If window channels are missing, skip the following QC and do not
@@ -3244,10 +3260,10 @@ subroutine qc_amsua(nchanl,is,ndat,nsig,npred,sea,land,ice,snow,mixed,luse,   &
           varinv(ich890)=zero
           if(id_qc(ich890) == igood_qc) id_qc(ich890) = ifail_interchan_qc 
 
-          if (latms) then 
-             errf(16:22)=zero
-             varinv(16:22)=zero
-             do i=16,22
+          if (latms .or. lmws) then 
+             errf(ich890:ich183a)=zero
+             varinv(ich890:ich183a)=zero
+             do i=ich890,ich183a
                 if(id_qc(i) == igood_qc)id_qc(i) = ifail_interchan_qc
              end do
           end if  
@@ -3269,8 +3285,8 @@ subroutine qc_amsua(nchanl,is,ndat,nsig,npred,sea,land,ice,snow,mixed,luse,   &
               if(id_qc(ich890) == igood_qc)id_qc(ich890)=ifail_factch6_qc
               errf(ich890) = zero
               varinv(ich890) = zero
-              if (latms) then
-                 do i=17,22   !  AMSU-B/MHS like channels 
+              if (latms .or. lmws) then
+                 do i=ich164,ich183a   !  AMSU-B/MHS like channels 
                     if(id_qc(i) == igood_qc)id_qc(i)=ifail_factch6_qc
                     errf(i) = zero
                     varinv(i) = zero
@@ -3290,8 +3306,8 @@ subroutine qc_amsua(nchanl,is,ndat,nsig,npred,sea,land,ice,snow,mixed,luse,   &
               if(id_qc(ich890) == igood_qc)id_qc(ich890)=ifail_factch4_qc
               errf(ich890) = zero
               varinv(ich890) = zero
-              if (latms) then
-                 do i=17,22   !  AMSU-B/MHS like channels 
+              if (latms .or. lmws) then
+                 do i=ich164,ich183a   !  AMSU-B/MHS like channels 
                     if(id_qc(i) == igood_qc)id_qc(i)=ifail_factch4_qc
                     errf(i) = zero
                     varinv(i) = zero
@@ -3336,24 +3352,24 @@ subroutine qc_amsua(nchanl,is,ndat,nsig,npred,sea,land,ice,snow,mixed,luse,   &
                  if(id_qc(ich890) == igood_qc)id_qc(ich890)=ifail_factch5_qc
                  errf(ich890) = zero
                  varinv(ich890) = zero
-                 if (latms) then
-                    do i=17,22   !  AMSU-B/MHS like channels
+                 if (latms .or. lmws) then
+                    do i=ich164,ich183a   !  AMSU-B/MHS like channels
                        if(id_qc(i) == igood_qc)id_qc(i)=ifail_factch5_qc
                        errf(i) = zero
                        varinv(i) = zero
                     enddo
                  endif
-              else if (latms) then
-                 if (abs(cldeff_obs(16)-cldeff_obs(17))>10.0_r_kind) then
+              else if (latms .or. lmws) then
+                 if (abs(cldeff_obs(ich890)-cldeff_obs(ich164))>10.0_r_kind) then
                     if(id_qc(ich890) == igood_qc)id_qc(ich890)=ifail_factch1617_qc
                     errf(ich890) = zero
                     varinv(ich890) = zero
-                    do i=17,22   !  AMSU-B/MHS like channels
+                    do i=ich164,ich183a   !  AMSU-B/MHS like channels
                        if(id_qc(i) == igood_qc)id_qc(i)=ifail_factch1617_qc
                        errf(i) = zero
                        varinv(i) = zero
                     enddo
-                    if (abs(cldeff_obs(16)-cldeff_obs(17))>15.0_r_kind) then
+                    if (abs(cldeff_obs(ich890)-cldeff_obs(ich164))>15.0_r_kind) then
                        efactmc=zero
                        vfactmc=zero
                        errf(1:ich544)=zero
@@ -3415,8 +3431,8 @@ subroutine qc_amsua(nchanl,is,ndat,nsig,npred,sea,land,ice,snow,mixed,luse,   &
                  if(id_qc(ich890) == igood_qc)id_qc(ich890)=ifail_factch6_qc
                  errf(ich890) = zero
                  varinv(ich890) = zero
-                 if (latms) then
-                    do i=17,22   !  AMSU-B/MHS like channels
+                 if (latms .or. lmws) then
+                    do i=ich164,ich183a   !  AMSU-B/MHS like channels
                        if(id_qc(i) == igood_qc)id_qc(i)=ifail_factch6_qc
                        errf(i) = zero
                        varinv(i) = zero
@@ -3435,24 +3451,24 @@ subroutine qc_amsua(nchanl,is,ndat,nsig,npred,sea,land,ice,snow,mixed,luse,   &
                  if(id_qc(ich890) == igood_qc)id_qc(ich890)=ifail_factch5_qc
                  errf(ich890) = zero
                  varinv(ich890) = zero
-                 if (latms) then
-                    do i=17,22   !  AMSU-B/MHS like channels
+                 if (latms .or. lmws) then
+                    do i=ich164,ich183a   !  AMSU-B/MHS like channels
                        if(id_qc(i) == igood_qc)id_qc(i)=ifail_factch5_qc
                        errf(i) = zero
                        varinv(i) = zero
                     enddo
                  endif
-              else if (latms) then
-                 if (abs(cldeff_obs(16)-cldeff_obs(17))>10.0_r_kind) then
+              else if (latms .or. lmws) then
+                 if (abs(cldeff_obs(ich890)-cldeff_obs(ich164))>10.0_r_kind) then
                     if(id_qc(ich890) == igood_qc)id_qc(ich890)=ifail_factch1617_qc
                     errf(ich890) = zero
                     varinv(ich890) = zero
-                    do i=17,22   !  AMSU-B/MHS like channels
+                    do i=ich164,ich183a   !  AMSU-B/MHS like channels
                        if(id_qc(i) == igood_qc)id_qc(i)=ifail_factch1617_qc
                        errf(i) = zero
                        varinv(i) = zero
                     enddo
-                    if (abs(cldeff_obs(16)-cldeff_obs(17))>15.0_r_kind) then
+                    if (abs(cldeff_obs(ich890)-cldeff_obs(ich164))>15.0_r_kind) then
                        efactmc=zero
                        vfactmc=zero
                        errf(1:ich544)=zero
@@ -3499,8 +3515,8 @@ subroutine qc_amsua(nchanl,is,ndat,nsig,npred,sea,land,ice,snow,mixed,luse,   &
            if(id_qc(ich890) == igood_qc)id_qc(ich890)=ifail_factch6_qc
            errf(ich890) = zero
            varinv(ich890) = zero
-           if (latms) then
-              do i=17,22   !  AMSU-B/MHS like channels 
+           if (latms .or. lmws) then
+              do i=ich164,ich183a   !  AMSU-B/MHS like channels 
                  if(id_qc(i) == igood_qc)id_qc(i)=ifail_factch6_qc
                  errf(i) = zero
                  varinv(i) = zero
@@ -3520,8 +3536,8 @@ subroutine qc_amsua(nchanl,is,ndat,nsig,npred,sea,land,ice,snow,mixed,luse,   &
            if(id_qc(ich890) == igood_qc)id_qc(ich890)=ifail_factch4_qc
            errf(ich890) = zero
            varinv(ich890) = zero
-           if (latms) then
-              do i=17,22   !  AMSU-B/MHS like channels 
+           if (latms .or. lmws) then
+              do i=ich164,ich183a   !  AMSU-B/MHS like channels 
                  if(id_qc(i) == igood_qc)id_qc(i)=ifail_factch4_qc
                  errf(i) = zero
                  varinv(i) = zero
@@ -3596,8 +3612,8 @@ subroutine qc_amsua(nchanl,is,ndat,nsig,npred,sea,land,ice,snow,mixed,luse,   &
         if(id_qc(ich890) == igood_qc)id_qc(ich890)=ifail_emiss_qc
         errf(ich890) = zero
         varinv(ich890) = zero
-        if (latms) then
-           do i=17,22   !  AMSU-B/MHS like channels 
+        if (latms .or. lmws) then
+           do i=ich164,ich183a   !  AMSU-B/MHS like channels 
               if(id_qc(i) == igood_qc)id_qc(i)=ifail_emiss_qc
               errf(i) = zero
               varinv(i) = zero
@@ -3617,8 +3633,8 @@ subroutine qc_amsua(nchanl,is,ndat,nsig,npred,sea,land,ice,snow,mixed,luse,   &
      errf(ich544)          = fact*errf(ich544)
      vfactmc               = fact*vfactmc
      varinv(ich544)        = fact*varinv(ich544)
-     if (latms) then
-        do i=17,22   !  AMSU-B/MHS like channels 
+     if (latms .or. lmws) then
+        do i=ich164,ich183a   !  AMSU-B/MHS like channels 
            varinv(i)        = fact*varinv(i)
            errf(i)          = fact*errf(i)
         enddo
diff --git a/src/gsi/radiance_mod.f90 b/src/gsi/radiance_mod.f90
index ee57a294a..a40d3b9fa 100644
--- a/src/gsi/radiance_mod.f90
+++ b/src/gsi/radiance_mod.f90
@@ -413,7 +413,7 @@ subroutine radiance_obstype_init
           rtype(i) == 'ssmi'   .or. rtype(i) == 'atms'     .or.  rtype(i) == 'cris'   .or. & 
           rtype(i) == 'amsr2'  .or. rtype(i) == 'gmi'      .or.  rtype(i) == 'saphir' .or. &
           rtype(i) == 'cris-fsr' .or. rtype(i) == 'abi'    .or.  rtype(i) == 'viirs'  .or. &
-          rtype(i) == 'iasi-ng' )then
+          rtype(i) == 'iasi-ng'  .or. rtype(i) == 'mws' )then
           drtype(i)='rads'
        end if
     end do
diff --git a/src/gsi/read_mws.f90 b/src/gsi/read_mws.f90
new file mode 100644
index 000000000..973f6a466
--- /dev/null
+++ b/src/gsi/read_mws.f90
@@ -0,0 +1,811 @@
+subroutine read_mws(mype,val_tovs,ithin,isfcalc,&
+     rmesh,jsatid,gstime,infile,lunout,obstype,&
+     nread,ndata,nodata,twind,sis, &
+     mype_root,mype_sub,npe_sub,mpi_comm_sub,nobs, &
+     nrec_start,nrec_start_ears,nrec_start_db,dval_use,radmod)
+!$$$  subprogram documentation block
+!                .      .    .                                       .
+! subprogram:    read_mws                  read mws 1b data
+!   prgmmr:         Jin          org: ncep/emc                date: 2024-10-15
+!
+! abstract:  This routine reads BUFR format MWS radiance 
+!            (brightness temperature) files. This is edited from read_atms.f90
+!            originally written by A. Collard. Here are some notes in
+!            read_atms.f90:   Optionally the data
+!            are filtered using the AAPP filtering code. This requires
+!            This code to differ from read_bufrtovs in that all the
+!            data needs to be read in together before it is processed further. 
+!
+!            Also optionally, the data 
+!            are thinned to a specified resolution using simple 
+!            quality control checks.
+!
+!            When running the gsi in regional mode, the code only
+!            retains those observations that fall within the regional
+!            domain
+!
+! program history log:
+!  2024-12-01  Modified from read_atms.f90
+!
+!   input argument list:
+!     mype     - mpi task id
+!     val_tovs - weighting factor applied to super obs
+!     ithin    - flag to thin data
+!     isfcalc  - method to calculate surface fields within FOV
+!                when one, calculate accounting for size/shape of FOV.
+!                otherwise, use bilinear interpolation.
+!     rmesh    - thinning mesh size (km)
+!     jsatid   - satellite to read
+!     gstime   - analysis time in minutes from reference date
+!     infile   - unit from which to read BUFR data
+!     lunout   - unit to which to write data for further processing
+!     obstype  - observation type to process
+!     twind    - input group time window(hours)
+!     sis      - sensor/instrument/satellite indicator
+!     mype_root - "root" task for sub-communicator
+!     mype_sub - mpi task id within sub-communicator
+!     npe_sub  - number of data read tasks
+!     mpi_comm_sub - sub-communicator for data read
+!     nrec_start - first subset with useful information
+!     nrec_start_ears - first ears subset with useful information
+!     nrec_start_db - first db subset with useful information
+!
+!   output argument list:
+!     nread    - number of BUFR MWS 1b observations read
+!     ndata    - number of BUFR MWS 1b profiles retained for further processing
+!     nodata   - number of BUFR MWS 1b observations retained for further processing
+!     nobs     - array of observations on each subdomain for each processor
+!
+! attributes:
+!   language: f90
+!   machine:  ibm RS/6000 SP
+!
+!$$$
+  use kinds, only: r_kind,r_double,i_kind
+  use satthin, only: super_val,itxmax,makegrids,destroygrids,checkob, &
+      finalcheck,map2tgrid,score_crit
+  use satthin, only: radthin_time_info,tdiff2crit
+  use obsmod,  only: time_window_max, ta2tb
+  use radinfo, only: iuse_rad,newchn,cbias,nusis,jpch_rad,air_rad,ang_rad, &
+      use_edges,radedge1,radedge2,nusis,radstart,radstep,newpc4pred,maxscan
+  use radinfo, only: adp_anglebc
+  use gridmod, only: diagnostic_reg,regional,nlat,nlon,tll2xy,txy2ll,rlats,rlons
+  use constants, only: deg2rad,zero,one,two,three,rad2deg,r60inv,r100,rearth_equator
+  use crtm_module, only : max_sensor_zenith_angle
+  use calc_fov_crosstrk, only : instrument_init, fov_cleanup, fov_check
+  use gsi_4dvar, only: l4dvar,l4densvar,iwinbgn,winlen
+  use deter_sfc_mod, only: deter_sfc_fov,deter_sfc
+  use mws_spatial_average_mod, only : mws_spatial_average
+  use gsi_nstcouplermod, only: nst_gsi,nstinfo
+  use gsi_nstcouplermod, only: gsi_nstcoupler_skindepth,gsi_nstcoupler_deter
+  use mpimod, only: npe
+  use radiance_mod, only: rad_obs_type
+
+  implicit none
+
+! Declare passed variables
+  character(len=*),intent(in   ) :: infile,obstype,jsatid
+  character(len=20),intent(in  ) :: sis
+  integer(i_kind) ,intent(in   ) :: mype,lunout,ithin
+  integer(i_kind) ,intent(in   ) :: nrec_start,nrec_start_ears,nrec_start_db
+  integer(i_kind) ,intent(inout) :: isfcalc
+  integer(i_kind) ,intent(inout) :: nread
+  integer(i_kind),dimension(npe) ,intent(inout) :: nobs
+  integer(i_kind) ,intent(  out) :: ndata,nodata
+  real(r_kind)    ,intent(in   ) :: rmesh,gstime,twind
+  real(r_kind)    ,intent(inout) :: val_tovs
+  integer(i_kind) ,intent(in   ) :: mype_root
+  integer(i_kind) ,intent(in   ) :: mype_sub
+  integer(i_kind) ,intent(in   ) :: npe_sub
+  integer(i_kind) ,intent(in   ) :: mpi_comm_sub
+  logical         ,intent(in   ) :: dval_use
+  type(rad_obs_type),intent(in ) :: radmod
+
+! Declare local parameters
+
+  character(8),parameter:: fov_flag="crosstrk"
+  integer(i_kind),parameter:: n1bhdr=14
+  integer(i_kind),parameter:: n2bhdr=4
+  integer(i_kind),parameter:: maxobs = 800000
+  integer(i_kind),parameter:: max_chanl = 24
+  real(r_kind),parameter:: r360=360.0_r_kind
+  real(r_kind),parameter:: tbmin=50.0_r_kind
+  real(r_kind),parameter:: tbmax=550.0_r_kind
+  ! The next two are one minute in hours
+  real(r_kind),parameter:: one_minute=0.01666667_r_kind
+  real(r_kind),parameter:: minus_one_minute=-0.01666667_r_kind
+
+! Declare local variables
+  logical outside,iuse,assim,valid
+
+  character(40) :: infile2
+  character(8) subset
+  character(80) hdr1b,hdr2b
+
+  integer(i_kind) ireadsb,ireadmg,nrec_startx
+  integer(i_kind) i,j,k,ntest,iob,llll
+  integer(i_kind) iret,idate,nchanl,n,idomsfc(1)
+  integer(i_kind) ich1,ich2,ich9,ich16,ich17,ich18
+  integer(i_kind) kidsat,maxinfo,eu_mws_id
+  integer(i_kind) nmind,itx,nreal,nele,itt,num_obs
+  integer(i_kind) iskip,ichan2,ichan1,ichan16,ichan17
+  integer(i_kind) lnbufr,ksatid,isflg,ichan3,ich3,ich4,ich6
+  integer(i_kind) ilat,ilon, ifovmod, nadir
+  integer(i_kind),dimension(5):: idate5
+  integer(i_kind) instr,ichan
+  integer(i_kind):: ierr
+  integer(i_kind):: radedge_min, radedge_max
+  integer(i_kind), POINTER :: ifov
+  integer(i_kind), TARGET :: ifov_save(maxobs)
+  integer(i_kind), ALLOCATABLE :: IScan(:)
+
+  real(r_kind) cosza,sfcr
+  real(r_kind) ch1,ch2,ch3,d0,d1,d2,ch16,qval
+  real(r_kind) expansion
+  real(r_kind),dimension(0:3):: sfcpct
+  real(r_kind),dimension(0:3):: ts
+  real(r_kind) :: tsavg,vty,vfr,sty,stp,sm,sn,zz,ff10
+  real(r_kind) :: zob,tref,dtw,dtc,tz_tr
+  real(r_kind) :: satellite_height, rato
+
+  real(r_kind) pred
+  real(r_kind) dlat,panglr,dlon,tdiff
+  real(r_kind) dlon_earth_deg,dlat_earth_deg,r01
+  real(r_kind) step,start,dist1
+  real(r_kind) tt,lzaest
+  real(r_kind),dimension(0:4):: rlndsea
+  real(r_kind),allocatable :: Relative_Time_In_Seconds(:)
+  real(r_kind),allocatable,dimension(:,:):: data_all
+  real(r_kind), POINTER :: bt_in(:), crit1,rsat, t4dv, solzen, solazi
+  real(r_kind), POINTER :: dlon_earth,dlat_earth,satazi, lza
+
+  integer(i_kind), ALLOCATABLE, TARGET :: it_mesh_save(:)
+  real(r_kind), ALLOCATABLE, TARGET :: rsat_save(:)
+  real(r_kind), ALLOCATABLE, TARGET :: t4dv_save(:)
+  real(r_kind), ALLOCATABLE, TARGET :: dlon_earth_save(:)
+  real(r_kind), ALLOCATABLE, TARGET :: dlat_earth_save(:)
+  real(r_kind), ALLOCATABLE, TARGET :: crit1_save(:)
+  real(r_kind), ALLOCATABLE, TARGET :: lza_save(:)
+  real(r_kind), ALLOCATABLE, TARGET :: satazi_save(:)
+  real(r_kind), ALLOCATABLE, TARGET :: solzen_save(:) 
+  real(r_kind), ALLOCATABLE, TARGET :: solazi_save(:) 
+  real(r_kind), ALLOCATABLE, TARGET :: bt_save(:,:)
+
+  integer(i_kind),allocatable,dimension(:):: nrec
+  real(r_double),allocatable,dimension(:):: data1b8
+  real(r_double),dimension(n1bhdr):: bfr1bhdr
+  real(r_double),dimension(n2bhdr):: bfr2bhdr
+
+  real(r_kind) cdist,disterr,disterrmax,dlon00,dlat00
+
+  logical :: critical_channels_missing
+  real(r_kind)    :: ptime,timeinflat,crit0
+  integer(i_kind) :: ithin_time,n_tbin
+  integer(i_kind),pointer :: it_mesh => null()
+!**************************************************************************
+! Initialize variables
+
+  maxinfo=31
+  lnbufr = 15
+  disterrmax=zero
+  ntest=0
+  ndata  = 0
+  nodata  = 0
+  nread  = 0
+
+  ilon=3
+  ilat=4
+
+  if(nst_gsi>0) then
+     call gsi_nstcoupler_skindepth(obstype,zob)
+  endif
+
+  call radthin_time_info(obstype, jsatid, sis, ptime, ithin_time)
+  if( ptime > 0.0_r_kind) then
+     n_tbin=nint(2*time_window_max/ptime)
+  else
+     n_tbin=1
+  endif
+! Make thinning grids
+  call makegrids(rmesh,ithin,n_tbin=n_tbin)
+
+! Set nadir position based on value of maxscan (95) for MWW
+  nadir=47
+
+! Set various variables depending on type of data to be read
+
+  if (obstype /= 'mws') then
+     write(6,*) 'READ_MWS called for obstype '//obstype//': RETURNING'
+     return
+  end if
+
+!  instrument specific variables
+  d1 =  0.754_r_kind
+  d2 = -2.265_r_kind 
+  r01 = 0.01_r_kind
+  ich1   = 1   !1
+  ich2   = 2   !2
+  ich3   = 3   !3
+
+  ich6   = 6   !6
+  ich9   = 9   !8
+  ich16  = 16  !16
+  ich17  = 17  !17
+  ich18  = 18  !18
+! Set array index for surface-sensing channels
+  ichan1  = newchn(sis,ich1)
+  ichan2  = newchn(sis,ich2)
+  ichan3  = newchn(sis,ich3)
+
+  ichan16 = newchn(sis,ich17)
+  ichan17 = newchn(sis,ich18)
+
+  if(jsatid == 'metop-sg-a1') then
+!    24: metop-D
+     kidsat=24   
+  else 
+     write(6,*) 'READ_MWS: Unrecognized value for jsatid '//jsatid//': RETURNING'
+     return
+  end if
+! ESA/EUMETSAT Radiometer MWS (Microwave Sounder)
+  eu_mws_id = 233
+
+  radedge_min = 0
+  radedge_max = 1000
+  do i=1,jpch_rad
+     if (trim(nusis(i))==trim(sis)) then
+        step  = radstep(i)
+        start = radstart(i)
+        if (radedge1(i)/=-1 .or. radedge2(i)/=-1) then
+           radedge_min=radedge1(i)
+           radedge_max=radedge2(i)
+        end if
+        exit 
+     endif
+  end do 
+
+! Allocate arrays to hold all data for given satellite
+  nchanl= max_chanl
+  if(dval_use) maxinfo = maxinfo+2
+  nreal = maxinfo + nstinfo
+  nele  = nreal   + nchanl
+  allocate(data_all(nele,itxmax),nrec(itxmax))
+  nrec=999999
+
+! IFSCALC setup
+  isfcalc = 0
+  if (isfcalc==1) then
+     instr=20                    
+     ichan=17                    ! pick a surface sens. channel
+     expansion=2.9_r_kind        ! use almost three for microwave sensors.
+  endif
+!   Set rlndsea for types we would prefer selecting
+  rlndsea(0) = zero
+  rlndsea(1) = 15._r_kind
+  rlndsea(2) = 10._r_kind
+  rlndsea(3) = 15._r_kind
+  rlndsea(4) = 100._r_kind
+     
+! If all channels of a given sensor are set to monitor or not
+! assimilate mode (iuse_rad<1), reset relative weight to zero.
+! We do not want such observations affecting the relative
+! weighting between observations within a given thinning group.
+
+  assim=.false.
+  search: do i=1,jpch_rad
+     if ((nusis(i)==sis) .and. (iuse_rad(i)>0)) then
+        assim=.true.
+        exit search
+     endif
+  end do search
+  if (.not.assim) val_tovs=zero
+
+! Initialize variables for use by FOV-based surface code.
+  if (isfcalc == 1) then
+     call instrument_init(instr,jsatid,expansion,valid)
+     if (.not. valid) then
+       if (assim) then
+         write(6,*)'READ_MWS:  ***ERROR*** IN SETUP OF FOV-SFC CODE. STOP'
+         call stop2(71)
+       else
+         call fov_cleanup
+         isfcalc = 0
+         write(6,*)'READ_MWS:  ***ERROR*** IN SETUP OF FOV-SFC CODE'
+       endif
+     endif
+  endif
+
+! This eventually needs to be spit between MHS and AMSU-A like channels
+  if (isfcalc==1) then
+!   if (amsub.or.mhs)then
+!     rlndsea(4) = max(rlndsea(0),rlndsea(1),rlndsea(2),rlndsea(3))
+!   else
+      rlndsea=0
+!   endif
+  endif
+
+! Allocate arrays for BUFR I/O
+  ALLOCATE(data1b8(nchanl))
+  ALLOCATE(rsat_save(maxobs))
+  ALLOCATE(t4dv_save(maxobs))
+  ALLOCATE(dlon_earth_save(maxobs))
+  ALLOCATE(dlat_earth_save(maxobs))
+  ALLOCATE(crit1_save(maxobs))
+  ALLOCATE(it_mesh_save(maxobs))
+  ALLOCATE(lza_save(maxobs))
+  ALLOCATE(satazi_save(maxobs))
+  ALLOCATE(solzen_save(maxobs)) 
+  ALLOCATE(solazi_save(maxobs)) 
+  ALLOCATE(bt_save(max_chanl,maxobs))
+
+  iob=1
+! Big loop over standard data feed and possible rars/db data
+! llll=1 normal feed, llll=2 RARS/EARS data, llll=3 DB/UW data
+  ears_db_loop: do llll= 1, 3
+
+     if(llll == 1)then
+        nrec_startx = nrec_start
+        infile2 = trim(infile)         ! Set bufr subset names based on type of data to read
+     elseif(llll == 2) then
+        nrec_startx = nrec_start_ears
+        infile2 = trim(infile)//'ears' ! Set bufr subset names based on type of data to read
+     elseif(llll == 3) then
+        nrec_startx = nrec_start_db
+        infile2 = trim(infile)//'_db'  ! Set bufr subset names based on type of data to read
+     end if
+
+!    Reopen unit to satellite bufr file
+     open(lnbufr,file=trim(infile2),form='unformatted',status = 'old', &
+         iostat = ierr)
+     if(ierr /= 0) cycle ears_db_loop
+
+     call openbf(lnbufr,'IN',lnbufr)
+     hdr1b ='SAID FOVN YEAR MNTH DAYS HOUR MINU SECO CLAT CLON CLATH CLONH HMSL SIID'
+     hdr2b ='SAZA SOZA BEARAZ SOLAZI'
+   
+!    Loop to read bufr file
+     read_subset: do while(ireadmg(lnbufr,subset,idate)>=0 .AND. iob < maxobs)
+
+        read_loop: do while (ireadsb(lnbufr)==0 .and. iob < maxobs)
+
+           rsat       => rsat_save(iob)
+           t4dv       => t4dv_save(iob)
+           dlon_earth => dlon_earth_save(iob)
+           dlat_earth => dlat_earth_save(iob)
+           crit1      => crit1_save(iob)
+           it_mesh    => it_mesh_save(iob)
+           ifov       => ifov_save(iob)
+           lza        => lza_save(iob)
+           satazi     => satazi_save(iob)
+           solzen     => solzen_save(iob)
+           solazi     => solazi_save(iob)
+
+!          inflate selection value for ears_db data
+           crit0 = 0.01_r_kind
+           if ( llll > 1 ) crit0 = crit0 + r100 * real(llll,r_kind)
+
+           call ufbint(lnbufr,bfr1bhdr,n1bhdr,1,iret,hdr1b)
+
+!          Extract satellite id and instrument id.  If not the one we want, read next record
+           rsat=bfr1bhdr(1) 
+           ksatid=nint(bfr1bhdr(1))
+           if(ksatid /= kidsat) cycle read_subset
+           if(nint(bfr1bhdr(14)) /= eu_mws_id) cycle read_subset
+
+!          Extract observation location and other required information
+           if(abs(bfr1bhdr(11)) <= 90._r_kind .and. abs(bfr1bhdr(12)) <= r360)then
+              dlat_earth = bfr1bhdr(11)
+              dlon_earth = bfr1bhdr(12)
+           elseif(abs(bfr1bhdr(9)) <= 90._r_kind .and. abs(bfr1bhdr(10)) <= r360)then
+              dlat_earth = bfr1bhdr(9)
+              dlon_earth = bfr1bhdr(10)
+           else
+              cycle read_loop
+           end if
+           if(dlon_earth<zero)  dlon_earth = dlon_earth+r360
+           if(dlon_earth>=r360) dlon_earth = dlon_earth-r360
+
+
+!          Extract date information.  If time outside window, skip this obs
+           idate5(1) = bfr1bhdr(3) !year
+           idate5(2) = bfr1bhdr(4) !month
+           idate5(3) = bfr1bhdr(5) !day
+           idate5(4) = bfr1bhdr(6) !hour
+           idate5(5) = bfr1bhdr(7) !minute
+           call w3fs21(idate5,nmind)
+           t4dv= (real((nmind-iwinbgn),r_kind) + bfr1bhdr(8)*r60inv)*r60inv    ! add in seconds
+           tdiff=t4dv+(iwinbgn-gstime)*r60inv
+           if (l4dvar.or.l4densvar) then
+              if (t4dv<minus_one_minute .OR. t4dv>winlen+one_minute) &
+                  cycle read_loop
+           else
+              if(abs(tdiff) > twind+one_minute) cycle read_loop
+           endif
+
+           timeinflat=two
+           call tdiff2crit(tdiff,ptime,ithin_time,timeinflat,crit0,crit1,it_mesh)
+ 
+           call ufbint(lnbufr,bfr2bhdr,n2bhdr,1,iret,hdr2b)
+
+           satazi=bfr2bhdr(3)
+           if (abs(satazi) > r360) then
+              satazi=zero
+           endif
+
+           ifov = nint(bfr1bhdr(2))
+           lza = bfr2bhdr(1)*deg2rad      ! local zenith angle
+           if(ifov <= nadir)    lza=-lza
+
+           panglr=(start+real(ifov-1,r_kind)*step)*deg2rad
+           satellite_height=bfr1bhdr(13)
+!          Ensure orbit height is reasonable, 840 km 
+           if (satellite_height < 780000.0_r_kind .OR. &
+              satellite_height > 900000.0_r_kind) satellite_height = 840000.0_r_kind
+           rato = one + satellite_height/rearth_equator
+           lzaest = asin(rato*sin(panglr))
+
+           if(abs(lza)*rad2deg > MAX_SENSOR_ZENITH_ANGLE) then
+              write(6,*)'READ_MWS WARNING lza error ',lza,panglr
+              cycle read_loop
+           end if
+
+!          Check for errors in satellite zenith angles 
+           if(abs(lzaest-lza)*rad2deg > one) then
+              write(6,*)' READ_MWS WARNING uncertainty in lza ', &
+              lza*rad2deg,lzaest*rad2deg,sis,ifov,start,step
+              cycle read_loop
+           end if
+
+           solzen_save(iob)=bfr2bhdr(2) 
+           solazi_save(iob)=bfr2bhdr(4) 
+
+!          Read data record.  Increment data counter
+           call ufbrep(lnbufr,data1b8,1,nchanl,iret,'TMBR')
+           if (iret <= 0) then
+!             Read 'TMBRST' in the sample data.
+              call ufbrep(lnbufr,data1b8,1,nchanl,iret,'TMBRST')
+           endif
+           bt_save(1:nchanl,iob) = data1b8(1:nchanl)
+
+           iob=iob+1
+
+        end do read_loop
+     end do read_subset
+     call closbf(lnbufr)
+     close(lnbufr)
+  end do ears_db_loop
+  deallocate(data1b8)
+
+  num_obs = iob-1
+
+  if (num_obs <= 0) then
+     write(6,*) 'READ_MWS: No MWS Data were read in'
+     return
+  end if
+
+! Call filtering code 
+
+  ALLOCATE(Relative_Time_In_Seconds(Num_Obs))
+  ALLOCATE(IScan(Num_Obs))
+  Relative_Time_In_Seconds = 3600.0_r_kind*T4DV_Save(1:Num_Obs)
+  call mws_spatial_average(Num_Obs, NChanl, IFOV_Save(1:Num_Obs), &
+       Relative_Time_In_Seconds, BT_Save(1:nchanl,1:Num_Obs), IScan, IRet)
+  write(6,*) 'mws_spatial_average Called with IRet=',IRet
+  DEALLOCATE(Relative_Time_In_Seconds)
+  
+  IF (IRet /= 0) THEN
+     write(6,*) 'Error Calling mws_spatial_average from READ_MWS'
+     RETURN
+  END IF
+
+! Complete Read_MWS thinning and QC steps
+
+  ObsLoop: do iob = 1, num_obs  
+
+     rsat       => rsat_save(iob)
+     t4dv       => t4dv_save(iob)
+     dlon_earth => dlon_earth_save(iob)
+     dlat_earth => dlat_earth_save(iob)
+     crit1      => crit1_save(iob)
+     it_mesh    => it_mesh_save(iob)
+     ifov       => ifov_save(iob)
+     lza        => lza_save(iob)
+     satazi     => satazi_save(iob)
+     solzen     => solzen_save(iob)
+     solazi     => solazi_save(iob)
+     bt_in      => bt_save(1:nchanl,iob)
+     
+     dlat_earth_deg = dlat_earth
+     dlon_earth_deg = dlon_earth
+     dlat_earth = dlat_earth*deg2rad
+     dlon_earth = dlon_earth*deg2rad   
+
+!    Regional case
+     if(regional)then
+        call tll2xy(dlon_earth,dlat_earth,dlon,dlat,outside)
+        if(diagnostic_reg) then
+           call txy2ll(dlon,dlat,dlon00,dlat00)
+           ntest=ntest+1
+           cdist=sin(dlat_earth)*sin(dlat00)+cos(dlat_earth)*cos(dlat00)* &
+                (sin(dlon_earth)*sin(dlon00)+cos(dlon_earth)*cos(dlon00))
+           cdist=max(-one,min(cdist,one))
+           disterr=acos(cdist)*rad2deg
+           disterrmax=max(disterrmax,disterr)
+        end if
+           
+!       Check to see if in domain
+        if(outside) cycle ObsLoop
+           
+!    Global case
+     else
+        dlat=dlat_earth
+        dlon=dlon_earth
+        call grdcrd1(dlat,rlats,nlat,1)
+        call grdcrd1(dlon,rlons,nlon,1)
+     endif
+
+! Check time window
+     if (l4dvar.or.l4densvar) then
+        if (t4dv<zero .OR. t4dv>winlen) cycle ObsLoop
+     else
+        tdiff=t4dv+(iwinbgn-gstime)*r60inv
+        if(abs(tdiff) > twind) cycle ObsLoop
+     endif
+ 
+!    Map obs to thinning grid
+     call map2tgrid(dlat_earth,dlon_earth,dist1,crit1,itx,ithin,itt,iuse,sis,it_mesh=it_mesh)
+     if(.not. iuse)cycle ObsLoop
+
+!
+!    Check FOV and scan-edge usage
+     if (.not. use_edges .and. (ifov < radedge_min .OR. ifov > radedge_max )) &
+          cycle ObsLoop
+
+     if (maxscan < 96) then
+       ! For ATMS when using the old style satang files, 
+       ! we shift the FOV number down by three as we can only use
+       ! 90 of the 96 positions right now because of the scan bias limitation.
+       ifovmod=ifov-3
+       ! Check that ifov is not out of range of cbias dimension
+       if (ifovmod < 1 .OR. ifovmod > 90) cycle ObsLoop
+     else
+       ! This line is for consistency with previous treatment
+       if (ifov < 4 .OR. ifov > 93) cycle ObsLoop
+       ifovmod=ifov
+     endif
+
+     nread=nread+nchanl
+     
+!    Transfer observed brightness temperature to work array.  If any
+!    temperature exceeds limits, reset observation to "bad" value
+     iskip=0
+     critical_channels_missing = .false.
+     do j=1,nchanl
+        if (bt_in(j) < tbmin .or. bt_in(j) > tbmax) then
+           iskip = iskip + 1
+           
+!          Flag profiles where key channels are bad  
+           if((j == ich1 .or. j == ich2 .or. &
+                j == ich17 .or. j == ich18)) critical_channels_missing = .true.
+        endif
+     end do
+     if (iskip >= nchanl) cycle ObsLoop
+
+!    Determine surface properties based on 
+!    sst and land/sea/ice mask   
+!
+!    isflg    - surface flag
+!               0 sea
+!               1 land
+!               2 sea ice
+!               3 snow
+!               4 mixed                       
+
+!    FOV-based surface code requires fov number.  if out-of-range, then
+!    skip this ob.
+
+     if (isfcalc == 1) then
+        call fov_check(ifov,instr,ichan,valid)
+        if (.not. valid) cycle ObsLoop
+
+!    When isfcalc is one, calculate surface fields based on size/shape of fov.
+!    Otherwise, use bilinear method.
+
+        call deter_sfc_fov(fov_flag,ifov,instr,ichan,satazi,dlat_earth_deg,&
+             dlon_earth_deg,expansion,t4dv,isflg,idomsfc(1), &
+             sfcpct,vfr,sty,vty,stp,sm,ff10,sfcr,zz,sn,ts,tsavg)
+     else
+        call deter_sfc(dlat,dlon,dlat_earth,dlon_earth,t4dv,isflg, &
+             idomsfc(1),sfcpct,ts,tsavg,vty,vfr,sty,stp,sm,sn,zz,ff10,sfcr)
+     endif
+
+     crit1 = crit1 + rlndsea(isflg) + 10._r_kind*real(iskip,r_kind) + 0.01_r_kind * abs(zz)
+     call checkob(dist1,crit1,itx,iuse)
+     if(.not. iuse)cycle ObsLoop
+
+           if (critical_channels_missing) then
+
+              pred=1.0e8_r_kind
+
+           else
+
+!    Set data quality predictor
+!    Simply modify the AMSU-A-Type calculations and use them for all ATMS channels.
+!    Remove angle dependent pattern (not mean).
+              if (adp_anglebc .and. newpc4pred) then
+                 ch1 = bt_in(ich1)-ang_rad(ichan1)*cbias(ifovmod,ichan1)
+                 ch2 = bt_in(ich2)-ang_rad(ichan2)*cbias(ifovmod,ichan2)
+                 ch16= bt_in(ich17)-ang_rad(ichan16)*cbias(ifovmod,ichan16)
+              else
+                 ch1 = bt_in(ich1)-ang_rad(ichan1)*cbias(ifovmod,ichan1)+ &
+                      air_rad(ichan1)*cbias(nadir,ichan1)
+                 ch2 = bt_in(ich2)-ang_rad(ichan2)*cbias(ifovmod,ichan2)+ &
+                      air_rad(ichan2)*cbias(nadir,ichan2)   
+                 ch16= bt_in(ich17)-ang_rad(ichan16)*cbias(ifovmod,ichan16)+ &
+                      air_rad(ichan16)*cbias(nadir,ichan16)
+              end if
+              if (isflg == 0 .and. ch1<285.0_r_kind .and. ch2<285.0_r_kind) then
+                 cosza = cos(lza)
+                 if (radmod%lcloud_fwd) then
+                    qval=-113.2_r_kind+(2.41_r_kind-0.0049_r_kind*ch1)*ch1 +  &
+                               0.454_r_kind*ch2-ch16
+                    if (qval>=9.0_r_kind) then
+                       qval=1000.0_r_kind*qval
+                    else
+                       qval  = zero
+                    end if
+                    if (radmod%lprecip) qval=zero 
+                 else 
+                    d0    = 8.24_r_kind - 2.622_r_kind*cosza + 1.846_r_kind*cosza*cosza
+                    qval  = cosza*(d0+d1*log(285.0_r_kind-ch1)+d2*log(285.0_r_kind-ch2))
+                 endif
+                 pred  = max(zero,qval)*100.0_r_kind
+              else
+!          This is taken straight from AMSU-A even though Ch 3 has a different polarisation
+!          and ATMS Ch16 is at a slightly different frequency to AMSU-A Ch 15.
+                 if (adp_anglebc .and. newpc4pred) then
+                    ch3 = bt_in(ich3)-ang_rad(ichan3)*cbias(ifovmod,ichan3)
+                 else
+                    ch3  = bt_in(ich3)-ang_rad(ichan3)*cbias(ifovmod,ichan3)+ &
+                         air_rad(ichan3)*cbias(nadir,ichan3)   
+                 end if
+                 pred = abs(ch1-ch16)
+                 if(ch1-ch16 >= three) then
+                    tt   = 168._r_kind-0.49_r_kind*ch16
+                    if(ch1 > 261._r_kind .or. ch1 >= tt .or. &
+                         (ch16 <= 273._r_kind))then
+                       pred = 100._r_kind
+                    end if
+                 end if
+              endif
+           end if
+
+!    Compute "score" for observation.  All scores>=0.0.  Lowest score is "best"
+     crit1 = crit1+pred 
+     call finalcheck(dist1,crit1,itx,iuse)
+     if(.not. iuse)cycle ObsLoop
+     
+!    interpolate NSST variables to Obs. location and get dtw, dtc, tz_tr
+     if(nst_gsi>0) then
+        tref  = ts(0)
+        dtw   = zero
+        dtc   = zero
+        tz_tr = one
+        if(sfcpct(0)>zero) then
+           call gsi_nstcoupler_deter(dlat_earth,dlon_earth,t4dv,zob,tref,dtw,dtc,tz_tr)
+        endif
+     endif
+
+! Re-calculate look angle
+     panglr=(start+real(ifov-1,r_kind)*step)*deg2rad
+
+
+!     Load selected observation into data array
+              
+     data_all(1 ,itx)= rsat                      ! satellite ID
+     data_all(2 ,itx)= t4dv                      ! time
+     data_all(3 ,itx)= dlon                      ! grid relative longitude
+     data_all(4 ,itx)= dlat                      ! grid relative latitude
+     data_all(5 ,itx)= lza                       ! local zenith angle
+     data_all(6 ,itx)= satazi                    ! local azimuth angle
+     data_all(7 ,itx)= panglr                    ! look angle
+     data_all(8 ,itx)= ifovmod                   ! scan position
+     data_all(9 ,itx)= solzen                    ! solar zenith angle
+     data_all(10,itx)= solazi                    ! solar azimuth angle
+     data_all(11,itx) = sfcpct(0)                ! sea percentage of
+     data_all(12,itx) = sfcpct(1)                ! land percentage
+     data_all(13,itx) = sfcpct(2)                ! sea ice percentage
+     data_all(14,itx) = sfcpct(3)                ! snow percentage
+     data_all(15,itx)= ts(0)                     ! ocean skin temperature
+     data_all(16,itx)= ts(1)                     ! land skin temperature
+     data_all(17,itx)= ts(2)                     ! ice skin temperature
+     data_all(18,itx)= ts(3)                     ! snow skin temperature
+     data_all(19,itx)= tsavg                     ! average skin temperature
+     data_all(20,itx)= vty                       ! vegetation type
+     data_all(21,itx)= vfr                       ! vegetation fraction
+     data_all(22,itx)= sty                       ! soil type
+     data_all(23,itx)= stp                       ! soil temperature
+     data_all(24,itx)= sm                        ! soil moisture
+     data_all(25,itx)= sn                        ! snow depth
+     data_all(26,itx)= zz                        ! surface height
+     data_all(27,itx)= idomsfc(1) + 0.001_r_kind ! dominate surface type
+     data_all(28,itx)= sfcr                      ! surface roughness
+     data_all(29,itx)= ff10                      ! ten meter wind factor
+     data_all(30,itx) = dlon_earth_deg           ! earth relative longitude (deg)
+     data_all(31,itx) = dlat_earth_deg           ! earth relative latitude (deg)
+     
+     if(dval_use) then
+        data_all(32,itx)= val_tovs
+        data_all(33,itx)= itt
+     end if
+     
+     if(nst_gsi>0) then
+        data_all(maxinfo+1,itx) = tref            ! foundation temperature
+        data_all(maxinfo+2,itx) = dtw             ! dt_warm at zob
+        data_all(maxinfo+3,itx) = dtc             ! dt_cool at zob
+        data_all(maxinfo+4,itx) = tz_tr           ! d(Tz)/d(Tr)
+     endif
+
+     do i=1,nchanl
+        data_all(i+nreal,itx)=bt_in(i)
+     end do
+     nrec(itx)=iob
+
+  end do ObsLoop
+
+
+  DEALLOCATE(iscan)
+! DEAllocate I/O arrays
+  DEALLOCATE(rsat_save)
+  DEALLOCATE(t4dv_save)
+  DEALLOCATE(dlon_earth_save)
+  DEALLOCATE(dlat_earth_save)
+  DEALLOCATE(crit1_save)
+  DEALLOCATE(it_mesh_save)
+  DEALLOCATE(lza_save)
+  DEALLOCATE(satazi_save)
+  DEALLOCATE(solzen_save) 
+  DEALLOCATE(solazi_save) 
+  DEALLOCATE(bt_save)
+
+  call combine_radobs(mype_sub,mype_root,npe_sub,mpi_comm_sub,&
+       nele,itxmax,nread,ndata,data_all,score_crit,nrec)
+
+! 
+  if(mype_sub==mype_root)then
+     do n=1,ndata
+        do i=1,nchanl
+           if(data_all(i+nreal,n) > tbmin .and. &
+                data_all(i+nreal,n) < tbmax)nodata=nodata+1
+        end do
+     end do
+
+     if(dval_use .and. assim)then
+        do n=1,ndata
+           itt=nint(data_all(33,n))
+           super_val(itt)=super_val(itt)+val_tovs
+        end do
+     end if
+     
+!    Write final set of "best" observations to output file
+     call count_obs(ndata,nele,ilat,ilon,data_all,nobs)
+     write(lunout) obstype,sis,nreal,nchanl,ilat,ilon
+     write(lunout) ((data_all(k,n),k=1,nele),n=1,ndata)
+  end if
+     
+! Deallocate local arrays
+  deallocate(data_all,nrec)
+
+! Deallocate satthin arrays
+  call destroygrids
+
+! Deallocate FOV surface code arrays and nullify pointers.
+  if (isfcalc == 1) call fov_cleanup
+
+  if(diagnostic_reg.and.ntest>0) write(6,*)'READ_MWS:  ',&
+     'mype,ntest,disterrmax=',mype,ntest,disterrmax
+
+! End of routine
+  return
+
+end subroutine read_mws
diff --git a/src/gsi/read_obs.F90 b/src/gsi/read_obs.F90
index 46bca242e..252563343 100644
--- a/src/gsi/read_obs.F90
+++ b/src/gsi/read_obs.F90
@@ -949,6 +949,7 @@ subroutine read_obs(ndata,mype)
                obstype == 'ahi'       .or. avhrr                  .or.  &
                amsre  .or. ssmis      .or. obstype == 'ssmi'      .or.  &
                obstype == 'ssu'       .or. obstype == 'atms'      .or.  &
+               obstype == 'mws'       .or.                              &
                obstype == 'cris'      .or. obstype == 'cris-fsr'  .or.  &
                obstype == 'amsr2'     .or. obstype == 'viirs-m'   .or.  obstype == 'metimage' .or. &
                obstype == 'gmi'       .or. obstype == 'saphir'   ) then
@@ -1046,6 +1047,8 @@ subroutine read_obs(ndata,mype)
                 parallel_read(i)= .true.
 ! N.B. ATMS must be run on one processor for the filtering code to work.
              else if(obstype == 'atms')then
+!                 parallel_read(i)= .true.
+             else if(obstype == 'mws')then
 !                 parallel_read(i)= .true.
              else if(ssmis)then
 !               parallel_read(i)= .true.  
@@ -1090,6 +1093,7 @@ subroutine read_obs(ndata,mype)
                    obstype == 'mhs'   .or. obstype == 'hirs3' .or. &
                    obstype == 'cris'  .or. obstype == 'cris-fsr' .or. &
                    obstype == 'iasi'  .or. obstype == 'iasi-ng'  .or. &
+                   obstype == 'mws'   .or.                         &
                    obstype == 'atms') .and. &
                   (dplat(i) == 'n17' .or. dplat(i) == 'n18' .or. & 
                    dplat(i) == 'n19' .or. dplat(i) == 'npp' .or. &
@@ -1100,6 +1104,7 @@ subroutine read_obs(ndata,mype)
           db_possible(i) = ditype(i) == 'rad'  .and.       & 
                   (obstype == 'amsua' .or.  obstype == 'amsub' .or.  & 
                    obstype == 'mhs' .or. obstype == 'atms' .or. &
+                   obstype == 'mws' .or.                        &
                    obstype == 'cris' .or. obstype == 'cris-fsr' .or. &
                    obstype == 'iasi' .or. obstype == 'iasi-ng') .and. &
                   (dplat(i) == 'n17' .or. dplat(i) == 'n18' .or. & 
@@ -1749,6 +1754,14 @@ subroutine read_obs(ndata,mype)
                      read_rec(i),read_ears_rec(i),read_db_rec(i),dval_use,radmod)
                 string='READ_ATMS'
 
+!            Process mws data
+             else if (obstype == 'mws') then
+                call read_mws(mype,val_dat,ithin,isfcalc,rmesh,dplat(i),gstime,&
+                     infile,lunout,obstype,nread,npuse,nouse,twind,sis, &
+                     mype_root,mype_sub(mm1,i),npe_sub(i),mpi_comm_sub(i),nobs_sub1(1,i),&
+                     read_rec(i),read_ears_rec(i),read_db_rec(i),dval_use,radmod)
+                string='READ_MWS'
+
 !            Process saphir data
              else if (obstype == 'saphir') then
                 call read_saphir(mype,val_dat,ithin,isfcalc,rmesh,dplat(i),gstime,&
diff --git a/src/gsi/read_satmar.f90 b/src/gsi/read_satmar.f90
index e9062a65f..3271c0703 100644
--- a/src/gsi/read_satmar.f90
+++ b/src/gsi/read_satmar.f90
@@ -121,7 +121,7 @@ subroutine read_satmar (nread, ndata, nodata,                                 &
    character(len=20),dimension(nosat) :: namesat
    character(len=20) :: sis
    character(len=20) :: subset
-   character(len=11), parameter :: myname='read_satmar '
+   character(len=11), parameter :: myname='read_satmar'
 !  logical
    logical outside, luse
    logical lhilbert
diff --git a/src/gsi/setuprad.f90 b/src/gsi/setuprad.f90
index 8ed14b6fe..95c0af85f 100644
--- a/src/gsi/setuprad.f90
+++ b/src/gsi/setuprad.f90
@@ -342,7 +342,7 @@ subroutine setuprad(obsLL,odiagLL,lunin,mype,aivals,stats,nchanl,nreal,nobs,&
 
   real(r_single) freq4,pol4,wave4,varch4,tlap4
   real(r_kind) node 
-  real(r_kind) term,tlap,tb_obsbc1,tb_obsbc16,tb_obsbc17 
+  real(r_kind) term,tlap,tb_obsbc1,tb_obsbc16,tb_obsbc17,tb_obsbc18
   real(r_kind) drad,dradnob,varrad,error,errinv,useflag
   real(r_kind) cg_rad,wgross,wnotgross,wgt,arg,exp_arg
   real(r_kind) tzbgr,tsavg5,trop5,pangs,cld,cldp
@@ -369,6 +369,7 @@ subroutine setuprad(obsLL,odiagLL,lunin,mype,aivals,stats,nchanl,nreal,nobs,&
   type(sparr2) :: dhx_dx
   logical avhrr,avhrr_navy,viirs,lextra,ssu,iasi,iasing,cris,seviri,atms
   logical ssmi,ssmis,amsre,amsre_low,amsre_mid,amsre_hig,amsr2,gmi,saphir
+  logical :: mws
   logical ssmis_las,ssmis_uas,ssmis_env,ssmis_img
   logical sea,mixed,land,ice,snow,toss,l_may_be_passive,eff_area
   logical microwave, microwave_low
@@ -528,11 +529,12 @@ subroutine setuprad(obsLL,odiagLL,lunin,mype,aivals,stats,nchanl,nreal,nobs,&
   atms       = obstype == 'atms'
   saphir     = obstype == 'saphir'
   abi        = obstype == 'abi'
+  mws        = obstype == 'mws'
 
   ssmis=ssmis_las.or.ssmis_uas.or.ssmis_img.or.ssmis_env.or.ssmis 
 
   microwave=amsua .or. amsub  .or. mhs .or. msu .or. hsb .or. &
-            ssmi  .or. ssmis  .or. amsre .or. atms .or. &
+            ssmi  .or. ssmis  .or. amsre .or. atms .or. mws .or. &
             amsr2 .or. gmi  .or.  saphir
 
   microwave_low =amsua  .or.  msu .or. ssmi .or. ssmis .or. amsre
@@ -1051,12 +1053,12 @@ subroutine setuprad(obsLL,odiagLL,lunin,mype,aivals,stats,nchanl,nreal,nobs,&
         cldeff_obs=zero 
         cldeff_fg=zero  
         if(microwave .and. sea) then 
-           if(radmod%lcloud_fwd .and. (amsua .or. atms)) then
-              call ret_amsua(tb_obs,nchanl,tsavg5,zasat,clw_obs,ierrret,scat)
+           if(radmod%lcloud_fwd .and. (amsua .or. atms .or. mws)) then
+              call ret_amsua(tb_obs,nchanl,tsavg5,zasat,clw_obs,ierrret,scat=scat)
               scatp=scat 
            else
               call calc_clw(nadir,tb_obs,tsim,ich,nchanl,no85GHz,amsua,ssmi,ssmis,amsre,atms, &
-                   amsr2,gmi,saphir,tsavg5,sfc_speed,zasat,clw_obs,tpwc_obs,gwp,kraintype,ierrret)
+                   mws,amsr2,gmi,saphir,tsavg5,sfc_speed,zasat,clw_obs,tpwc_obs,gwp,kraintype,ierrret)
            end if
 
            if (ierrret /= 0) then
@@ -1070,6 +1072,11 @@ subroutine setuprad(obsLL,odiagLL,lunin,mype,aivals,stats,nchanl,nreal,nobs,&
                 id_qc(1:7) = ifail_cloud_qc
                 varinv(16:22)=zero
                 id_qc(16:22) = ifail_cloud_qc
+             else if (mws) then 
+                varinv(1:8)=zero
+                id_qc(1:8) = ifail_cloud_qc
+                varinv(17:24)=zero
+                id_qc(17:24) = ifail_cloud_qc
              else       
                 varinv(1:nchanl)=zero
                 id_qc(1:nchanl) = ifail_cloud_qc
@@ -1090,6 +1097,11 @@ subroutine setuprad(obsLL,odiagLL,lunin,mype,aivals,stats,nchanl,nreal,nobs,&
                        id_qc(1:7) = ifail_cao_qc
                        varinv(16:22)=zero
                        id_qc(16) = ifail_cao_qc
+                    else if (mws) then
+                       varinv(1:8)=zero
+                       id_qc(1:8) = ifail_cao_qc
+                       varinv(17:24)=zero
+                       id_qc(17:24) = ifail_cao_qc
                     else
                        varinv(1:nchanl)=zero
                        id_qc(1:nchanl) = ifail_cao_qc
@@ -1101,7 +1113,7 @@ subroutine setuprad(obsLL,odiagLL,lunin,mype,aivals,stats,nchanl,nreal,nobs,&
 
         predbias=zero
 
-!$omp parallel do  schedule(dynamic,1) private(i,mm,j,k,tlap,node,bias)
+!##!$omp parallel do  schedule(dynamic,1) private(i,mm,j,k,tlap,node,bias)
         do i=1,nchanl
            mm=ich(i)
 
@@ -1219,7 +1231,7 @@ subroutine setuprad(obsLL,odiagLL,lunin,mype,aivals,stats,nchanl,nreal,nobs,&
 
         kmax = 0
         if (lwrite_peakwt .or. passive_bc) then
-!$omp parallel do  schedule(dynamic,1) private(i,k,ptau5derivmax,ptau5deriv)
+!##!$omp parallel do  schedule(dynamic,1) private(i,k,ptau5derivmax,ptau5deriv)
            do i=1,nchanl
               ptau5derivmax = -9.9e31_r_kind
 ! maximum of weighting function is level at which transmittance
@@ -1245,7 +1257,7 @@ subroutine setuprad(obsLL,odiagLL,lunin,mype,aivals,stats,nchanl,nreal,nobs,&
         cld_rbc_idx2=zero
         if (radmod%lcloud_fwd .and. radmod%ex_biascor .and. eff_area) then
            ierrret=0
-!$omp parallel do  schedule(dynamic,1) private(i,mm,j)
+!##!$omp parallel do  schedule(dynamic,1) private(i,mm,j)
            do i=1,nchanl
               mm=ich(i)
               tsim_bc(i)=tsim(i)
@@ -1261,7 +1273,7 @@ subroutine setuprad(obsLL,odiagLL,lunin,mype,aivals,stats,nchanl,nreal,nobs,&
               tsim_clr_bc(i)=tsim_clr_bc(i)+predbias(npred+2,i)
            end do
 
-           if(amsua.or.atms) then
+           if(amsua.or.atms .or. mws) then
               call ret_amsua(tsim_bc,nchanl,tsavg5,zasat,clw_guess_retrieval,ierrret)
            else if(gmi) then
               call gmi_37pol_diff(tsim(6),tsim(7),tsim_clr(6),tsim_clr(7),clw_guess_retrieval,ierrret)
@@ -1288,6 +1300,11 @@ subroutine setuprad(obsLL,odiagLL,lunin,mype,aivals,stats,nchanl,nreal,nobs,&
                 id_qc(1:7) = ifail_cloud_qc
                 varinv(16:22)=zero
                 id_qc(16:22) = ifail_cloud_qc
+             else if (mws) then 
+                varinv(1:8)=zero
+                id_qc(1:8) = ifail_cloud_qc
+                varinv(17:24)=zero
+                id_qc(17:24) = ifail_cloud_qc
              else       
                 varinv(1:nchanl)=zero
                 id_qc(1:nchanl) = ifail_cloud_qc
@@ -1445,6 +1462,29 @@ subroutine setuprad(obsLL,odiagLL,lunin,mype,aivals,stats,nchanl,nreal,nobs,&
               pred,predchan,id_qc,aivals,errf,errf0,clw_obs,varinv,cldeff_obs,cldeff_fg,factch6, &
               cld_rbc_idx,sfc_speed,error0,clw_guess_retrieval,scatp,radmod)                   
 
+!  ---------- MWS ------------------- 
+!       QC MWS data (Using the QC for ATMS)
+
+        else if (mws) then
+
+           if (adp_anglebc) then
+              tb_obsbc1=tb_obs(1)-cbias(nadir,ich(1))-predx(1,ich(1))
+              tb_obsbc17=tb_obs(17)-cbias(nadir,ich(17))-predx(1,ich(17))
+              tb_obsbc18=tb_obs(18)-cbias(nadir,ich(18))-predx(1,ich(18))
+           else
+              tb_obsbc1=tb_obs(1)-cbias(nadir,ich(1))
+              tb_obsbc17=tb_obs(17)-cbias(nadir,ich(17))
+              tb_obsbc18=tb_obs(18)-cbias(nadir,ich(18))
+           end if
+           si_obs = (tb_obsbc17-tb_obsbc18) - (tsim_clr(17)-tsim_clr(18))
+           si_fg  = (tsim(17)-tsim(18)) - (tsim_clr(17)-tsim_clr(18))
+!          si_mean= half*(si_obs+si_fg) 
+
+           call qc_atms(nchanl,is,ndat,nsig,npred,sea,land,ice,snow,mixed,luse(n),    &
+              zsges,cenlat,tb_obsbc1,cosza,clw_obs,tbc,ptau5,emissivity_k,ts, & 
+              pred,predchan,id_qc,aivals,errf,errf0,clw_obs,varinv,cldeff_obs,cldeff_fg,factch6, &
+              cld_rbc_idx,sfc_speed,error0,clw_guess_retrieval,scatp,radmod)                   
+
 !  ---------- GOES imager --------------
 !       GOES imager Q C
 !
@@ -1634,9 +1674,16 @@ subroutine setuprad(obsLL,odiagLL,lunin,mype,aivals,stats,nchanl,nreal,nobs,&
                     else
                        errf(i) = min(three*errf(i),10.0_r_kind)
                     endif
+                 else if(radmod%rtype == 'mws' .and. (i <= 7 .or. i>=17) ) then
+                    if (radmod%lprecip) then
+                       errf(i) = min(2.5_r_kind*errf(i),10.0_r_kind)
+                    else
+                       errf(i) = min(three*errf(i),10.0_r_kind)
+                    endif
                  else if(radmod%rtype == 'gmi') then
                     errf(i) = min(2.0_r_kind*errf(i),ermax_rad(m))
-                 else if (radmod%rtype/='amsua' .and. radmod%rtype/='atms' .and. radmod%rtype/='gmi' .and. radmod%lcloud4crtm(i)>=0) then
+                 else if (radmod%rtype/='amsua' .and. radmod%rtype/='atms' .and. radmod%rtype/='gmi' .and. &
+                         radmod%rtype/='mws' .and. radmod%lcloud4crtm(i)>=0) then
                     errf(i) = three*errf(i)    
                  else 
                     errf(i) = min(three*errf(i),ermax_rad(m))
@@ -1661,11 +1708,13 @@ subroutine setuprad(obsLL,odiagLL,lunin,mype,aivals,stats,nchanl,nreal,nobs,&
            end if
         end do
 
-        if(amsua .or. atms .or. amsub .or. mhs .or. msu .or. hsb)then
+        if(amsua .or. atms .or. mws .or. amsub .or. mhs .or. msu .or. hsb)then
            if(amsua)then
               nlev=6
            else if(atms)then
               nlev=7
+           else if(mws)then
+              nlev=8
            else if(amsub .or. mhs)then
               nlev=5
            else if(hsb)then
@@ -1682,7 +1731,7 @@ subroutine setuprad(obsLL,odiagLL,lunin,mype,aivals,stats,nchanl,nreal,nobs,&
                  kval=max(i-1,kval)
                  if(amsub .or. hsb .or. mhs)then
                     kval=nlev
-                 else if((amsua .or. atms) .and. i <= 3) then
+                 else if((amsua .or. atms .or. mws) .and. i <= 3) then
                     kval = zero
                  end if
               end if
@@ -1700,6 +1749,11 @@ subroutine setuprad(obsLL,odiagLL,lunin,mype,aivals,stats,nchanl,nreal,nobs,&
                  if(id_qc(16) == igood_qc)id_qc(16)=ifail_interchan_qc
                  if(id_qc(17) == igood_qc)id_qc(17)=ifail_interchan_qc
                  if(id_qc(18) == igood_qc)id_qc(18)=ifail_interchan_qc
+              else if (mws) then
+                 varinv(17:19)=zero
+                 if(id_qc(17) == igood_qc)id_qc(17)=ifail_interchan_qc
+                 if(id_qc(18) == igood_qc)id_qc(18)=ifail_interchan_qc
+                 if(id_qc(19) == igood_qc)id_qc(19)=ifail_interchan_qc
               end if
            end if
 
@@ -1785,7 +1839,7 @@ subroutine setuprad(obsLL,odiagLL,lunin,mype,aivals,stats,nchanl,nreal,nobs,&
         account_for_corr_obs = .false.
         varinv0=zero
         raterr2 = zero
-!$omp parallel do  schedule(dynamic,1) private(ii,m,k,asum)
+!##!$omp parallel do  schedule(dynamic,1) private(ii,m,k,asum)
         do ii=1,nchanl
            m=ich(ii)
            if (varinv(ii)>tiny_r_kind .and. iuse_rad(m)>=1) then
diff --git a/src/gsi/sst_retrieval.f90 b/src/gsi/sst_retrieval.f90
index 97f1073a5..78d8c868d 100644
--- a/src/gsi/sst_retrieval.f90
+++ b/src/gsi/sst_retrieval.f90
@@ -86,7 +86,7 @@ subroutine setup_sst_retrieval(obstype,csatid,mype)
 
 ! Define parameters
   
-    character(10)  , intent(in   ) :: obstype,csatid
+    character(len=*), intent(in   ) :: obstype,csatid
     integer(i_kind), intent(in   ) :: mype
 
     integer(i_kind) i
@@ -173,7 +173,7 @@ subroutine avhrr_sst_retrieval(csatid,nchanl,&
          dtp_avh
     real(r_kind),dimension(nchanl)           , intent(in   ) :: ts
     real(r_kind),dimension(nsig,nchanl)      , intent(in   ) :: wmix,temp
-    character(10)                            , intent(in   ) :: csatid
+    character(len=*)                         , intent(in   ) :: csatid
     logical                                  , intent(in   ) :: duse
     real(r_kind)                             , intent(  out) :: sstph,dta,dqa
 
diff --git a/src/gsi/statsoz.f90 b/src/gsi/statsoz.f90
index fb5f53691..6a13c3d40 100644
--- a/src/gsi/statsoz.f90
+++ b/src/gsi/statsoz.f90
@@ -135,7 +135,7 @@ subroutine statsoz(stats_oz,ndata)
 1102 format(1x,i4,i4,1x,a20,2i7,1x,f8.3,1x,6(e11.4,1x))
 1109 format(t5,'it',t11,'sat',t22,'inst',t36,'# read',t46,'# keep',t55,'# assim',&
           t63,'penalty',t78,'cpen',t88,'qcpen',t101,'qcfail')
-1115 format('o-g',1x,i2.2,1x,'oz ',a10,1x,a10,1x,3(i9,1x),3(g12.5,1x),i8)
+1115 format('o-g',1x,i2.2,1x,'oz ',a11,1x,a10,1x,3(i9,1x),3(g12.5,1x),i8)
 
 ! End of ozone diagnostic print block.
 
diff --git a/src/gsi/statspcp.f90 b/src/gsi/statspcp.f90
index ad79aed67..eeca17a84 100644
--- a/src/gsi/statspcp.f90
+++ b/src/gsi/statspcp.f90
@@ -226,7 +226,7 @@ subroutine statspcp(aivals,ndata)
         endif
         write(iout_pcp,1102) dtype(is),dplat(is),isum,icerr,&
              aivals(16,is),aivals(13,is),aivals(15,is),aivals(14,is),sdv
-1102    format(a10,1x,a10,1x,2(i6,1x),6(g17.10,1x))
+1102    format(a10,1x,a11,1x,2(i6,1x),6(g17.10,1x))
      else
         rpen(is)   = zero
         qcpen(is)  = zero


Reviews:
user: login: RussTreadon-NOAA
body: Some comments
- Current suite of ctests do not cover this data type
- Exercising the functionality added by this PR needs updates to GSI-fix.  When will the required fix files be added?
- Advise against adding a date/time check in read_obs.F90
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T16:36:34Z
user: login: jianjunj
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T16:49:34Z
user: login: jianjunj
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T18:15:05Z
user: login: RussTreadon-NOAA
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T18:18:21Z
user: login: RussTreadon-NOAA
body: Looks good.  Minor nitpick request.
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T11:25:06Z
user: login: RussTreadon-NOAA
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T14:37:43Z
user: login: jianjunj
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T14:37:46Z
user: login: RussTreadon-NOAA
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T14:44:18Z
user: login: jianjunj
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T14:52:28Z
user: login: jianjunj
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T14:57:08Z
user: login: jianjunj
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T14:58:54Z
user: login: RussTreadon-NOAA
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T15:02:22Z
user: login: jianjunj
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T15:18:21Z
user: login: RussTreadon-NOAA
body: Please check for all uses of `dplat` or variables/subroutines into which `dplat` is assigned/passed.  For example, obs_para.f90 and statspcp.f90 print `dplat` via formatted writes.  The format statements use `A10` formatting.   `dplat` is now declared `character(11)`.
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-01T16:23:47Z
user: login: jianjunj
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-02T17:04:12Z
user: login: jianjunj
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-02T17:32:58Z
user: login: RussTreadon-NOAA
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-02T17:46:03Z
user: login: jianjunj
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-02T17:54:41Z
user: login: jianjunj
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-02T18:49:04Z
user: login: ShunLiu-NOAA
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-02T18:49:12Z
user: login: ADCollard
body: Thanks @jianjunj  and @RussTreadon-NOAA for all your hard work with this.   I think the removal of the omp statments in setuprad is acceptable.   The rest looks good too.

Approve.
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-02T19:37:51Z
user: login: emilyhcliu
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-02T20:43:38Z
user: login: RussTreadon-NOAA
body: Approve.
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T17:51:31Z
user: login: CoryMartin-NOAA
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T17:59:09Z
user: login: RussTreadon-NOAA
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T18:00:36Z
user: login: RussTreadon-NOAA
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T18:03:28Z
user: login: CoryMartin-NOAA
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T18:04:02Z
user: login: jianjunj
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T18:06:12Z

Review comments:
diff_hunk: @@ -213,8 +213,12 @@ subroutine read_obs_check (lexist,filename,jsatid,dtype,minuse,nread)
               write(6,*)'***read_obs_check analysis and data file date differ, but use anyway'
             else
                write(6,*)'***read_obs_check*** ',&
-                 'incompatable analysis and observation date/time',trim(filename),trim(dtype)
-               lexist=.false.
+                 'incompatable analysis and observation date/time ',trim(filename),' ', trim(dtype)
+               if (trim(dtype) == 'mws' .and. idate < 2025010100_i_kind) then
path: src/gsi/read_obs.F90
user: login: RussTreadon-NOAA
body: It's dangerous to put time based checks in the code.  These checks can be easily forgotten.  It is better to control what data is or is not processed by the GSI at script level and/or via fix files.
created_at: 2025-03-20T16:31:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -213,8 +213,12 @@ subroutine read_obs_check (lexist,filename,jsatid,dtype,minuse,nread)
               write(6,*)'***read_obs_check analysis and data file date differ, but use anyway'
             else
                write(6,*)'***read_obs_check*** ',&
-                 'incompatable analysis and observation date/time',trim(filename),trim(dtype)
-               lexist=.false.
+                 'incompatable analysis and observation date/time ',trim(filename),' ', trim(dtype)
+               if (trim(dtype) == 'mws' .and. idate < 2025010100_i_kind) then
path: src/gsi/read_obs.F90
user: login: jianjunj
body: I agree.
created_at: 2025-03-20T16:49:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -213,8 +213,12 @@ subroutine read_obs_check (lexist,filename,jsatid,dtype,minuse,nread)
               write(6,*)'***read_obs_check analysis and data file date differ, but use anyway'
             else
                write(6,*)'***read_obs_check*** ',&
-                 'incompatable analysis and observation date/time',trim(filename),trim(dtype)
-               lexist=.false.
+                 'incompatable analysis and observation date/time ',trim(filename),' ', trim(dtype)
+               if (trim(dtype) == 'mws' .and. idate < 2025010100_i_kind) then
path: src/gsi/read_obs.F90
user: login: jianjunj
body: Removed the check.
created_at: 2025-03-20T18:15:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -213,8 +213,12 @@ subroutine read_obs_check (lexist,filename,jsatid,dtype,minuse,nread)
               write(6,*)'***read_obs_check analysis and data file date differ, but use anyway'
             else
                write(6,*)'***read_obs_check*** ',&
-                 'incompatable analysis and observation date/time',trim(filename),trim(dtype)
-               lexist=.false.
+                 'incompatable analysis and observation date/time ',trim(filename),' ', trim(dtype)
+               if (trim(dtype) == 'mws' .and. idate < 2025010100_i_kind) then
path: src/gsi/read_obs.F90
user: login: RussTreadon-NOAA
body: Thanks!
created_at: 2025-03-20T18:18:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1231,7 +1231,7 @@ subroutine setuprad(obsLL,odiagLL,lunin,mype,aivals,stats,nchanl,nreal,nobs,&
 
         kmax = 0
         if (lwrite_peakwt .or. passive_bc) then
-!$omp parallel do  schedule(dynamic,1) private(i,k,ptau5derivmax,ptau5deriv)
+!**!$omp parallel do  schedule(dynamic,1) private(i,k,ptau5derivmax,ptau5deriv)
path: src/gsi/setuprad.f90
user: login: RussTreadon-NOAA
body: Nitpick.  Replace the four `!**` with `!` or `!##`.  We often use the asterisk as a wildcard character. 
created_at: 2025-04-29T11:24:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1231,7 +1231,7 @@ subroutine setuprad(obsLL,odiagLL,lunin,mype,aivals,stats,nchanl,nreal,nobs,&
 
         kmax = 0
         if (lwrite_peakwt .or. passive_bc) then
-!$omp parallel do  schedule(dynamic,1) private(i,k,ptau5derivmax,ptau5deriv)
+!**!$omp parallel do  schedule(dynamic,1) private(i,k,ptau5derivmax,ptau5deriv)
path: src/gsi/setuprad.f90
user: login: RussTreadon-NOAA
body: Addressed by [53adef8](https://github.com/NOAA-EMC/GSI/pull/844/commits/53adef8deafb2eaf96df7e3b4b953554988c2f8f)
created_at: 2025-04-29T14:37:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1231,7 +1231,7 @@ subroutine setuprad(obsLL,odiagLL,lunin,mype,aivals,stats,nchanl,nreal,nobs,&
 
         kmax = 0
         if (lwrite_peakwt .or. passive_bc) then
-!$omp parallel do  schedule(dynamic,1) private(i,k,ptau5derivmax,ptau5deriv)
+!**!$omp parallel do  schedule(dynamic,1) private(i,k,ptau5derivmax,ptau5deriv)
path: src/gsi/setuprad.f90
user: login: jianjunj
body: Done.  Thanks.
created_at: 2025-04-29T14:37:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1231,7 +1231,7 @@ subroutine setuprad(obsLL,odiagLL,lunin,mype,aivals,stats,nchanl,nreal,nobs,&
 
         kmax = 0
         if (lwrite_peakwt .or. passive_bc) then
-!$omp parallel do  schedule(dynamic,1) private(i,k,ptau5derivmax,ptau5deriv)
+!**!$omp parallel do  schedule(dynamic,1) private(i,k,ptau5derivmax,ptau5deriv)
path: src/gsi/setuprad.f90
user: login: RussTreadon-NOAA
body: Thank you @jianjunj 
created_at: 2025-04-29T14:44:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -804,6 +806,7 @@ subroutine setuprad(obsLL,odiagLL,lunin,mype,aivals,stats,nchanl,nreal,nobs,&
      if(in_curbin) then
 
         id_qc = igood_qc
+!       varinv = zero
path: src/gsi/setuprad.f90
user: login: jianjunj
body: Just want to leave a note:  Results would change if varinv was initialized by zero here. It is not expected to have an impact since it is initialized after call_crtm() (at line 991 and 994).    
created_at: 2025-04-29T14:52:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1051,12 +1054,12 @@ subroutine setuprad(obsLL,odiagLL,lunin,mype,aivals,stats,nchanl,nreal,nobs,&
         cldeff_obs=zero 
         cldeff_fg=zero  
         if(microwave .and. sea) then 
-           if(radmod%lcloud_fwd .and. (amsua .or. atms)) then
-              call ret_amsua(tb_obs,nchanl,tsavg5,zasat,clw_obs,ierrret,scat)
+           if(radmod%lcloud_fwd .and. (amsua .or. atms .or. mws)) then
+              call ret_amsua(tb_obs,nchanl,tsavg5,zasat,clw_obs,ierrret,scat=scat)
               scatp=scat 
            else
               call calc_clw(nadir,tb_obs,tsim,ich,nchanl,no85GHz,amsua,ssmi,ssmis,amsre,atms, &
-                   amsr2,gmi,saphir,tsavg5,sfc_speed,zasat,clw_obs,tpwc_obs,gwp,kraintype,ierrret)
+                   mws,amsr2,gmi,saphir,tsavg5,sfc_speed,zasat,clw_obs,tpwc_obs,gwp,kraintype,ierrret)
            end if
 
            if (ierrret /= 0) then
path: src/gsi/setuprad.f90
user: login: jianjunj
body: Another note: Results change in control had I added a simple print out like "write(6,*)". It is out of the OpenMP block. 
created_at: 2025-04-29T14:57:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -804,6 +806,7 @@ subroutine setuprad(obsLL,odiagLL,lunin,mype,aivals,stats,nchanl,nreal,nobs,&
      if(in_curbin) then
 
         id_qc = igood_qc
+!       varinv = zero
path: src/gsi/setuprad.f90
user: login: jianjunj
body: I meant results could change in the control experiment without any changes related with MWS.  
created_at: 2025-04-29T14:58:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -804,6 +806,7 @@ subroutine setuprad(obsLL,odiagLL,lunin,mype,aivals,stats,nchanl,nreal,nobs,&
      if(in_curbin) then
 
         id_qc = igood_qc
+!       varinv = zero
path: src/gsi/setuprad.f90
user: login: RussTreadon-NOAA
body: A note in a PR will not be seen by many developers.  Is it correct to set `varinnv = zero` here?  If this is the correct thing to do, uncomment and set `varinv = zero`.  If this is not the correct thing to do or is not needed, remove the line.
created_at: 2025-04-29T15:02:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -804,6 +806,7 @@ subroutine setuprad(obsLL,odiagLL,lunin,mype,aivals,stats,nchanl,nreal,nobs,&
      if(in_curbin) then
 
         id_qc = igood_qc
+!       varinv = zero
path: src/gsi/setuprad.f90
user: login: jianjunj
body: I cannot say it is correct or not correct. It is supposed to have no impact. I was kind of just throwing an initialization before calling CRTM.  Does anyone have a comment?  I will remove it if it is not helping us.      
created_at: 2025-04-29T15:18:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -268,6 +270,7 @@ $nln $datobs/${prefix_obs}.esatms.${suffix}        ./atmsbufrears
 # Do not process
 ## $nln $datobs/${prefix_obs}.amsre.${suffix}      ./amsrebufr
 ## $nln $datobs/${prefix_obs}.amsr2.tm00.bufr_d    ./amsr2bufr
+## $nln $datobs/${prefix_obs}.mws.${suffix}        ./mwsbufr
path: regression/global_4denvar.sh
user: login: RussTreadon-NOAA
body: We should uncomment this line and move it up to the microwave observation section.  Then `global_4denvar.sh` is ready when we update to a new case including mws data.
created_at: 2025-05-01T16:04:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -289,6 +289,7 @@ SATINFO=${fixgsi}/global_satinfo.txt
 OZINFO=${fixgsi}/global_ozinfo.txt
 PCPINFO=${fixgsi}/global_pcpinfo.txt
 ATMS_BEAMWIDTH=${fixgsi}/atms_beamwidth.txt
+MWS_BEAMWIDTH=${fixgsi}/mws_beamwidth.txt
path: regression/rrfs_3denvar_rdasens.sh
user: login: RussTreadon-NOAA
body: Don't we need to add mws lines to `obs_files_source` and `obs_files_target` above?  Once we have mws dump files, this script needs to get the data into the run directory.
created_at: 2025-05-01T16:10:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -268,6 +270,7 @@ $nln $datobs/${prefix_obs}.esatms.${suffix}        ./atmsbufrears
 # Do not process
 ## $nln $datobs/${prefix_obs}.amsre.${suffix}      ./amsrebufr
 ## $nln $datobs/${prefix_obs}.amsr2.tm00.bufr_d    ./amsr2bufr
+## $nln $datobs/${prefix_obs}.mws.${suffix}        ./mwsbufr
path: regression/global_4denvar.sh
user: login: jianjunj
body: Agree.
created_at: 2025-05-02T17:04:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -289,6 +289,7 @@ SATINFO=${fixgsi}/global_satinfo.txt
 OZINFO=${fixgsi}/global_ozinfo.txt
 PCPINFO=${fixgsi}/global_pcpinfo.txt
 ATMS_BEAMWIDTH=${fixgsi}/atms_beamwidth.txt
+MWS_BEAMWIDTH=${fixgsi}/mws_beamwidth.txt
path: regression/rrfs_3denvar_rdasens.sh
user: login: jianjunj
body: Frankly to say, I don't know what I should add in those testing files for regional models. 
created_at: 2025-05-02T17:32:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -289,6 +289,7 @@ SATINFO=${fixgsi}/global_satinfo.txt
 OZINFO=${fixgsi}/global_ozinfo.txt
 PCPINFO=${fixgsi}/global_pcpinfo.txt
 ATMS_BEAMWIDTH=${fixgsi}/atms_beamwidth.txt
+MWS_BEAMWIDTH=${fixgsi}/mws_beamwidth.txt
path: regression/rrfs_3denvar_rdasens.sh
user: login: RussTreadon-NOAA
body: Let's ask @ShunLiu-NOAA if GSI-based RRFS will assimilate this data type.  If "no", revert the changes to  `regression/rrfs_3denvar_rdasens.sh`.  If "yes", we should be forward looking and update the script to process mws data.
created_at: 2025-05-02T17:46:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -289,6 +289,7 @@ SATINFO=${fixgsi}/global_satinfo.txt
 OZINFO=${fixgsi}/global_ozinfo.txt
 PCPINFO=${fixgsi}/global_pcpinfo.txt
 ATMS_BEAMWIDTH=${fixgsi}/atms_beamwidth.txt
+MWS_BEAMWIDTH=${fixgsi}/mws_beamwidth.txt
path: regression/rrfs_3denvar_rdasens.sh
user: login: jianjunj
body: Right.  @ShunLiu-NOAA Can you take a look and let us know whether we should add MWS observations in `regression/rrfs_3denvar_rdasens.sh`?  Thank you both.
created_at: 2025-05-02T17:54:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -289,6 +289,7 @@ SATINFO=${fixgsi}/global_satinfo.txt
 OZINFO=${fixgsi}/global_ozinfo.txt
 PCPINFO=${fixgsi}/global_pcpinfo.txt
 ATMS_BEAMWIDTH=${fixgsi}/atms_beamwidth.txt
+MWS_BEAMWIDTH=${fixgsi}/mws_beamwidth.txt
path: regression/rrfs_3denvar_rdasens.sh
user: login: jianjunj
body: @RussTreadon-NOAA  I added links to `mwsbufr` in `regression/rrfs_3denvar_rdasens.sh` after  a quick chat with @ShunLiu-NOAA.
created_at: 2025-05-02T18:49:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -289,6 +289,7 @@ SATINFO=${fixgsi}/global_satinfo.txt
 OZINFO=${fixgsi}/global_ozinfo.txt
 PCPINFO=${fixgsi}/global_pcpinfo.txt
 ATMS_BEAMWIDTH=${fixgsi}/atms_beamwidth.txt
+MWS_BEAMWIDTH=${fixgsi}/mws_beamwidth.txt
path: regression/rrfs_3denvar_rdasens.sh
user: login: ShunLiu-NOAA
body: Looks good to me. Thank you @jianjunj 
created_at: 2025-05-02T18:49:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -268,6 +270,7 @@ $nln $datobs/${prefix_obs}.esatms.${suffix}        ./atmsbufrears
 # Do not process
 ## $nln $datobs/${prefix_obs}.amsre.${suffix}      ./amsrebufr
 ## $nln $datobs/${prefix_obs}.amsr2.tm00.bufr_d    ./amsr2bufr
+$nln $datobs/${prefix_obs}.mws.${suffix}        ./mwsbufr
path: regression/global_4denvar.sh
user: login: CoryMartin-NOAA
body: Pedantic, but should this be after `atmsbufrears`? because at first glance this is in the "do not process" section
created_at: 2025-05-06T17:59:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -268,6 +270,7 @@ $nln $datobs/${prefix_obs}.esatms.${suffix}        ./atmsbufrears
 # Do not process
 ## $nln $datobs/${prefix_obs}.amsre.${suffix}      ./amsrebufr
 ## $nln $datobs/${prefix_obs}.amsr2.tm00.bufr_d    ./amsr2bufr
+$nln $datobs/${prefix_obs}.mws.${suffix}        ./mwsbufr
path: regression/global_4denvar.sh
user: login: RussTreadon-NOAA
body: Good catch @CoryMartin-NOAA .  The mwsbufr line should be moved up.
created_at: 2025-05-06T18:00:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -268,6 +270,7 @@ $nln $datobs/${prefix_obs}.esatms.${suffix}        ./atmsbufrears
 # Do not process
 ## $nln $datobs/${prefix_obs}.amsre.${suffix}      ./amsrebufr
 ## $nln $datobs/${prefix_obs}.amsr2.tm00.bufr_d    ./amsr2bufr
+$nln $datobs/${prefix_obs}.mws.${suffix}        ./mwsbufr
path: regression/global_4denvar.sh
user: login: RussTreadon-NOAA
body: @CoryMartin-NOAA , the line has been moved as of [d4b8bf4](https://github.com/NOAA-EMC/GSI/pull/844/commits/d4b8bf42b7e01a90a6a42023a7a5dd41281a059b)
created_at: 2025-05-06T18:03:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -268,6 +270,7 @@ $nln $datobs/${prefix_obs}.esatms.${suffix}        ./atmsbufrears
 # Do not process
 ## $nln $datobs/${prefix_obs}.amsre.${suffix}      ./amsrebufr
 ## $nln $datobs/${prefix_obs}.amsr2.tm00.bufr_d    ./amsr2bufr
+$nln $datobs/${prefix_obs}.mws.${suffix}        ./mwsbufr
path: regression/global_4denvar.sh
user: login: jianjunj
body: Thank you both.
created_at: 2025-05-06T18:06:12Z
author_association: CONTRIBUTOR

PR comments:
user: login: jianjunj
created_at: 2025-03-19T03:25:39Z
body: I cannot say there is zero-diff, though I don't expect this PR causes any differences since no proxy or real MWS data are processed in the ctests.
author_association: CONTRIBUTOR
user: login: RussTreadon-NOAA
created_at: 2025-03-19T10:29:23Z
body: @jianjunj , on which machine were ctests run?
author_association: CONTRIBUTOR
user: login: jianjunj
created_at: 2025-03-19T12:40:32Z
body: @RussTreadon-NOAA  It is Orion.
author_association: CONTRIBUTOR
user: login: jianjunj
created_at: 2025-03-20T17:42:28Z
body: @RussTreadon-NOAA 
> Current suite of ctests do not cover this data type

Right. There aren't real data to do the tests. The satellite is planed to be launched in this fall.
author_association: CONTRIBUTOR
user: login: RussTreadon-NOAA
created_at: 2025-03-20T18:51:35Z
body: **Hera ctests**

Install `jianjunj:feature/initial_metop-sg-a1_mws` at 405b00cb and `develop` at 33012bcc.  Run ctests with following results
```
Test project /scratch1/NCEPDEV/da/Russ.Treadon/git/gsi/pr844/build
    Start 1: global_4denvar
    Start 2: rtma
    Start 3: rrfs_3denvar_rdasens
    Start 4: hafs_4denvar_glbens
    Start 5: hafs_3denvar_hybens
    Start 6: global_enkf
1/6 Test #3: rrfs_3denvar_rdasens .............   Passed  2483.64 sec
2/6 Test #6: global_enkf ......................   Passed  4307.89 sec
3/6 Test #1: global_4denvar ...................   Passed  6250.88 sec
4/6 Test #5: hafs_3denvar_hybens ..............   Passed  8486.52 sec
5/6 Test #4: hafs_4denvar_glbens ..............   Passed  8643.46 sec
6/6 Test #2: rtma .............................   Passed  9560.97 sec

100% tests passed, 0 tests failed out of 6

Total Test time (real) = 9561.00 sec
```

All tests pass.  This is an expected result because Metop-SG-a1 MWS dump files are not available for the ctest cases.
author_association: CONTRIBUTOR
user: login: RussTreadon-NOAA
created_at: 2025-03-21T10:43:05Z
body: **Hercules ctests**
nstall jianjunj:feature/initial_metop-sg-a1_mws at https://github.com/NOAA-EMC/GSI/commit/405b00cb1f2f29f3c98a6f858367795cf66a3c4a and develop at https://github.com/NOAA-EMC/GSI/commit/33012bcc9dfc053d33fd4713f9cd1e15c4513d59. Run ctests with following results
```
Test project /work/noaa/da/rtreadon/git/gsi/pr844/build
    Start 1: global_4denvar
    Start 2: rtma
    Start 3: rrfs_3denvar_rdasens
    Start 4: hafs_4denvar_glbens
    Start 5: hafs_3denvar_hybens
    Start 6: global_enkf
1/6 Test #3: rrfs_3denvar_rdasens .............***Failed  6428.51 sec
2/6 Test #6: global_enkf ......................   Passed  18496.88 sec
3/6 Test #5: hafs_3denvar_hybens ..............   Passed  20108.16 sec
4/6 Test #4: hafs_4denvar_glbens ..............   Passed  20113.52 sec
5/6 Test #2: rtma .............................   Passed  20406.74 sec
6/6 Test #1: global_4denvar ...................   Passed  21425.99 sec

83% tests passed, 1 tests failed out of 6

Total Test time (real) = 21425.99 sec

The following tests FAILED:
          3 - rrfs_3denvar_rdasens (Failed)
```

The `rrfs_3denvar_rdasens` failure is due to
```
The memory for rrfs_3denvar_rdasens_loproc_updat is 1112824 KBs.  This has exceeded maximum allowable memory of 1088661 KBs,
resulting in Failure memthresh of the regression test.
```
This is not a fatal fail.  The memory check is not a robust test since it only reports task 0 memory usage.
author_association: CONTRIBUTOR
user: login: RussTreadon-NOAA
created_at: 2025-03-21T10:58:08Z
body: **Hercules rrfs_3denvar_rdasens**

Update and recompile `develop` at b25de8c8 and `jianjunj:feature/initial_metop-sg-a1_mws` at fbeea03e.  Rerun `rrfs_3denvar_rdasens` test with following results  
```
Test project /work/noaa/da/rtreadon/git/gsi/pr844/build
    Start 3: rrfs_3denvar_rdasens
1/1 Test #3: rrfs_3denvar_rdasens .............   Passed  549.59 sec

100% tests passed, 0 tests failed out of 1

Total Test time (real) = 549.61 sec
```

This _Passed_  result for this and other tests is expected.  This PR does not alter existing functionality.  It adds the ability to process a new observation type. This observation type is not yet routinely available.

author_association: CONTRIBUTOR
user: login: RussTreadon-NOAA
created_at: 2025-03-21T13:45:43Z
body: **WCOSS2 ctests**

Install `develop` at b25de8c8 and `jianjunj:feature/initial_metop-sg-a1_mws` at fbeea03e on Dogwood.  Run ctests with the following results
```
Test project /lfs/h2/emc/da/noscrub/russ.treadon/git/gsi/pr844/build
    Start 1: global_4denvar
    Start 2: rtma
    Start 3: rrfs_3denvar_rdasens
    Start 4: hafs_4denvar_glbens
    Start 5: hafs_3denvar_hybens
    Start 6: global_enkf
1/6 Test #3: rrfs_3denvar_rdasens .............***Failed  731.58 sec
2/6 Test #6: global_enkf ......................   Passed  858.72 sec
3/6 Test #2: rtma .............................   Passed  1035.02 sec
4/6 Test #5: hafs_3denvar_hybens ..............***Failed  1221.05 sec
5/6 Test #4: hafs_4denvar_glbens ..............***Failed  1342.26 sec
6/6 Test #1: global_4denvar ...................***Failed  1804.11 sec

33% tests passed, 4 tests failed out of 6

Total Test time (real) = 1804.34 sec

The following tests FAILED:
          1 - global_4denvar (Failed)
          3 - rrfs_3denvar_rdasens (Failed)
          4 - hafs_4denvar_glbens (Failed)
          5 - hafs_3denvar_hybens (Failed)
```
Each of the tests failed due to
```
The results (penalty) between the two runs are nonreproducible,
thus the regression test has Failed on cost for hafs_3denvar_hybens_loproc_updat and hafs_3denvar_hybens_loproc_\
contrl analyses.
```
Comparison of the _updat_ (`jianjunj:feature/initial_metop-sg-a1_mws`) and _contrl_ (`develop`) show that while the initial penalty an gradient norm are identical to the printed 19 digits, the first step size differs in the 15th or 16th digit.  This difference accumulates so that by the end of the second outer loop only the first few (2 to 5) digits in the total penalty are identical.  For rrfs_3denvar_rdasens the final total penalties agree to 15 digits.

It is interesting that results are reproducible on Hera, Hercules, and Orion but differ on Dogwood.  The RDHPCS builds use newer versions of the intel compiler and spack-stack installed libraries.  The WCOSS2 build uses an older intel compiler (19.1.3.304) with hpc-stack installed libraries.

We need to better understand the observed WCOSS2 differences.  The changes in this PR should **_not_**  alter GSI results.
author_association: CONTRIBUTOR
user: login: RussTreadon-NOAA
created_at: 2025-03-24T12:48:46Z
body: **WCOSS2 global_4denvar test**

As a test, replace `setuprad.f90` from `jianjunj:feature/initial_metop-sg-a1_mws` with `develop` `setuprad.f90`.  

Make the following changes to the `devlop` copy of  `setuprad.f90`
- add logical `mws`
- set `mws = .false.`
- add `mws` to `call calc_clw` argument list

Rebuild `gsi.x` and run `ctest -R global_4denar`.  The ctest passed.  
```
Test project /lfs/h2/emc/da/noscrub/russ.treadon/git/gsi/test/build
    Start 1: global_4denvar
1/1 Test #1: global_4denvar ...................   Passed  1803.31 sec

100% tests passed, 0 tests failed out of 1

Total Test time (real) = 1803.33 sec
```
We should take a closer look at the changes this PR makes to to `setuprad.f90`. 


author_association: CONTRIBUTOR
user: login: RussTreadon-NOAA
created_at: 2025-03-24T17:51:34Z
body: **WCOSS2 omp test**

`setuprad.f90` contains four `!$omp parallel do` loops.  Comment out the four `!$omp parallel do` directives in `setuprad.f90` in both working copies of `develop` and `initial_metop-sg-a1_mws`.  Recompile both working copies and rerun ctests on Dogwood.
```
Test project /lfs/h2/emc/da/noscrub/russ.treadon/git/gsi/test/build
    Start 1: global_4denvar
    Start 2: rtma
    Start 3: rrfs_3denvar_rdasens
    Start 4: hafs_4denvar_glbens
    Start 5: hafs_3denvar_hybens
    Start 6: global_enkf
1/6 Test #3: rrfs_3denvar_rdasens .............   Passed  733.70 sec
2/6 Test #6: global_enkf ......................   Passed  859.61 sec
3/6 Test #2: rtma .............................   Passed  1035.69 sec
4/6 Test #5: hafs_3denvar_hybens ..............   Passed  1223.31 sec
5/6 Test #4: hafs_4denvar_glbens ..............   Passed  1342.58 sec
6/6 Test #1: global_4denvar ...................   Passed  1924.15 sec

100% tests passed, 0 tests failed out of 6

Total Test time (real) = 1924.17 sec
```

Interesting result.  Why / how does **_deactivating_** `!$omp` directives have this impact on WCOSS2?
author_association: CONTRIBUTOR
user: login: jianjunj
created_at: 2025-03-25T03:09:41Z
body: There are some minor updates in the reader "read_mws.f90" in addition to adding "mws" into the radiance data type list in radiance_mod.f90.
author_association: CONTRIBUTOR
user: login: jianjunj
created_at: 2025-03-25T14:12:43Z
body: > **WCOSS2 global_4denvar test**
> 
> As a test, replace `setuprad.f90` from `jianjunj:feature/initial_metop-sg-a1_mws` with `develop` `setuprad.f90`.
> 
> Make the following changes to the `devlop` copy of `setuprad.f90`
> 
> * add logical `mws`
> * set `mws = .false.`
> * add `mws` to `call calc_clw` argument list
> 
> We should take a closer look at the changes this PR makes to to `setuprad.f90`.

There are undefined cloud values in the subroutine "calc_clw" for "mhs" observations and the old data types "amsub, msu  and hsb", which is a bit dangerous since Fortran doesnot always return zeros for them. See https://github.com/jianjunj/GSI/blob/develop/src/gsi/clw_mod.f90#L112-113

In addition, the returned "clw_obs" is used for bias correction in MHS observations. https://github.com/jianjunj/GSI/blob/develop/src/gsi/setuprad.f90#L1131.  Is there anything missing in handling MHS data?  @ADCollard @emilyhcliu 

author_association: CONTRIBUTOR
user: login: RussTreadon-NOAA
created_at: 2025-04-01T12:16:35Z
body: **WCOSS2 update**

Unable, thus far, to get `gsi.x` built from `jianjunj:feature/initial_metop-sg-a1_mws` at [`1a67992`](https://github.com/jianjunj/GSI/commit/1a67992dd0909d698002625978846ab17db707af) to reproduce `develop gsi.x` on Dogwood in global_4denvar ctest.

There are four `!$omp parallel do` sections in `src/gsi/setuprad.f90`.  If the four `!$omp parallel do` directives are commented out in `develop` and `jianjunj:feature/initial_metop-sg-a1_mws` `setuprad.f90`, the resulting `gsi.x` yield identical results in the global_4denvar ctest.  

As expected the `develop gsi.x` yields identical global_4denvar results whether `!$omp parallel do` directives are present or absent in `setuprad.f90`.

If we can not figure out how to get  `jianjunj:feature/initial_metop-sg-a1_mws setuprad.f90` to reproduce `develop`, one option to consider is to remove all or some of the `!$omp parallel do` sections from `jianjunj:feature/initial_metop-sg-a1_mws setuprad.f90`.  Care must be done in doing so.  We need to ensure that the `gsi.x` wall time does not significantly increase as `!$omp parallel do` sections are removed.
author_association: CONTRIBUTOR
user: login: RussTreadon-NOAA
created_at: 2025-04-01T14:32:46Z
body: **Dogwood test**

Build `develop` and `jianjunj:feature/initial_metop-sg-a1_mws gsi.x` with and without omp directives in `setuprad.f90`.  Run `gsi.x` for 20250401 00Z GFS and GDAS cycles.  All jobs ran `gsi.x` with 780 tasks on 52 nodes, ppn=15, threads=8.  Below are `gsi.x` wall times for various configurations

|                               | `develop`     | `jianjunj:feature/initial_metop-sg-a1_mws` |
| -------------------- | :--------: | :-----------:  |
| gfs with omp         |  1913.131444 |  1912.957237 | 
| gfs without omp   |   1944.277022 |  1917.032215 |
| gdas with omp      |  2422.959107  | 2413.466572  |
| gdas without omp |  2424.081064  | 2410.864379 |

Apart from the `develop` gfs runs the wall time impact of including or removing omp directives from `setuprad.f90` is not significant.
author_association: CONTRIBUTOR
user: login: RussTreadon-NOAA
created_at: 2025-04-01T18:15:22Z
body: @jianjunj , I am standing down on this PR for the time being to give you and others time to 
- look more closely at `setuprad.f90` to see if you see any threading errors
- see if you can develop modifications to `setuprad.f90` that allow it to reproduce `develop`
- consider if removing `!$ omp parallel` from `setuprad.f90` is a viable option

Please member to keep `jianjunj:feature/initial_metop-sg-a1_mws` in sync with the current head of `develop`.  As of 4/1/2025 `jianjunj:feature/initial_metop-sg-a1_mws` is 4 commits behind the head of `develop`.
author_association: CONTRIBUTOR
user: login: jianjunj
created_at: 2025-04-01T18:27:53Z
body: @RussTreadon-NOAA Thank you very much for these tests. Yes, I am actually working on this issue. Finally got an account on WCOSS2 last week and built the GSI on it the morning.  I am running the ctest now and will update on what I get.  
author_association: CONTRIBUTOR
user: login: RussTreadon-NOAA
created_at: 2025-04-09T10:56:22Z
body: Notice that `setuprad.f90` in operational gfsda.v16.3.23 does **not** contain omp directives.  If we can not figure out how to modify `jianjunj:feature/initial_metop-sg-a1_mws` such that it reproduces `develop` on WCOSS2, we should consider removing the omp directives from `jianjunj:feature/initial_metop-sg-a1_mws setuprad.f90`.
author_association: CONTRIBUTOR
user: login: jianjunj
created_at: 2025-04-09T17:57:27Z
body: Thank you @RussTreadon-NOAA . I haven't figured out why the ctests fails on WCOSS2 even though spent quit some time on it.  Anyway, I am going to add some updates after running the tests. 
author_association: CONTRIBUTOR
user: login: jianjunj
created_at: 2025-04-10T17:47:28Z
body: Still testing on WCOSS2, but all ctests pass on Hera and Hecules.  Here are ctest results on Hera:
```
[Jianjun.Jin@hfe05 build]$ cat ctest.log 
Test project /scratch1/NCEPDEV/da/Jianjun.Jin/git/GSI_JianjunJin/build
    Start 1: global_4denvar
    Start 2: rtma
    Start 3: rrfs_3denvar_rdasens
    Start 4: hafs_4denvar_glbens
    Start 5: hafs_3denvar_hybens
    Start 6: global_enkf
1/6 Test #3: rrfs_3denvar_rdasens .............   Passed  800.77 sec
2/6 Test #6: global_enkf ......................   Passed  1116.86 sec
3/6 Test #5: hafs_3denvar_hybens ..............   Passed  2309.72 sec
4/6 Test #4: hafs_4denvar_glbens ..............   Passed  2367.23 sec
5/6 Test #1: global_4denvar ...................   Passed  3184.46 sec
6/6 Test #2: rtma .............................   Passed  6132.50 sec

100% tests passed, 0 tests failed out of 6

Total Test time (real) = 6132.53 sec

```
author_association: CONTRIBUTOR
user: login: jianjunj
created_at: 2025-04-10T17:50:10Z
body: Here is the ctest log on Hercules:
```
[jianjun@hercules-login-2 build]$ cat ctest.log 
Test project /work2/noaa/da/jianjun/git/GSI_forked/build
    Start 1: global_4denvar
    Start 2: rtma
    Start 3: rrfs_3denvar_rdasens
    Start 4: hafs_4denvar_glbens
    Start 5: hafs_3denvar_hybens
    Start 6: global_enkf
1/6 Test #3: rrfs_3denvar_rdasens .............   Passed  724.92 sec
2/6 Test #2: rtma .............................   Passed  1145.44 sec
3/6 Test #6: global_enkf ......................   Passed  1302.78 sec
4/6 Test #5: hafs_3denvar_hybens ..............   Passed  1448.89 sec
5/6 Test #4: hafs_4denvar_glbens ..............   Passed  1517.46 sec
6/6 Test #1: global_4denvar ...................   Passed  1955.59 sec

100% tests passed, 0 tests failed out of 6

Total Test time (real) = 1955.59 sec
```

author_association: CONTRIBUTOR
user: login: RussTreadon-NOAA
created_at: 2025-04-10T18:07:34Z
body: Thank you @jianjunj for these tests. Your results are consistent with previous tests.  We never had any problems on RDHPCS machines.  The WCOSS2 ctest is the problem.  

As mentioned before, the WCOSS@ ctests pass if we remove the 4 omp directives from `setuprad.f90` in jianjunj:feature/initial_metop-sg-a1_mws.  I repeated this test on Cactus.  Same result - the ctests pass.
```
Test project /lfs/h2/emc/da/noscrub/russ.treadon/git/gsi/pr844/build
    Start 1: global_4denvar
    Start 2: rtma
    Start 3: rrfs_3denvar_rdasens
    Start 4: hafs_4denvar_glbens
    Start 5: hafs_3denvar_hybens
    Start 6: global_enkf
1/6 Test #3: rrfs_3denvar_rdasens .............   Passed  734.33 sec
2/6 Test #6: global_enkf ......................   Passed  857.10 sec
3/6 Test #2: rtma .............................   Passed  1035.66 sec
4/6 Test #5: hafs_3denvar_hybens ..............   Passed  1226.31 sec
5/6 Test #4: hafs_4denvar_glbens ..............   Passed  1290.66 sec
6/6 Test #1: global_4denvar ...................   Passed  1865.28 sec

100% tests passed, 0 tests failed out of 6

Total Test time (real) = 1865.41 sec
```
So we need to discuss & decide whether or not we are OK with remove the omp directives from `setuprad.f90`.  Before doing so we should make some operational and C1152 gsi.x runs to ensure removing the omp directives does not adversely impact gsi.x wall time at high resolution.

author_association: CONTRIBUTOR
user: login: jianjunj
created_at: 2025-04-11T21:02:33Z
body: @RussTreadon-NOAA  Let me give you an update on Monday.  Still trying to understand why. :(
author_association: CONTRIBUTOR
user: login: jianjunj
created_at: 2025-04-15T15:25:49Z
body: Hi all, after spending quite a lot time try to find out the reason why Ctests fail on WCOSS2, I give up my hope. :(. Here is what I found.  Ctests fail once I add these lines in setuprad.f90:
https://github.com/NOAA-EMC/GSI/blob/1289a2e17b3cb8c91591d984882aa55180187b1b/src/gsi/setuprad.f90#L1075-L1079   
There is no parallel reading for MWS data and GSI does not even try to read MWS after finding its BUFR file is unavailable.

I'd like to take @RussTreadon-NOAA 's suggestion to take off the "$omp parallel" line in setuprad.f90. Any comments?
  

author_association: CONTRIBUTOR
user: login: emilyhcliu
created_at: 2025-04-15T22:10:00Z
body: How about removing the $omp one by one and checking which omp setting is causing the problem?  
author_association: CONTRIBUTOR
user: login: RussTreadon-NOAA
created_at: 2025-04-18T17:41:47Z
body: @emilyhcliu :  I made the [test you suggested](https://github.com/NOAA-EMC/GSI/pull/844#issuecomment-2807639703) using the global_4denvar loproc_updat test.  

`gsi.x` was built four times from `jianjunj:feature/initial_metop-sg-a1_mws` .  Each build turned off a different `!$omp parallel` directive in `setuprad.f90`.  Interestingly, the analysis increments produced from all four runs are bitwise identical.   Each run matches the run in which all 4 `!$omp parallel` directives are active.  **None** of these configurations match the control using the `develop gsi.x`.

As a final test all four `!$omp parallel` directives were turned off in `setuprad.f90`.  The analysis increments from this run are bitwise identical to those from the `develop gsi.x`.

One could go through the various combinations of turning off 2 or 3 `!$omp parallel` directives.  Doing so would take some time.

As an aside, debug builds of `gsi.x` on WCOSS2 generate the following warning from `setuprad.f90`
```
[ 85%] Building Fortran object src/gsi/CMakeFiles/gsi_fortran_obj.dir/setuprad.f90.o
/lfs/h2/emc/da/noscrub/russ.treadon/git/gsi/pr844/src/gsi/setuprad.f90(8): warning #16219: Some OpenMP processing was skipped to constrain compile time. Consider overriding limits (-qoverride-limits).
```
I have not explored this option to see if this changes the behavior of `gsi.x` built from `develop` or `jianjunj:feature/initial_metop-sg-a1_mws`

author_association: CONTRIBUTOR
user: login: RussTreadon-NOAA
created_at: 2025-04-18T19:30:57Z
body: **-qoverride-limits test**

The suggested compiler option, `-qoverride-limits`, was added to `CMAKE_Fortran_FLAGS` in `src/gsi/cmake/gsiapp_compiler_flags_Intel_Fortran.cmake`.   `gsi.x` was built.  The build took 43:46 (minutes:seconds) to complete.   Without `-qoverride-limits the build takes 12:06.

Unfortunately, including `-qoverride-limits` in the build of `jianjunj:feature/initial_metop-sg-a1_mws` did not yield results which reproduce `develop` `gsi.x` built with the same option.  

Analysis increments do **not** change whether `develop` is build with or without `-qoverride-limits`.   `develop` reproduces `develop` and `jianjunj:feature/initial_metop-sg-a1_mws` reproduces `jianjunj:feature/initial_metop-sg-a1_mws`.
author_association: CONTRIBUTOR
user: login: jianjunj
created_at: 2025-04-21T04:19:34Z
body: Thank you @RussTreadon-NOAA.  I am afraid that my changes about MWS break GSI at some subroutines but not actually in setuprad.f90.  That's is just my guess. I had a test using the same files in ./fix  in order to make sure I use the same data. That test failed on SCOSS2.  I am sorry I have no clue.  I have to think about it too after I come back from PTO.  
author_association: CONTRIBUTOR
user: login: RussTreadon-NOAA
created_at: 2025-04-24T12:05:08Z
body: @jianjunj , please keep your branch `jianjunj:feature/initial_metop-sg-a1_mws` up to date with the head of `develop`.  

Your branch is currently [1 commit](https://github.com/jianjunj/GSI/compare/feature/initial_metop-sg-a1_mws...NOAA-EMC%3AGSI%3Adevelop) behind `develop`.  The missing `develop` commit includes an update to `global_convinfo.txt`.  As a result your branch and develop assimilate different gpsro observations.  This complicates efforts to debug the `setuprad.f90` omp issue.

GSI PR #863 will be merged into `develop` this morning putting your branch even further behind `develop`.
author_association: CONTRIBUTOR
user: login: jianjunj
created_at: 2025-04-24T14:53:24Z
body: @RussTreadon-NOAA Thanks.  Will do that in a moment.
author_association: CONTRIBUTOR
user: login: RussTreadon-NOAA
created_at: 2025-04-24T17:11:10Z
body: @dkokron examined `omp` directives in `setuprad.f90`.  He identified `tsavg5` and `ys_bias_sst` as variables which need to be private in the first `omp` loop in `setuprad.f90`.   These variables are output in the `spline_cub` call below
```
!          Apply SST dependent bias correction with cubic spline                                                                                                                
           if (retrieval) then
              call spline_cub(fbias(:,mm),tsavg5,ys_bias_sst)
              predbias(npred+2,i) = ys_bias_sst
              if (iuse_rad(mm)==4) predbias(npred+2,i) = zero
           endif
```
The current suite of GSI ctests run with `retrieval=.false.` so execution never enters this block.  That said, the indicated variables should be made private.   Doing so in working copies of `develop` and `jianjunj:feature/initial_metop-sg-a1_mws` did yield identical analysis results.  

**_The recommended change is to comment out the four omp directives in `setuprad.f90`._**   

This was done in a working copy of `jianjunj:feature/initial_metop-sg-a1_mws` on Cactus.  The 20250424 00Z GDAS case was run without the omp directives in the PR #844 `setuprad.f90`.  The same case was run using `develop` with the directives active.  The analysis results are identical between these two runs.  The `gsi.x` wall times are comparable.  A third run was made using the PR #844 code _with_ omp directives active in `setuprad.90`.  Analysis results from this `gsi.x` differ from the other two executables.

 - `develop gsi.x` with omp in `setuprad.f90`:  3727.948445 seconds
 - `jianjunj:feature/initial_metop-sg-a1_mws gsi.x` without omp in `setuprad.f90`:  3716.064622 seconds
 - `jianjunj:feature/initial_metop-sg-a1_mws gsi.x` with omp in `setuprad.f90`:  3746.896502 seconds
author_association: CONTRIBUTOR
user: login: jianjunj
created_at: 2025-04-24T17:53:42Z
body: Thank you @RussTreadon-NOAA @dkokron . I see "tsavg5" is used in
```
!       Apply bias correction

           tlapchn(i)= (ptau5(2,i)-ptau5(1,i))*(tsavg5-tvp(2))
```
Is it the reason? 
author_association: CONTRIBUTOR
user: login: RussTreadon-NOAA
created_at: 2025-04-24T18:06:24Z
body: `tsavg5` is an `inout` argument to subroutine `spline_cub`  Thus, the value of `tsavg5` is thread specific.  This is not an issue for our ctests or global GSI runs.  `spline_cub` is not executed in either because `gsi.x` is run with `retrieval=.false.`.
author_association: CONTRIBUTOR
user: login: dkokron
created_at: 2025-04-24T19:53:17Z
body: I want to point out that simply making tsavg5 and ys_bias_sst private is not enough to resolve all issues with those OpenMP directives.  The trouble is with tsavg5.  tsavg5 is set above the "compute and apply bias correction" loop, modified and used inside the loop (in spline_cub()) and then used downstream of the loop.  The appropriate OpenMP designation for tsavg5 is some kind of "reduction", but I haven't spent enough time figuring out if OpenMP can handle it.
author_association: COLLABORATOR
user: login: RussTreadon-NOAA
created_at: 2025-04-28T10:35:52Z
body: @jianjunj , @ADCollard , and @emilyhcliu :  Are we OK with commenting out the four `!$omp parallel do` directives in `setuprad.f90`?  If not, what's the plan for this PR?
author_association: CONTRIBUTOR
user: login: RussTreadon-NOAA
created_at: 2025-04-29T11:24:19Z
body: **WCOSS2 ctests**

Install `develop` at 95b8e3c and `jianjunj:feature/initial_metop-sg-a1_mws` at 58b58e6 on Cactus.  Run ctests with following results
```
Test project /lfs/h2/emc/da/noscrub/russ.treadon/git/gsi/pr844/build
    Start 1: global_4denvar
    Start 2: rtma
    Start 3: rrfs_3denvar_rdasens
    Start 4: hafs_4denvar_glbens
    Start 5: hafs_3denvar_hybens
    Start 6: global_enkf
1/6 Test #3: rrfs_3denvar_rdasens .............   Passed  730.64 sec
2/6 Test #6: global_enkf ......................   Passed  855.35 sec
3/6 Test #2: rtma .............................   Passed  1034.35 sec
4/6 Test #5: hafs_3denvar_hybens ..............   Passed  1222.12 sec
5/6 Test #4: hafs_4denvar_glbens ..............   Passed  1223.33 sec
6/6 Test #1: global_4denvar ...................   Passed  1925.55 sec

100% tests passed, 0 tests failed out of 6

Total Test time (real) = 1925.56 sec
```

As expected ctests now pass on WCOSS2 because [cfc2ed7](https://github.com/NOAA-EMC/GSI/pull/844/commits/cfc2ed79b6f1c07a70648d13998146ee3fc35e16) commented out the four `!$omp parallel do` directives in `setuprad.f90`. 
author_association: CONTRIBUTOR
user: login: wx20jjung
created_at: 2025-04-29T20:07:21Z
body: It seems to me that varinv is set in an if block around line 990 and then
again in if blocks around line 1064 - 1094.  The first time it is used is
about line 1341.

If you want to define a value to varinv, I suggest doing it in the
declaration statement about line 391.
Jim

On Tue, Apr 29, 2025 at 11:18 AM jianjunj ***@***.***> wrote:

> ***@***.**** commented on this pull request.
> ------------------------------
>
> In src/gsi/setuprad.f90
> <https://github.com/NOAA-EMC/GSI/pull/844#discussion_r2066806820>:
>
> > @@ -804,6 +806,7 @@ subroutine setuprad(obsLL,odiagLL,lunin,mype,aivals,stats,nchanl,nreal,nobs,&
>       if(in_curbin) then
>
>          id_qc = igood_qc
> +!       varinv = zero
>
> I cannot say it is correct or not correct. It is supposed to have no
> impact. I was kind of just throwing an initialization before calling CRTM.
> Does anyone have a comment? I will remove it if it is not helping us.
>
> —
> Reply to this email directly, view it on GitHub
> <https://github.com/NOAA-EMC/GSI/pull/844#discussion_r2066806820>, or
> unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AMPASA5F3I3T34KLSYR6N2D236J5HAVCNFSM6AAAAABZISNXCCVHI2DSMVQWIX3LMV43YUDVNRWFEZLROVSXG5CSMV3GSZLXHMZDQMBUGA4DSMZYGM>
> .
> You are receiving this because your review was requested.Message ID:
> ***@***.***>
>

author_association: CONTRIBUTOR
user: login: jianjunj
created_at: 2025-04-30T16:12:12Z
body: Thank you very much @wx20jjung .  I had two tests on WCOSS2. I re-activated the OpenMP in the setuprad.f90 in both of the two tests.  I set varinv=zero at about line 341 as you suggested, but in the **control,**  in one test, and set varinv=zero at about line 809 as what I did before, also in the **control** in the second test. There are no other changes in the control.  The "global_4denvar" failed in the first test, but  passed in the second one.  It is kind of cheating, of course, since it changed the control results in the second test. 
author_association: CONTRIBUTOR
user: login: jianjunj
created_at: 2025-04-30T16:28:19Z
body: Forgot to note that I added varinv=zero in my setuprad.f90 with MWS at the place @wx20jjung suggested in my tests. 
author_association: CONTRIBUTOR
user: login: jianjunj
created_at: 2025-04-30T17:33:25Z
body: Un-surprisingly, the global_4denvar test fails after varinv=zero is put the same replace as in the develop  and the OpenMP is deactivated in another test. 
Anyway,  I am going to delete that line "!     varinv=zeo" which I added.
author_association: CONTRIBUTOR
user: login: RussTreadon-NOAA
created_at: 2025-05-02T10:05:24Z
body: @jianjunj: The conflicts in `regression/regression_namelist.sh` are easily resolved.  `abi_g19` has been added to the same spots you added `mws_metop-sg-a1`.  Resolve the conflicts. 

You can update the `fix` submodule aafter GSI-fix PR [#31](https://github.com/NOAA-EMC/GSI-fix/pull/31) is merged into `develop`  

We can then rerun ctests, post results to this PR, and invite peer reviewers to review and, hopefully, approve this PR.
author_association: CONTRIBUTOR
user: login: jianjunj
created_at: 2025-05-02T18:53:45Z
body: @RussTreadon-NOAA  All those ctests passed on WCOSS2 after the conflicts were resolved and minor updates in regards to the "dplat" character length. 

```
    Start 1: global_4denvar
    Start 2: rtma
    Start 3: rrfs_3denvar_rdasens
    Start 4: hafs_4denvar_glbens
    Start 5: hafs_3denvar_hybens
    Start 6: global_enkf
1/6 Test #6: global_enkf ......................   Passed  381.44 sec
2/6 Test #3: rrfs_3denvar_rdasens .............   Passed  796.33 sec
3/6 Test #2: rtma .............................   Passed  1219.54 sec
4/6 Test #5: hafs_3denvar_hybens ..............   Passed  1227.31 sec
5/6 Test #4: hafs_4denvar_glbens ..............   Passed  1465.31 sec
6/6 Test #1: global_4denvar ...................   Passed  1565.36 sec

100% tests passed, 0 tests failed out of 6

Total Test time (real) = 1565.38 sec
```
author_association: CONTRIBUTOR
user: login: RussTreadon-NOAA
created_at: 2025-05-02T19:01:13Z
body: Thank you @jianjunj .  Where do we stand regarding GSI-fix PR [#31](https://github.com/NOAA-EMC/GSI-fix/pull/31)?  While GSI-fix PR #31 has two approvals, my approval does not count toward two peer reviews and approvals.  My approval is required by git since I have write permission to GSI-fix.
author_association: CONTRIBUTOR
user: login: jianjunj
created_at: 2025-05-02T19:18:51Z
body: > Thank you @jianjunj . Where do we stand regarding GSI-fix PR [#31](https://github.com/NOAA-EMC/GSI-fix/pull/31)? While GSI-fix PR #31 has two approvals, my approval does not count toward two peer reviews and approvals. My approval is required by git since I have write permission to GSI-fix.

Just updated that GSI-fix PR and sent another review request.
author_association: CONTRIBUTOR
user: login: RussTreadon-NOAA
created_at: 2025-05-06T13:23:12Z
body: @jianjunj , GSI-fix PR [#31](https://github.com/NOAA-EMC/GSI-fix/pull/31) has been merged into `develop`.  Done at [4b6c86f](https://github.com/NOAA-EMC/GSI-fix/commit/4b6c86fb84ae0629cfa409368d92ed444ed12195).

Please update the `fix` submodule in this PR.

After this is done we need to run one more round of ctests.  This PR can be merged into `develop`  pending _Passed_ ctests.
author_association: CONTRIBUTOR
user: login: RussTreadon-NOAA
created_at: 2025-05-06T17:50:40Z
body: **WCOSS ctest**

Install `jianjunj:feature/initial_metop-sg-a1_mws` at  [a774e59](https://github.com/jianjunj/GSI/commit/a774e59fdbcc2d41f150cb35d8bd9d93692da17e) and `develop` at [aea2e2d](https://github.com/NOAA-EMC/GSI/commit/aea2e2d07e7b0832aba542329cf460bef2103a6e) on Cactus.

Run ctests with the following results
```
Test project /lfs/h2/emc/da/noscrub/russ.treadon/git/gsi/pr844/build
    Start 1: global_4denvar
    Start 2: rtma
    Start 3: rrfs_3denvar_rdasens
    Start 4: hafs_4denvar_glbens
    Start 5: hafs_3denvar_hybens
    Start 6: global_enkf
1/6 Test #3: rrfs_3denvar_rdasens .............   Passed  732.56 sec
2/6 Test #6: global_enkf ......................   Passed  857.21 sec
3/6 Test #2: rtma .............................   Passed  1095.26 sec
4/6 Test #5: hafs_3denvar_hybens ..............   Passed  1222.18 sec
5/6 Test #4: hafs_4denvar_glbens ..............   Passed  1406.40 sec
6/6 Test #1: global_4denvar ...................   Passed  1924.48 sec

100% tests passed, 0 tests failed out of 6

Total Test time (real) = 1924.52 sec
```
author_association: CONTRIBUTOR