1 subroutine da_read_obs_bufrtovs (obstype,iv, infile)
3 !---------------------------------------------------------------------------
4 ! Purpose: read in NCEP bufr tovs 1b data to innovation structure
6 ! METHOD: use F90 sequential data structure to avoid reading file twice
7 ! so that da_scan_bufrtovs is not necessary any more.
8 ! 1. read file radiance data in sequential data structure
10 ! 3. assign sequential data structure to innovation structure
11 ! and deallocate sequential data structure
13 ! Peiming Dong Added NPP atms, 2012/4/17
14 !---------------------------------------------------------------------------
18 character(5) , intent (in) :: obstype
19 character(20) , intent (in) :: infile
20 type (iv_type) , intent (inout) :: iv
25 integer(i_kind), allocatable :: nread(:)
27 integer(i_kind),parameter:: n1bhdr=15
28 integer(i_kind),parameter:: n2bhdr=2
29 integer(i_kind),parameter:: maxinfo=12
30 integer(i_kind),parameter:: maxchanl=100
32 logical hirs2,hirs3,hirs4,msu,amsua,amsub,mhs,atms
33 logical outside, outside_all, iuse
37 character(8) subset,subfgn
40 integer(i_kind) ihh,i,j,k,ifov,idd,ireadmg,ireadsb
41 integer(i_kind) iret,idate,im,iy,nchan
42 integer :: num_bufr(7), numbufr, ibufr
43 character(20) :: filename
46 integer(i_kind) itt,itx,iobs,iout
47 real(r_kind) terrain,timedif,crit,dist
48 real(r_kind) dlon_earth,dlat_earth
50 real(r_kind) tbmin,tbmax, tbbad
51 real(r_kind) panglr,rato
53 real(r_kind) step,start
55 real(r_double),dimension(maxinfo+maxchanl):: data1b8
56 real(r_double),dimension(n1bhdr):: bfr1bhdr
57 real(r_double),dimension(n2bhdr):: bfr2bhdr
59 ! Instrument triplet, follow the convension of RTTOV
60 integer :: platform_id, satellite_id, sensor_id
63 integer :: year,month,day,hour,minute,second ! observation time
65 ! real :: rlat, rlon ! lat/lon in degrees for Anfovs
66 real :: satzen, satazi, solzen ,solazi ! scan angles for Anfovs
67 integer :: landsea_mask
69 ! channels' bright temperature
70 real , allocatable :: tb_inv(:) ! bright temperatures
71 ! end type bright_temperature
73 type (datalink_type), pointer :: head, p, current, prev
76 type(info_type) :: info
77 type(model_loc_type) :: loc
79 data hdr1b /'SAID FOVN YEAR MNTH DAYS HOUR MINU SECO CLAT CLON SAZA SOZA HOLS LSQL SOLAZI'/
80 data hdr2b /'CLATH CLONH'/
81 ! data hdr1b /'FOVN YEAR MNTH DAYS HOUR MINU SECO CLAT CLON SAZA SOZA HOLS LSQL SLNM BEARAZ'/
83 data tbmin,tbmax,tbbad / 50.0_r_kind, 550.0_r_kind, -9.99e11_r_kind /
84 integer :: num_tovs_local, num_tovs_file, num_tovs_global, num_tovs_selected
85 integer :: num_tovs_thinned, num_tovs_used, num_tovs_used_tmp
88 integer(i_kind), allocatable :: ptotal(:)
89 real , allocatable :: in(:), out(:)
90 logical :: found, head_found
92 call da_trace_entry("da_read_obs_bufrtovs")
94 ! Initialize variables
97 allocate(nread(1:rtminit_nsensor))
98 allocate(ptotal(0:num_fgat_time))
99 nread(1:rtminit_nsensor) = 0
100 ptotal(0:num_fgat_time) = 0
102 ! Set various variables depending on type of data to be read
104 ! platform_id = 1 !! for NOAA series
105 ! platform_id = 10 !! for METOP series
107 hirs2= obstype == 'hirs2'
108 hirs3= obstype == 'hirs3'
109 hirs4= obstype == 'hirs4'
110 msu= obstype == 'msu '
111 amsua= obstype == 'amsua'
112 amsub= obstype == 'amsub'
113 mhs= obstype == 'mhs '
114 atms= obstype == 'atms '
122 rato=1.1363987_r_kind
137 step = 10.0_r_kind/9.0_r_kind
138 start = -445.0_r_kind/9.0_r_kind
144 start = -47.37_r_kind
147 rato=1.1363987_r_kind
150 step = three + one/three
151 start = -48.33_r_kind
157 start = -48.95_r_kind
163 start = -52.725_r_kind
166 hdr1b='SAID FOVN YEAR MNTH DAYS HOUR MINU SECO CLAT CLON SAZA SOZA HMSL LSQL SOLAZI'
169 allocate (tb_inv(nchan))
171 num_tovs_file = 0 ! number of obs in file
172 num_tovs_global = 0 ! number of obs within whole domain
173 num_tovs_local = 0 ! number of obs within tile
174 num_tovs_thinned = 0 ! number of obs rejected by thinning
175 num_tovs_used = 0 ! number of obs entered into innovation computation
176 num_tovs_selected = 0 ! number of obs limited for debuging
177 iobs = 0 ! for thinning, argument is inout
179 ! 0.0 Open unit to satellite bufr file and read file header
180 !--------------------------------------------------------------
184 if (num_fgat_time>1) then
186 call da_get_unit(lnbufr)
187 write(filename,fmt='(A,2I1,A)') trim(infile),0,i,'.bufr'
188 open(unit = lnbufr, FILE = trim(filename),iostat = iost, form = 'unformatted', STATUS = 'OLD')
195 call da_free_unit(lnbufr)
201 if (numbufr==0) numbufr=1
203 bufrfile: do ibufr=1,numbufr
204 if (num_fgat_time==1) then
205 filename=trim(infile)//'.bufr'
207 if ((numbufr ==1) .and. (num_bufr(ibufr) == 0)) then
208 filename=trim(infile)//'.bufr'
210 write(filename,fmt='(A,2I1,A)') trim(infile),0,num_bufr(ibufr),'.bufr'
214 ! We want to use specific unit number for bufr data, so we can control the endian format in environment.
217 open(unit=lnbufr,file=trim(filename),form='unformatted', &
218 iostat = iost, status = 'old')
220 call da_warning(__FILE__,__LINE__, &
221 (/"Cannot open file "//infile/))
222 call da_trace_exit("da_read_obs_bufrtovs")
226 call openbf(lnbufr,'IN',lnbufr)
228 call readmg(lnbufr,subset,idate,iret)
229 if (subset /= subfgn) then
232 message(1)='The file title does not match the data subset'
233 write(unit=message(2),fmt=*) &
234 'infile=', lnbufr, infile,' subset=', subset, ' subfgn=',subfgn
235 call da_error(__FILE__,__LINE__,message(1:2))
242 write(unit=date,fmt='( i10)') idate
243 read(unit=date,fmt='(i4,3i2)') iy,im,idd,ihh
244 write(unit=stdout,fmt=*) &
245 'Bufr file date is ',iy,im,idd,ihh,infile
247 ! Loop to read bufr file and assign information to a sequential structure
248 !-------------------------------------------------------------------------
250 if ( ibufr == 1 ) then
252 ! allocate ( head % tb_inv (1:nchan) )
253 nullify ( head % next )
257 if (tovs_start > 1) then
258 write (unit=stdout,fmt='(A,I6)') " Skipping tovs obs before", tovs_start
262 obs: do while (ireadmg(lnbufr,subset,idate)==0 .and. subset==subfgn)
263 do while (ireadsb(lnbufr)==0)
265 ! 1.0 Read header record and data record
266 call ufbint(lnbufr,bfr1bhdr,n1bhdr,1,iret,hdr1b)
267 call ufbint(lnbufr,bfr2bhdr,n2bhdr,1,iret,hdr2b)
268 call ufbrep(lnbufr,data1b8,1,nchan,iret,'TMBR')
269 ! call ufbrep(lnbufr,data1b8,1,1,iret,'BEARAZ')
271 ! check if observation outside range
273 num_tovs_file = num_tovs_file + 1
275 ! 2.0 Extract observation location and other required information
276 ! QC1: judge if data is in the domain, read next record if not
277 !------------------------------------------------------------------------
278 ! rlat = bfr1bhdr(bufr_lat)
279 ! rlon = bfr1bhdr(bufr_lat)
280 ! if (rlon < 0.0) rlon = rlon+360.0
282 if(abs(bfr2bhdr(1)) <= 90. .and. abs(bfr2bhdr(2)) <= 360.)then
283 info%lat = bfr2bhdr(1)
284 info%lon = bfr2bhdr(2)
285 elseif(abs(bfr1bhdr(9)) <= 90. .and. abs(bfr1bhdr(10)) <= 360.)then
286 info%lat = bfr1bhdr(9)
287 info%lon = bfr1bhdr(10)
290 call da_llxy (info, loc, outside, outside_all)
292 if (outside_all) cycle
294 ! 3.0 Extract other information
295 !------------------------------------------------------
296 ! 3.1 Extract satellite id and scan position.
298 if ( nint(bfr1bhdr(bufr_satellite_id)) >= 200 .and. nint(bfr1bhdr(bufr_satellite_id)) <= 204 ) then
300 satellite_id = nint(bfr1bhdr(bufr_satellite_id))-192
301 else if ( nint(bfr1bhdr(bufr_satellite_id)) >= 205 .and. nint(bfr1bhdr(bufr_satellite_id)) <= 209 ) then
303 satellite_id = nint(bfr1bhdr(bufr_satellite_id))-191
304 else if ( nint(bfr1bhdr(bufr_satellite_id)) == 223 ) then ! noaa-19
306 satellite_id = nint(bfr1bhdr(bufr_satellite_id))-204
307 else if ( nint(bfr1bhdr(bufr_satellite_id)) >= 3 .and. nint(bfr1bhdr(bufr_satellite_id)) <= 5 ) then
309 satellite_id = nint(bfr1bhdr(bufr_satellite_id))-2
310 else if ( nint(bfr1bhdr(bufr_satellite_id)) == 708 ) then ! tiros-n
313 else if ( nint(bfr1bhdr(bufr_satellite_id)) == 224 ) then ! npp
316 else if ( nint(bfr1bhdr(bufr_satellite_id)) >= 701 .and. nint(bfr1bhdr(bufr_satellite_id)) <= 707 ) then
318 satellite_id = nint(bfr1bhdr(bufr_satellite_id))-700
320 ifov = nint(bfr1bhdr(bufr_ifov))
323 ! QC2: limb pixel rejected (not implemented)
325 ! 3.2 Extract date information.
327 year = bfr1bhdr(bufr_year)
328 month = bfr1bhdr(bufr_month)
329 day = bfr1bhdr(bufr_day)
330 hour = bfr1bhdr(bufr_hour)
331 minute = bfr1bhdr(bufr_minute)
332 second = bfr1bhdr(bufr_second)
334 write(unit=info%date_char, fmt='(i4,a,i2.2,a,i2.2,a,i2.2,a,i2.2,a,i2.2)') &
335 year, '-', month, '-', day, '_', hour, ':', minute, ':', second
337 ! QC3: time consistency check with the background date
347 call da_get_julian_time(year,month,day,hour,minute,obs_time)
349 if (obs_time < time_slots(0) .or. &
350 obs_time >= time_slots(num_fgat_time)) cycle
352 ! 3.2.1 determine FGAT index ifgat
354 do ifgat=1,num_fgat_time
355 if (obs_time >= time_slots(ifgat-1) .and. &
356 obs_time < time_slots(ifgat)) exit
359 ! 3.3 Find wrfvar instrument index from RTTOV instrument triplet
360 ! go to next data if id is not in the lists
363 do i = 1, rtminit_nsensor
364 if (platform_id == rtminit_platform(i) &
365 .and. satellite_id == rtminit_satid(i) &
366 .and. sensor_id == rtminit_sensor(i)) then
373 ! 3.4 extract satellite and solar angle
375 panglr=(start+float(ifov-1)*step)*deg2rad
376 if (hirs2 .or. msu) then
377 satzen = asin(rato*sin(panglr))*rad2deg
380 satzen = bfr1bhdr(bufr_satzen) !*deg2rad ! local zenith angle
383 ! if (amsua .and. ifov .le. 15) satzen=-satzen
384 ! if (amsub .and. ifov .le. 45) satzen=-satzen
385 ! if (hirs3 .and. ifov .le. 28) satzen=-satzen
387 if ( satzen > 65.0 ) cycle ! CRTM has a satzen > 65.0 check
388 satazi = panglr*rad2deg ! look angle
389 ! if (satazi<0.0) satazi = satazi+360.0
390 solzen = bfr1bhdr(bufr_solzen) ! solar zenith angle
391 solazi = bfr1bhdr(bufr_solazi) !RTTOV9_3
393 num_tovs_global = num_tovs_global + 1
394 ptotal(ifgat) = ptotal(ifgat) + 1
396 if (num_tovs_global < tovs_start) then
400 if (num_tovs_global > tovs_end) then
401 write (unit=stdout,fmt='(A,I6)') " Skipping radiance obs after", tovs_end
405 num_tovs_selected = num_tovs_selected + 1
407 if (num_tovs_selected > max_tovs_input) then
408 write(unit=message(1),fmt='(A,I10,A)') &
409 "Max number of tovs",max_tovs_input," reached"
410 call da_warning(__FILE__,__LINE__,message(1:1))
411 num_tovs_selected = num_tovs_selected-1
412 num_tovs_global = num_tovs_global-1
413 ptotal(ifgat) = ptotal(ifgat) - 1
417 if (outside) cycle ! No good for this PE
418 num_tovs_local = num_tovs_local + 1
421 ! Map obs to thinning grid
422 !-------------------------------------------------------------------
424 dlat_earth = info%lat
425 dlon_earth = info%lon
426 if (dlon_earth<zero) dlon_earth = dlon_earth+r360
427 if (dlon_earth>=r360) dlon_earth = dlon_earth-r360
428 dlat_earth = dlat_earth*deg2rad
429 dlon_earth = dlon_earth*deg2rad
430 timedif = 0.0 !2.0_r_kind*abs(tdiff) ! range: 0 to 6
431 terrain = 0.01_r_kind*abs(bfr1bhdr(13))
432 crit = 1.0 !0.01_r_kind+terrain + timedif !+ 10.0_r_kind*float(iskip)
433 call map2grids(inst,ifgat,dlat_earth,dlon_earth,crit,iobs,itx,1,itt,iout,iuse)
435 num_tovs_thinned=num_tovs_thinned+1
440 num_tovs_used = num_tovs_used + 1
441 nread(inst) = nread(inst) + 1
443 ! 3.5 extract surface information
444 srf_height = bfr1bhdr(bufr_station_height) ! station height
445 if (srf_height < 8888.0 .AND. srf_height > -416.0) then
450 landsea_mask = nint(bfr1bhdr(bufr_landsea_mask)) ! 0:land ; 1:sea (same as RTTOV)
452 ! if (nint(bfr1bhdr(bufr_landsea_mask))==1) rmask=0.0_r_kind ! reverse the land/sea mask in bufr
453 ! landsea_mask = rmask+.001_r_kind ! land sea mask
455 info%elv = srf_height
457 ! 3.6 extract channel bright temperature
459 tb_inv(1:nchan) = data1b8(1:nchan)
461 if ( tb_inv(k) < tbmin .or. tb_inv(k) > tbmax) &
462 tb_inv(k) = missing_r
464 if ( all(tb_inv<0.0) ) then
465 num_tovs_local = num_tovs_local -1
466 num_tovs_used = num_tovs_used - 1
467 nread(inst) = nread(inst) - 1
471 ! 4.0 assign information to sequential radiance structure
472 !--------------------------------------------------------------------------
473 allocate (p % tb_inv (1:nchan))
476 p%landsea_mask = landsea_mask
481 p%tb_inv(1:nchan) = tb_inv(1:nchan)
482 p%sensor_index = inst
487 allocate (p%next) ! add next data
499 if (thinning .and. num_tovs_global > 0 ) then
503 ! Get minimum crit and associated processor index.
505 do ifgat = 1, num_fgat_time
506 do n = 1, iv%num_inst
507 j = j + thinning_grid(n,ifgat)%itxmax
515 do ifgat = 1, num_fgat_time
516 do n = 1, iv%num_inst
517 do i = 1, thinning_grid(n,ifgat)%itxmax
519 in(j) = thinning_grid(n,ifgat)%score_crit(i)
523 call mpi_reduce(in, out, j, true_mpi_real, mpi_min, root, comm, ierr)
525 call wrf_dm_bcast_real (out, j)
528 do ifgat = 1, num_fgat_time
529 do n = 1, iv%num_inst
530 do i = 1, thinning_grid(n,ifgat)%itxmax
532 if ( ABS(out(j)-thinning_grid(n,ifgat)%score_crit(i)) > 1.0E-10 ) thinning_grid(n,ifgat)%ibest_obs(i) = 0
542 ! Delete the nodes which being thinning out
546 num_tovs_used_tmp = num_tovs_used
547 do j = 1, num_tovs_used_tmp
552 do i = 1, thinning_grid(n,ifgat)%itxmax
553 if ( thinning_grid(n,ifgat)%ibest_obs(i) == j .and. thinning_grid(n,ifgat)%score_crit(i) < 9.99e6_r_kind ) then
560 if ( .not. found ) then
563 if ( head_found ) then
569 deallocate ( current % tb_inv )
570 deallocate ( current )
571 num_tovs_thinned = num_tovs_thinned + 1
572 num_tovs_used = num_tovs_used - 1
573 nread(n) = nread(n) - 1
577 if ( found .and. head_found ) then
583 if ( found .and. .not. head_found ) then
592 endif ! End of thinning
594 iv%total_rad_pixel = iv%total_rad_pixel + num_tovs_used
595 iv%total_rad_channel = iv%total_rad_channel + num_tovs_used*nchan
597 iv%info(radiance)%nlocal = iv%info(radiance)%nlocal + num_tovs_used
598 iv%info(radiance)%ntotal = iv%info(radiance)%ntotal + num_tovs_global
600 do i = 1, num_fgat_time
601 ptotal(i) = ptotal(i) + ptotal(i-1)
602 iv%info(radiance)%ptotal(i) = iv%info(radiance)%ptotal(i) + ptotal(i)
604 if ( iv%info(radiance)%ptotal(num_fgat_time) /= iv%info(radiance)%ntotal ) then
605 write(unit=message(1),fmt='(A,I10,A,I10)') &
606 "Number of ntotal:",iv%info(radiance)%ntotal," is different from the sum of ptotal:", iv%info(radiance)%ptotal(num_fgat_time)
607 call da_warning(__FILE__,__LINE__,message(1:1))
610 write(unit=stdout,fmt='(a)') 'num_tovs_file num_tovs_global num_tovs_local num_tovs_used num_tovs_thinned'
611 write(unit=stdout,fmt='(5i10)') num_tovs_file,num_tovs_global, num_tovs_local,num_tovs_used,num_tovs_thinned
615 ! 5.0 allocate innovation radiance structure
616 !----------------------------------------------------------------
618 do i = 1, iv%num_inst
619 if (nread(i) < 1) cycle
620 iv%instid(i)%num_rad = nread(i)
621 iv%instid(i)%info%nlocal = nread(i)
622 write(UNIT=stdout,FMT='(a,i3,2x,a,3x,i10)') &
623 'Allocating space for radiance innov structure', &
624 i, iv%instid(i)%rttovid_string, iv%instid(i)%num_rad
626 call da_allocate_rad_iv(i,nchan,iv)
630 ! 6.0 assign sequential structure to innovation structure
631 !-------------------------------------------------------------
632 nread(1:rtminit_nsensor) = 0
634 ! do while ( associated(p) )
636 do n = 1, num_tovs_used
638 nread(i) = nread(i) + 1
640 call da_initialize_rad_iv (i, nread(i), iv, p)
646 deallocate ( current % tb_inv )
647 deallocate ( current )
655 ! check if sequential structure has been freed
658 ! do i = 1, num_rad_selected
659 ! write (unit=stdout,fmt=*) i, p%tb_inv(1:nchan)
663 call da_trace_exit("da_read_obs_bufrtovs")
665 call da_error(__FILE__,__LINE__,(/"Needs to be compiled with a BUFR library"/))
669 end subroutine da_read_obs_bufrtovs