1 subroutine da_read_obs_fy3 (obstype,iv, infile)
3 !---------------------------------------------------------------------------
4 ! Purpose: read in fy3 1b data to innovation structure
6 ! Dong peiming 2012/03/09
7 ! METHOD: use F90 sequential data structure to avoid reading file twice
8 ! so that da_scan_bufrtovs is not necessary any more.
9 ! 1. read file radiance data in sequential data structure
10 ! 2. do gross QC check
11 ! 3. assign sequential data structure to innovation structure
12 ! and deallocate sequential data structure
13 !---------------------------------------------------------------------------
17 character(5) , intent (in) :: obstype
18 character(20) , intent (in) :: infile
19 type (iv_type) , intent (inout) :: iv
23 INTEGER :: yyyy,mn,dd,hh,mm,ss
24 INTEGER :: iscanline,iscanpos
25 REAL*4 :: rlat,rlon !lat/lon in degrees for Anfovs
26 INTEGER :: isurf_height, isurf_type !height/type for Anfovs
27 REAL*4 :: satzen,satazi,solzen,solazi !scan angles for Anfovs
28 REAL*4 :: tbb(20) !bright temperatures
29 ! REAL*4 :: btemps(20)
30 INTEGER :: iavhrr(13),ihirsflag
31 INTEGER :: iprepro(5) ! values from pre-processing
32 REAL*4 :: clfra ! Cloud cover (<1.0)
33 REAL*4 :: ts ! Skin temperature
34 REAL*4 :: tctop ! Cloud top temperature
37 TYPE (type_rad_FY3) :: rad
38 integer :: iscan,nscan
41 integer(i_kind), allocatable :: nread(:)
43 !dongpm logical hirs2,hirs3,hirs4,msu,amsua,amsub,mhs
45 logical outside, outside_all, iuse
48 integer(i_kind) i,j,k,ifov
50 integer :: num_bufr(7), numbufr, ibufr
51 character(20) :: filename
54 integer(i_kind) itt,itx,iobs,iout
55 real(r_kind) terrain,timedif,crit,dist
56 real(r_kind) dlon_earth,dlat_earth
58 real(r_kind) tbmin,tbmax, tbbad
61 ! Instrument triplet, follow the convension of RTTOV
62 integer :: platform_id, satellite_id, sensor_id
65 integer :: year,month,day,hour,minute,second ! observation time
67 ! real :: rlat, rlon ! lat/lon in degrees for Anfovs
68 real :: satzen, satazi, solzen ,solazi ! scan angles for Anfovs
69 integer :: landsea_mask
71 ! channels' bright temperature
72 real , allocatable :: tb_inv(:) ! bright temperatures
73 ! end type bright_temperature
75 type (datalink_type), pointer :: head, p, current, prev
78 type(info_type) :: info
79 type(model_loc_type) :: loc
81 data tbmin,tbmax,tbbad / 50.0_r_kind, 550.0_r_kind, -9.99e11_r_kind /
82 integer :: num_tovs_local, num_tovs_file, num_tovs_global, num_tovs_selected
83 integer :: num_tovs_thinned, num_tovs_used, num_tovs_used_tmp
86 integer(i_kind), allocatable :: ptotal(:)
87 real , allocatable :: in(:), out(:)
88 logical :: found, head_found
90 if (trace_use) call da_trace_entry("da_read_obs_fy3")
92 ! Initialize variables
95 allocate(nread(1:rtminit_nsensor))
96 allocate(ptotal(0:num_fgat_time))
97 nread(1:rtminit_nsensor) = 0
98 ptotal(0:num_fgat_time) = 0
100 ! Set various variables depending on type of data to be read
102 ! platform_id = 1 !! for NOAA series
103 ! platform_id = 10 !! for METOP series
105 !dongpm hirs2= obstype == 'hirs2'
106 !dongpm hirs3= obstype == 'hirs3'
107 !dongpm hirs4= obstype == 'hirs4'
108 !dongpm msu= obstype == 'msu '
109 !dongpm amsua= obstype == 'amsua'
110 !dongpm amsub= obstype == 'amsub'
111 !dongpm mhs= obstype == 'mhs '
112 mwts= obstype == 'mwts '
113 mwhs= obstype == 'mwhs '
115 !dongpm if (hirs2) then
116 !dongpm sensor_id = 0
117 !dongpm step = 1.80_r_kind
118 !dongpm start = -49.5_r_kind
119 !dongpm nchan=nchan_hirs2
120 !dongpm subfgn='NC021021'
121 !dongpm rato=1.1363987_r_kind
122 !dongpm else if (hirs3) then
123 !dongpm sensor_id = 0
124 !dongpm step = 1.80_r_kind
125 !dongpm start = -49.5_r_kind
126 !dongpm nchan=nchan_hirs3
127 !dongpm subfgn='NC021025'
128 !dongpm else if (hirs4) then
129 !dongpm sensor_id = 0
130 !dongpm step = 1.80_r_kind
131 !dongpm start = -49.5_r_kind
132 !dongpm nchan=nchan_hirs4
133 !dongpm subfgn='NC021028'
134 !dongpm else if (mhs) then
135 !dongpm sensor_id = 15
136 !dongpm step = 10.0_r_kind/9.0_r_kind
137 !dongpm start = -445.0_r_kind/9.0_r_kind
138 !dongpm nchan=nchan_mhs
139 !dongpm subfgn='NC021027'
140 !dongpm else if (msu) then
141 !dongpm sensor_id = 1
142 !dongpm step = 9.474_r_kind
143 !dongpm start = -47.37_r_kind
144 !dongpm nchan=nchan_msu
145 !dongpm subfgn='NC021022'
146 !dongpm rato=1.1363987_r_kind
147 !dongpm else if (amsua) then
148 !dongpm sensor_id = 3
149 !dongpm step = three + one/three
150 !dongpm start = -48.33_r_kind
151 !dongpm nchan=nchan_amsua
152 !dongpm subfgn='NC021023'
153 !dongpm else if (amsub) then
154 !dongpm sensor_id = 4
155 !dongpm step = 1.1_r_kind
156 !dongpm start = -48.95_r_kind
157 !dongpm nchan=nchan_amsub
158 !dongpm subfgn='NC021024'
170 allocate (tb_inv(nchan))
172 num_tovs_file = 0 ! number of obs in file
173 num_tovs_global = 0 ! number of obs within whole domain
174 num_tovs_local = 0 ! number of obs within tile
175 num_tovs_thinned = 0 ! number of obs rejected by thinning
176 num_tovs_used = 0 ! number of obs entered into innovation computation
177 num_tovs_selected = 0 ! number of obs limited for debuging
178 iobs = 0 ! for thinning, argument is inout
180 ! 0.0 Open unit to satellite bufr file and read file header
181 !--------------------------------------------------------------
185 if (num_fgat_time>1) then
187 call da_get_unit(lnbufr)
188 write(filename,fmt='(A,2I1,A)') trim(infile),0,i,'.dat'
189 open(unit = lnbufr, FILE = trim(filename),iostat = iost, form = 'unformatted', STATUS = 'OLD')
196 call da_free_unit(lnbufr)
202 if (numbufr==0) numbufr=1
204 bufrfile: do ibufr=1,numbufr
205 if (num_fgat_time==1) then
206 filename=trim(infile)//'.dat'
208 if ((numbufr ==1) .and. (num_bufr(ibufr) == 0)) then
209 filename=trim(infile)//'.dat'
211 write(filename,fmt='(A,2I1,A)') trim(infile),0,num_bufr(ibufr),'.dat'
215 ! We want to use specific unit number for bufr data, so we can control the endian format in environment.
218 open(unit=lnbufr,file=trim(filename),form='unformatted', &
219 iostat = iost, status = 'old')
221 call da_warning(__FILE__,__LINE__, &
222 (/"Cannot open file "//filename/))
223 if (trace_use) call da_trace_exit("da_read_obs_fy3")
228 if ( ibufr == 1 ) then
230 ! allocate ( head % tb_inv (1:nchan) )
231 nullify ( head % next )
235 if (tovs_start > 1) then
236 write (unit=stdout,fmt='(A,I6)') " Skipping tovs obs before", tovs_start
239 obs: do while (.true.)
243 read(lnbufr,end=1000) rad
245 num_tovs_file = num_tovs_file + 1
247 ! 2.0 Extract observation location and other required information
248 ! QC1: judge if data is in the domain, read next record if not
249 !------------------------------------------------------------------------
250 ! rlat = bfr1bhdr(bufr_lat)
251 ! rlon = bfr1bhdr(bufr_lat)
252 ! if (rlon < 0.0) rlon = rlon+360.0
257 call da_llxy (info, loc, outside, outside_all)
259 if (outside_all) cycle
261 ! 3.0 Extract other information
262 !------------------------------------------------------
263 ! 3.1 Extract satellite id and scan position.
266 if(infile(5:5)=='a') then
268 elseif(infile(5:5)=='b') then
271 call da_warning(__FILE__,__LINE__,(/"Can not assimilate data from this instrument"/))
272 if (trace_use) call da_trace_exit("da_read_obs_fy3")
277 ! QC2: limb pixel rejected (not implemented)
279 ! 3.2 Extract date information.
295 write(unit=info%date_char, fmt='(i4,a,i2.2,a,i2.2,a,i2.2,a,i2.2,a,i2.2)') &
296 year, '-', month, '-', day, '_', hour, ':', minute, ':', second
298 ! QC3: time consistency check with the background date
308 call da_get_julian_time(year,month,day,hour,minute,obs_time)
310 if (obs_time < time_slots(0) .or. &
311 obs_time >= time_slots(num_fgat_time)) cycle
313 ! 3.2.1 determine FGAT index ifgat
315 do ifgat=1,num_fgat_time
316 if (obs_time >= time_slots(ifgat-1) .and. &
317 obs_time < time_slots(ifgat)) exit
320 ! 3.3 Find wrfvar instrument index from RTTOV instrument triplet
321 ! go to next data if id is not in the lists
324 do i = 1, rtminit_nsensor
325 if (platform_id == rtminit_platform(i) &
326 .and. satellite_id == rtminit_satid(i) &
327 .and. sensor_id == rtminit_sensor(i)) then
334 ! 3.4 extract satellite and solar angle
336 satzen = rad%satzen !*deg2rad ! local zenith angle
339 ! if (amsua .and. ifov .le. 15) satzen=-satzen
340 ! if (amsub .and. ifov .le. 45) satzen=-satzen
341 ! if (hirs3 .and. ifov .le. 28) satzen=-satzen
342 !dongpm if ( satzen > 65.0 ) cycle ! CRTM has a satzen > 65.0 check
343 satazi = rad%satazi*0.01 ! look angle
344 ! if (satazi<0.0) satazi = satazi+360.0
345 solzen = rad%solzen*0.01 ! solar zenith angle
346 solazi = rad%solazi*0.01 !RTTOV9_3
348 num_tovs_global = num_tovs_global + 1
349 ptotal(ifgat) = ptotal(ifgat) + 1
351 if (num_tovs_global < tovs_start) then
355 if (num_tovs_global > tovs_end) then
356 write (unit=stdout,fmt='(A,I6)') " Skipping radiance obs after", tovs_end
360 num_tovs_selected = num_tovs_selected + 1
362 if (num_tovs_selected > max_tovs_input) then
363 write(unit=message(1),fmt='(A,I10,A)') &
364 "Max number of tovs",max_tovs_input," reached"
365 call da_warning(__FILE__,__LINE__,message(1:1))
366 num_tovs_selected = num_tovs_selected-1
367 num_tovs_global = num_tovs_global-1
368 ptotal(ifgat) = ptotal(ifgat) - 1
372 if (outside) cycle ! No good for this PE
373 num_tovs_local = num_tovs_local + 1
376 ! Map obs to thinning grid
377 !-------------------------------------------------------------------
379 dlat_earth = info%lat
380 dlon_earth = info%lon
381 if (dlon_earth<zero) dlon_earth = dlon_earth+r360
382 if (dlon_earth>=r360) dlon_earth = dlon_earth-r360
383 dlat_earth = dlat_earth*deg2rad
384 dlon_earth = dlon_earth*deg2rad
385 timedif = 0.0 !2.0_r_kind*abs(tdiff) ! range: 0 to 6
386 !dongpm terrain = 0.01_r_kind*abs(bfr1bhdr(13))
387 terrain = 0.01_r_kind*abs(rad%satzen)
388 crit = 1.0 !0.01_r_kind+terrain + timedif !+ 10.0_r_kind*float(iskip)
389 call map2grids(inst,ifgat,dlat_earth,dlon_earth,crit,iobs,itx,1,itt,iout,iuse)
391 num_tovs_thinned=num_tovs_thinned+1
396 num_tovs_used = num_tovs_used + 1
397 nread(inst) = nread(inst) + 1
399 ! 3.5 extract surface information
400 srf_height = rad%isurf_height ! station height
401 if (srf_height < 8888.0 .AND. srf_height > -416.0) then
406 !dongpm landsea_mask = rad%isurf_type ! 0:land ; 1:sea (same as RTTOV)
407 !fy3 isurf_type is just reversed as RTTOV
408 if(rad%isurf_type .eq. 0) then ! sea
410 elseif(rad%isurf_type .eq. 1) then !coast
412 elseif(rad%isurf_type .eq. 2) then !land
415 landsea_mask = rad%isurf_type
416 write(unit=message(1),fmt='(A,I6)') 'Unknown surface type: ', landsea_mask
417 call da_warning(__FILE__,__LINE__,message(1:1))
420 ! if (nint(bfr1bhdr(bufr_landsea_mask))==1) rmask=0.0_r_kind ! reverse the land/sea mask in bufr
421 ! landsea_mask = rmask+.001_r_kind ! land sea mask
423 info%elv = srf_height
425 ! 3.6 extract channel bright temperature
427 tb_inv(1:nchan) = rad%tbb(1:nchan)
429 if ( tb_inv(k) < tbmin .or. tb_inv(k) > tbmax) &
430 tb_inv(k) = missing_r
432 if ( all(tb_inv<0.0) ) then
433 num_tovs_local = num_tovs_local -1
434 num_tovs_used = num_tovs_used - 1
435 nread(inst) = nread(inst) - 1
439 ! 4.0 assign information to sequential radiance structure
440 !--------------------------------------------------------------------------
441 allocate (p % tb_inv (1:nchan))
444 p%landsea_mask = landsea_mask
449 p%tb_inv(1:nchan) = tb_inv(1:nchan)
450 p%sensor_index = inst
455 allocate (p%next) ! add next data
467 if (thinning .and. num_tovs_global > 0 ) then
471 ! Get minimum crit and associated processor index.
473 do ifgat = 1, num_fgat_time
474 do n = 1, iv%num_inst
475 j = j + thinning_grid(n,ifgat)%itxmax
483 do ifgat = 1, num_fgat_time
484 do n = 1, iv%num_inst
485 do i = 1, thinning_grid(n,ifgat)%itxmax
487 in(j) = thinning_grid(n,ifgat)%score_crit(i)
491 call mpi_reduce(in, out, j, true_mpi_real, mpi_min, root, comm, ierr)
493 call wrf_dm_bcast_real (out, j)
496 do ifgat = 1, num_fgat_time
497 do n = 1, iv%num_inst
498 do i = 1, thinning_grid(n,ifgat)%itxmax
500 if ( ABS(out(j)-thinning_grid(n,ifgat)%score_crit(i)) > 1.0E-10 ) thinning_grid(n,ifgat)%ibest_obs(i) = 0
510 ! Delete the nodes which being thinning out
514 num_tovs_used_tmp = num_tovs_used
515 do j = 1, num_tovs_used_tmp
520 do i = 1, thinning_grid(n,ifgat)%itxmax
521 if ( thinning_grid(n,ifgat)%ibest_obs(i) == j .and. thinning_grid(n,ifgat)%score_crit(i) < 9.99e6_r_kind ) then
528 if ( .not. found ) then
531 if ( head_found ) then
537 deallocate ( current % tb_inv )
538 deallocate ( current )
539 num_tovs_thinned = num_tovs_thinned + 1
540 num_tovs_used = num_tovs_used - 1
541 nread(n) = nread(n) - 1
545 if ( found .and. head_found ) then
551 if ( found .and. .not. head_found ) then
560 endif ! End of thinning
562 iv%total_rad_pixel = iv%total_rad_pixel + num_tovs_used
563 iv%total_rad_channel = iv%total_rad_channel + num_tovs_used*nchan
565 iv%info(radiance)%nlocal = iv%info(radiance)%nlocal + num_tovs_used
566 iv%info(radiance)%ntotal = iv%info(radiance)%ntotal + num_tovs_global
568 do i = 1, num_fgat_time
569 ptotal(i) = ptotal(i) + ptotal(i-1)
570 iv%info(radiance)%ptotal(i) = iv%info(radiance)%ptotal(i) + ptotal(i)
572 if ( iv%info(radiance)%ptotal(num_fgat_time) /= iv%info(radiance)%ntotal ) then
573 write(unit=message(1),fmt='(A,I10,A,I10)') &
574 "Number of ntotal:",iv%info(radiance)%ntotal," is different from the sum of ptotal:", iv%info(radiance)%ptotal(num_fgat_time)
575 call da_warning(__FILE__,__LINE__,message(1:1))
578 write(unit=stdout,fmt='(a)') 'num_tovs_file num_tovs_global num_tovs_local num_tovs_used num_tovs_thinned'
579 write(unit=stdout,fmt='(5i10)') num_tovs_file,num_tovs_global, num_tovs_local,num_tovs_used,num_tovs_thinned
583 ! 5.0 allocate innovation radiance structure
584 !----------------------------------------------------------------
586 do i = 1, iv%num_inst
587 if (nread(i) < 1) cycle
588 iv%instid(i)%num_rad = nread(i)
589 iv%instid(i)%info%nlocal = nread(i)
590 write(UNIT=stdout,FMT='(a,i3,2x,a,3x,i10)') &
591 'Allocating space for radiance innov structure', &
592 i, iv%instid(i)%rttovid_string, iv%instid(i)%num_rad
594 call da_allocate_rad_iv(i,nchan,iv)
598 ! 6.0 assign sequential structure to innovation structure
599 !-------------------------------------------------------------
600 nread(1:rtminit_nsensor) = 0
602 ! do while ( associated(p) )
604 do n = 1, num_tovs_used
606 nread(i) = nread(i) + 1
608 call da_initialize_rad_iv (i, nread(i), iv, p)
614 deallocate ( current % tb_inv )
615 deallocate ( current )
623 ! check if sequential structure has been freed
626 ! do i = 1, num_rad_selected
627 ! write (unit=stdout,fmt=*) i, p%tb_inv(1:nchan)
631 if (trace_use) call da_trace_exit("da_read_obs_fy3")
635 end subroutine da_read_obs_fy3