subroutine read_avhrr_navy(mype,val_avhrr,ithin,rmesh,jsatid,& gstime,infile,lunout,obstype,nread,ndata,nodata,twind,sis, & mype_root,mype_sub,npe_sub,mpi_comm_sub,nobs,& nrec_start,dval_use) !$$$ subprogram documentation block ! . . . . ! subprogram: read_avhrr_navy read navy avhrr data ! prgmmr: li, xu org: np23 date: 2003-03-26 ! ! abstract: This routine reads BUFR format AVHRR radiance (brightness ! temperature) files from the U.S. Navy. 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: ! 2003-03-26 li, xu - read Navy avhrr_sst data ! 2004-05-28 kleist - update subroutine call ! 2004-06-16 treadon - update documentation ! 2004-07-23 derber - make changes to eliminate obs. earlier in thinning ! 2004-07-29 treadon - add only to module use, add intent in/out ! 2005-01-26 derber - land/sea determination and weighting for data selection ! 2005-04-18 treadon - read in and interpolate hi-res SST analysis to obs locations ! 2005-09-08 derber - modify to use input group time window ! 2005-09-28 derber - modify to produce consistent surface info ! 2005-10-17 treadon - add grid and earth relative obs location to output file ! 2005-10-18 treadon - remove array obs_load and call to sumload ! 2005-10-19 li, xu - modify to use new (operational bufr table) ! 2005-11-29 parrish - modify getsfc to work for different regional options ! 2006-02-01 parrish - remove getsfc (different version called now in read_obs) ! 2006-02-03 derber - modify for new obs control and obs count ! 2006-04-21 keyser/treadon - add logic to correctly set BUFR subset ! 2006-04-27 derber - clean up code ! 2006-05-19 eliu - add logic to reset relative weight when all channels not used ! 2006-07-28 derber - add solar and satellite azimuth angles remove isflg from output ! 2007-03-01 tremolet - measure time from beginning of assimilation window ! 2008-05-28 safford - rm unused vars and uses ! 2008-10-10 derber - modify to allow mpi_io ! 2008-12-30 todling - memory leak fix (data_crit,idata_itx) ! 2009-04-21 derber - add ithin to call to makegrids ! 2011-04-08 li - (1) use nst_gsi, nstinfo, fac_dtl, fac_tsl and add NSST vars ! (2) get zob, tz_tr (call skindepth and cal_tztr) ! (3) interpolate NSST Variables to Obs. location (call deter_nst) ! (4) add more elements (nstinfo) in data array ! 2011-08-01 lueken - added module use deter_sfc_mod ! 2012-03-05 akella - nst now controlled via coupler ! 2013-01-26 parrish - change from grdcrd to grdcrd1 (to allow successful debug compile on WCOSS) ! 2015-02-23 Rancic/Thomas - add thin4d to time window logical ! 2015-10-01 guo - consolidate use of ob location (in deg) ! 2018-05-21 j.jin - added time-thinning. Moved the checking of thin4d into satthin.F90. ! ! input argument list: ! mype - mpi task id ! val_avhrr- weighting factor applied to super obs ! ithin - flag to thin data ! 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 - satellite/instrument/sensor indicator ! nrec_start - first subset with useful information ! ! output argument list: ! nread - number of BUFR NAVY AVHRR observations read ! ndata - number of BUFR NAVY AVHRR profiles retained for further processing ! nodata - number of BUFR NAVY AVHRR 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,map2tgrid,destroygrids, & finalcheck,score_crit use satthin, only: radthin_time_info,tdiff2crit use obsmod, only: time_window_max use gridmod, only: diagnostic_reg,regional,nlat,nlon,tll2xy,txy2ll,rlats,rlons use constants, only: deg2rad, zero, one, rad2deg, r60inv use radinfo, only: retrieval,iuse_rad,jpch_rad,nusis use gsi_4dvar, only: l4dvar,l4densvar,iwinbgn,winlen use deter_sfc_mod, only: deter_sfc use obsmod, only: bmiss 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,nrec_start integer(i_kind) ,intent(inout) :: nread integer(i_kind),dimension(npe) ,intent(inout) :: nobs integer(i_kind) ,intent(inout) :: ndata,nodata real(r_kind) ,intent(in ) :: rmesh,gstime,twind real(r_kind) ,intent(inout) :: val_avhrr 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 ! Declare local parameters character(6),parameter:: file_sst='SST_AN' integer(i_kind),parameter:: mlat_sst = 3000 integer(i_kind),parameter:: mlon_sst = 5000 real(r_kind),parameter:: r6=6.0_r_kind 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 ! Declare local variables logical outside,iuse,assim character(1):: cdummy character(8):: subset integer(i_kind) klon1,klatp1,klonp1,klat1 integer(i_kind) lnbufr,nchanl,iret integer(i_kind) idate,n,maxinfo integer(i_kind) ilat,ilon,iskip integer(i_kind) idummy1,idummy2,lun integer(i_kind),dimension(5):: idate5 integer(i_kind) nmind,isflg,idomsfc integer(i_kind) itx,k,i,bufsat integer(i_kind) ireadsb,ireadmg integer(i_kind) nreal,nele,itt integer(i_kind) nlat_sst,nlon_sst,irec,next integer(i_kind),allocatable,dimension(:)::nrec real(r_kind) dlon,dlat,sfcr real(r_kind) dlon_earth,dlat_earth real(r_kind) dlon_earth_deg,dlat_earth_deg real(r_kind) w00,w01,w10,w11,dx1,dy1 real(r_kind) pred,crit1,tdiff,sstime,dx,dy,dist1 real(r_kind) dlat_sst,dlon_sst,sst_hires real(r_kind) :: tsavg,vty,vfr,sty,stp,sm,sn,zz,ff10 real(r_kind) :: zob,tref,dtw,dtc,tz_tr real(r_kind) :: t4dv real(r_kind),dimension(0:4):: rlndsea real(r_kind),dimension(0:3):: sfcpct real(r_kind),dimension(0:3):: ts real(r_kind),dimension(mlat_sst):: rlats_sst real(r_kind),dimension(mlon_sst):: rlons_sst real(r_kind),allocatable,dimension(:,:):: sst_an real(r_kind),allocatable,dimension(:,:):: data_all real(r_double),dimension(100):: bufrf ! array to store the read bufr record real(r_kind) cdist,disterr,disterrmax,dlon00,dlat00 integer(i_kind) ntest real(r_kind) :: ptime,timeinflat,crit0 integer(i_kind) :: ithin_time,n_tbin,it_mesh !************************************************************************** ! Start routine here. Set constants. Initialize variables maxinfo = 33 disterrmax=zero lnbufr = 10 ntest=0 ndata = 0 nodata = 0 nchanl = 3 ilon=3 ilat=4 zob = zero if(nst_gsi>0) then call gsi_nstcoupler_skindepth(obstype, zob) ! get penetration depth (zob) for the obstype endif rlndsea(0) = zero rlndsea(1) = 30._r_kind rlndsea(2) = 20._r_kind rlndsea(3) = 30._r_kind rlndsea(4) = 30._r_kind ! 207, 208 or 209 for NOAA-16, 17 & 18 respectively if(jsatid == 'n16')bufsat = 207 if(jsatid == 'n17')bufsat = 208 if(jsatid == 'n18')bufsat = 209 if(jsatid == 'n19')bufsat = 223 if(jsatid == 'metop-a')bufsat = 4 if(jsatid == 'metop-b')bufsat = 3 if(jsatid == 'metop-c')bufsat = 5 ! 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_avhrr=zero 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) ! Read hi-res sst analysis if (retrieval) then allocate(sst_an(mlat_sst, mlon_sst)) call rdgrbsst(file_sst,mlat_sst,mlon_sst,& sst_an,rlats_sst,rlons_sst,nlat_sst,nlon_sst) endif ! Allocate arrays to hold all data for given satellite if(dval_use) maxinfo = maxinfo + 2 nreal = maxinfo + nstinfo nele = nreal + nchanl allocate(data_all(nele,itxmax),nrec(itxmax)) open(lnbufr,file=trim(infile),form='unformatted') ! open bufr data file ! Associate the tables file with the message file, and identify th elatter to BUFRLIB software call openbf (lnbufr,'IN',lnbufr) ! Check to see if data are in message type NC012015 or in NC012012 ! (should be in latter after spring 2006, will know this if ! message typoe NC012015 is no longer present in BUFRLIB) subset = 'NC012012' call status(lnbufr,lun,idummy1,idummy2) call nemtab(lun,'NC012015',idummy1,cdummy,iret) if(iret>0) subset = 'NC012015' next=0 ! Read BUFR Navy data irec=0 read_msg: do while (ireadmg(lnbufr,subset,idate) >= 0) irec=irec+1 if(irec < nrec_start)cycle read_msg next=next+1 if(next == npe_sub)next=0 if(next /= mype_sub)cycle read_loop:do while (ireadsb(lnbufr) == 0) call ufbint(lnbufr,bufrf(1),9,1,iret, & 'YEAR MNTH DAYS HOUR MINU SECO CLAT CLON SAID') if ( bufsat /= nint(bufrf(9)) ) cycle read_loop ! read next bufr subset call ufbint(lnbufr,bufrf(10),4,1,iret,'SAZA SOZA SOLAZI SSTYPE') call ufbint(lnbufr,bufrf(14),1,1,iret,'SST1') call ufbrep(lnbufr,bufrf(15),1,5,iret,'TMBR') iskip = 0 do k=1,nchanl if(bufrf(16+k) < tbmin .or. bufrf(16+k) > tbmax) then iskip=iskip+1 else nread=nread+1 end if end do if(iskip >= nchanl)cycle read_loop ! Extract date information. If time outside window, skip this obs idate5(1) = nint(bufrf(1)) !year idate5(2) = nint(bufrf(2)) !month idate5(3) = nint(bufrf(3)) !day idate5(4) = nint(bufrf(4)) !hour idate5(5) = nint(bufrf(5)) !minute call w3fs21(idate5,nmind) t4dv=(real(nmind-iwinbgn,r_kind) + real(bufrf(6),r_kind)*r60inv)*r60inv sstime=real(nmind,r_kind) + real(bufrf(6),r_kind)*r60inv tdiff=(sstime-gstime)*r60inv if (l4dvar.or.l4densvar) then if (t4dvwinlen) cycle read_loop else if(abs(tdiff) > twind) cycle read_loop endif ! Convert obs location to radians if (bufrf(8)>=r360) bufrf(8)=bufrf(8)-r360 if (bufrf(8)< zero) bufrf(8)=bufrf(8)+r360 dlon_earth_deg = bufrf(8) dlat_earth_deg = bufrf(7) dlon_earth = bufrf(8)*deg2rad !convert degrees to radians dlat_earth = bufrf(7)*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 if(outside) cycle read_loop ! Global case else dlat = dlat_earth dlon = dlon_earth call grdcrd1(dlat,rlats,nlat,1) call grdcrd1(dlon,rlons,nlon,1) endif ! Set common predictor parameters ! Map obs to thinning grid crit0 = 0.01_r_kind timeinflat=r6 call tdiff2crit(tdiff,ptime,ithin_time,timeinflat,crit0,crit1,it_mesh) call map2tgrid(dlat_earth,dlon_earth,dist1,crit1,itx,ithin,itt,iuse,sis,it_mesh=it_mesh) if(.not. iuse)cycle read_loop ! "Score" observation. We use this information to id "best" obs. ! Locate the observation on the analysis grid. Get sst and land/sea/ice ! mask. ! isflg - surface flag ! 0 sea ! 1 land ! 2 sea ice ! 3 snow ! 4 mixed call deter_sfc(dlat,dlon,dlat_earth,dlon_earth,t4dv,isflg,idomsfc,sfcpct, & ts,tsavg,vty,vfr,sty,stp,sm,sn,zz,ff10,sfcr) pred=zero ! Compute "score" for observation. All scores>=0.0. Lowest score is "best" crit1 = crit1+pred + rlndsea(isflg) call finalcheck(dist1,crit1,itx,iuse) if(.not. iuse)cycle read_loop ! Interpolate hi-res sst analysis to observation location dlat_sst = dlat_earth dlon_sst = dlon_earth call grdcrd1(dlat_sst,rlats_sst,nlat_sst,1) call grdcrd1(dlon_sst,rlons_sst,nlon_sst,1) klon1=int(dlon_sst); klat1=int(dlat_sst) dx =dlon_sst-klon1; dy =dlat_sst-klat1 dx1 =one-dx; dy1 =one-dy w00=dx1*dy1; w10=dx1*dy; w01=dx*dy1; w11=dx*dy klat1=min(max(1,klat1),nlat_sst); klon1=min(max(0,klon1),nlon_sst) if(klon1==0) klon1=nlon_sst klatp1=min(nlat_sst,klat1+1); klonp1=klon1+1 if(klonp1==nlon_sst+1) klonp1=1 if(retrieval) then sst_hires=w00*sst_an(klat1,klon1 ) + w10*sst_an(klatp1,klon1 ) + & w01*sst_an(klat1,klonp1) + w11*sst_an(klatp1,klonp1) else sst_hires= zero endif ! ! 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 ! Transfer information to work array data_all(1, itx) = bufrf(9) ! satellite id data_all(2, itx) = t4dv ! time (hours) data_all(3, itx) = dlon ! grid relative longitude data_all(4, itx) = dlat ! grid relative latitude data_all(5, itx) = bufrf(10)*deg2rad ! satellite zenith angle (radians) data_all(6, itx) = bmiss ! satellite azimuth angle data_all(7, itx) = bufrf(14) ! Navy SST retrieval data_all(8, itx) = zero ! scan position (unavailable) data_all(9, itx) = bufrf(11) ! solar zenith angle (radians) data_all(10,itx) = bufrf(12) ! solar azimuth angle (radians) 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 (from surface file: sst_full) 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 + 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 (degrees) data_all(31,itx) = dlat_earth_deg ! earth relative latitude (degrees) data_all(32,itx) = bufrf(13) ! Data type: 151=day,152=night,159=cloud problem data_all(33,itx) = sst_hires ! interpolated hires SST (deg K) if(dval_use)then data_all(34,itx) = val_avhrr data_all(35,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 k=1,nchanl data_all(k+maxinfo,itx)= bufrf(16+k) ! Tb for avhrr ch-3, ch-4 and ch-5 end do nrec(itx)=irec ! End of satellite read block end do read_loop end do read_msg ! if ( ierrmg == 0 ) then write(6,*) 'READ_AVHRR_NAVY: total number of obs, nread,ndata : ',nread,ndata ! Normal exit 700 continue call combine_radobs(mype_sub,mype_root,npe_sub,mpi_comm_sub,& nele,itxmax,nread,ndata,data_all,score_crit,nrec) ! Now that we've identified the "best" observations, pull out best obs ! and write them to the output file do n=1,ndata do k=1,nchanl if(data_all(k+nreal,n) > tbmin .and. & data_all(k+nreal,n) < tbmax)nodata=nodata+1 end do end do if(dval_use .and. assim)then do n=1,ndata itt=nint(data_all(35,n)) super_val(itt)=super_val(itt)+val_avhrr end do end if ! Write retained data to local 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) ! Deallocate local arrays deallocate(data_all,nrec) if(retrieval) deallocate(sst_an) ! Deallocate arrays 900 continue call destroygrids call closbf(lnbufr) close(lnbufr) if(diagnostic_reg.and.ntest>0) write(6,*)'READ_AVHRR_NAVY: ',& 'mype,ntest,disterrmax=',mype,ntest,disterrmax ! End of routine return end subroutine read_avhrr_navy