1 subroutine da_read_obs_bufrgpsro (iv)
3 !---------------------------------------------------------------------------
4 ! Purpose: Read NCEP GPSRO BUFR observation file for input to wrfvar
5 !---------------------------------------------------------------------------
6 ! METHOD: use F90 sequantial data structure to avoid read file twice
7 ! so that da_scan_obs_bufr is not necessary any more.
8 ! 1. read gpsro data in sequential data structure
10 ! 3. assign sequential data structure to innovation structure
11 ! and deallocate sequential data structure
13 ! HISTORY: 2009/12/17 - F90 sequantial structure Peng Xiu
15 !----------------------------------------------------------------------------
21 type (iv_type), intent(inout) :: iv
25 real, parameter :: r8bfms = 9.0D08 ! BUFR missing value threshold
26 integer, parameter :: maxlevs = 500
27 integer :: iunit, iost, idate, iret, nlev1, nlev2,k,i,ii
28 integer :: num_report, num_outside_all, num_outside_time
29 integer :: iyear,imonth,iday,ihour,imin
30 integer :: ntotal, nlocal, nlev, ref_qc
33 real :: ntotal_ifgat(0:num_fgat_time)
34 real*8 :: rdata1(25,maxlevs), rdata2(25,maxlevs)
35 real :: height, ref_data, ref_error
36 character(len=8) :: subset
37 character(len=80) :: hdstr
38 character(len=12) :: filename
39 logical :: outside, outside_all
40 type(info_type) :: info
41 type(model_loc_type) :: loc
42 character(len=5) :: id
43 character(len=19) :: date_char
44 integer :: ifgat, kk, num_p
45 integer :: err_opt ! 1: WRF-Var/obsproc, 2: GSI
46 real :: erh90, erh0, err90, err0
47 integer(i_kind) :: ireadns
48 integer :: num_bufr(7), numbufr, ibufr
49 type datalink_gpsro !for gpsro data reading
50 type (info_type) :: info
51 type(model_loc_type) :: loc
52 type (gpsref_type) :: gpsref
54 type (field_type) :: slp
55 type (field_type) :: pw
56 integer :: obs_global_index
57 type(datalink_gpsro), pointer :: next
58 end type datalink_gpsro
59 type(datalink_gpsro),pointer :: head=>null(), plink=>null()
60 integer(i_kind) :: iprof
62 if (trace_use) call da_trace_entry("da_read_obs_bufrgosro")
71 ntotal_ifgat(0:num_fgat_time)=0
77 if (num_fgat_time>1) then
79 call da_get_unit(iunit)
80 write(filename,fmt='(A,I1,A)') 'gpsro0',i,'.bufr'
81 open(unit = iunit, FILE = trim(filename),iostat = iost, form = 'unformatted', STATUS = 'OLD')
88 call da_free_unit(iunit)
94 if (numbufr==0) numbufr=1
96 bufrfile: do ibufr=1,numbufr
97 if (num_fgat_time==1) then
100 if ((numbufr ==1) .and. (num_bufr(ibufr) == 0)) then
101 filename='gpsro.bufr'
103 write(filename,fmt='(A,I1,A)') 'gpsro0',num_bufr(ibufr),'.bufr'
107 ! Use specified unit number, so we can control its endian format in environment.
110 open(unit = iunit, FILE = trim(filename), &
111 iostat = iost, form = 'unformatted', STATUS = 'OLD')
113 write(unit=message(1),fmt='(A,I5,A)') &
114 "Error",iost," opening PREPBUFR obs file "//trim(filename)
115 call da_warning(__FILE__,__LINE__,message(1:1))
116 if (trace_use) call da_trace_exit("da_read_obs_bufrgpsro")
120 !--------------------------------
121 ! open bufr file then check date
122 !--------------------------------
123 call openbf(iunit,'IN',iunit)
125 call readmg(iunit,subset,idate,iret)
126 if ( iret /= 0 ) then
127 write(unit=message(1),fmt='(A,I5,A)') &
128 "Error",iret," reading GPSRO BUFR obs file "//trim(filename)
129 call da_warning(__FILE__,__LINE__,message(1:1))
132 if (trace_use) call da_trace_exit("da_read_obs_bufrgpsro")
135 write(unit=message(1),fmt='(a,i10)') 'GPSRO BUFR file date is: ', idate
136 call da_message(message(1:1))
139 hdstr = 'YEAR MNTH DAYS HOUR MINU PCCF ELRC SAID PTID GEODU'
141 reports: do while ( ireadns(iunit,subset,idate) == 0 )
143 num_report = num_report + 1
145 call ufbint(iunit,hdr,10,1,iret,hdstr)
153 write(id, '(i3.3,i2.2)') int(hdr(8)), int(hdr(9)) ! construct id using SAID and PTID
154 write(date_char, fmt='(i4,a,i2.2,a,i2.2,a,i2.2,a,i2.2,a,i2.2)') &
155 iyear, '-', imonth, '-', iday, '_', ihour, ':', imin, ':', 0
158 call da_get_julian_time (iyear,imonth,iday,ihour,imin,obs_time)
159 if (obs_time < time_slots(0) .or. &
160 obs_time >= time_slots(num_fgat_time)) then
161 num_outside_time = num_outside_time + 1
162 if ( print_detail_obs ) then
163 write(unit=stderr,fmt='(a,1x,i4.4,4i2.2,a)') &
164 info%id(1:5),iyear,imonth,iday,ihour,imin, ' -> outside_time'
169 if ( hdr(6) < 100.0 ) then ! check percentage of confidence PCCF
173 call ufbseq(iunit,rdata1,25,maxlevs,nlev1,'ROSEQ1') ! RAOC PROFILE LOCATIONS SEQUENCE
174 call ufbseq(iunit,rdata2,25,maxlevs,nlev2,'ROSEQ3') ! RAOC HEIGHT/REFRACTIVITY SEQUENCE
176 if ( nlev1 /= nlev2 ) then
180 !-------- determine FGAT index ifgat
182 do ifgat=1,num_fgat_time
183 if (obs_time >= time_slots(ifgat-1) .and. &
184 obs_time < time_slots(ifgat)) exit
189 lev_loop: do k = 1, nlev1
191 info%lat = rdata1(1,k)
192 info%lon = rdata1(2,k)
194 ! gpsro.bufr contains missing longitude, occasionally
195 if ( info%lat > r8bfms .or. info%lon > r8bfms ) then
200 ref_data = rdata2(2,k)
202 ! check for missing data
203 if ( height > r8bfms .or. ref_data > r8bfms ) then
207 ref_qc = 0 ! initialized to be good
208 ref_error = ref_data * 0.01
211 info%lat = max(info%lat, -89.95)
212 info%lat = min(info%lat, 89.95)
213 call da_llxy(info, loc, outside, outside_all)
214 if ( outside_all ) then
215 num_outside_all = num_outside_all + 1
216 if ( print_detail_obs ) then
217 write(unit=stderr,fmt='(a,2(1x,f8.3),a)') &
218 id(1:5), info%lat, info%lon, ' -> outside_domain'
223 ntotal_ifgat(ifgat)=ntotal_ifgat(ifgat)+1
229 ! check height, only keep data below certain height (default is 30km)
230 if ( height > top_km_gpsro*1000.0 .or. &
231 height < bot_km_gpsro*1000.0 ) then
236 ! observation errors WRF-Var/obsproc
237 if ( err_opt == 1 ) then
238 if ( height >= 12000.0 ) then
239 ref_error = ref_error * 0.3
241 erh90 = (0.3-1.5)*(height-12000.0)/(12000.0-0.0) + 0.3
242 if ( height >= 5500.0 ) then
243 erh0 = (0.3-1.3)*(height-12000.0)/(12000.0-5500.0) + 0.3
244 else if ( height >= 2500.0) then
245 erh0 = (1.3-2.5)*(height-5500.0)/(5500.0-2500.0) + 1.3
249 err90 = ref_error * erh90
250 err0 = ref_error * erh0
251 ref_error = err90 - (1.0-abs(info%lat)/90.0)*(err90-err0)
255 ! observation errors GSI_Q1FY09, Kuo et al. 2003
256 if ( err_opt == 2 ) then
257 if ( (info%lat >= -30.0) .and. (info%lat <= 30.0) ) then ! tropics
258 if ( (height >= 7000.0) .and. (height <= 31000.0) ) then
259 ref_error = ref_error*(0.1125+(1.25e-5*height))
260 else if ( height > 31000.0 ) then
261 ref_error = ref_error*0.5
262 else if ( height < 7000.0 ) then
263 ref_error = ref_error*(3.0-(4.0e-4*height))
265 write(unit=message(1),fmt='(a,f8.1,a,f8.2)') 'unable to process with height = ', &
266 height, ' at lat = ', info%lat
267 call da_error(__FILE__,__LINE__,message(1:1))
270 if ( (height >= 5000.0) .and. (height <= 25000.0) ) then
271 ref_error = ref_error*0.3
272 else if ( (height >= 25000.0) .and. (height <= 31000.0) ) then
273 ref_error = ref_error*(-3.45+(1.5e-4*height))
274 else if ( height > 31000.0 ) then
275 ref_error = ref_error*1.2
276 else if ( height < 5000.0 ) then
277 ref_error = ref_error*(0.75-(9.0e-5*height))
279 write(unit=message(1),fmt='(a,f8.1,a,f8.2)') 'unable to process with height = ', &
280 height, ' at lat = ', info%lat
281 call da_error(__FILE__,__LINE__,message(1:1))
286 !write(info%name, '(a,i6.6,a,a)') 'NCEP_GPSRO_', nlocal, '_', date_char
287 write(info%name, '(a,i6.6,a,a)') 'NCEP_GPSRO_', iprof, '_', date_char
289 if ( print_detail_obs ) then
290 write(unit=stdout,fmt='(a,1x,a,1x,i4.4,4i2.2,2f8.2,f8.1,f8.2,i3,f9.5)') &
291 info%name,id(1:5),iyear,imonth,iday,ihour,imin, &
292 info%lat,info%lon,height,ref_data,ref_qc,ref_error
295 if (.not. associated(head)) then
298 nullify ( head%next )
301 allocate ( plink%next )
303 nullify ( plink%next )
306 plink%info%name = info%name
307 plink%info%platform = 'FM-116 GPSRF'
309 plink%info%date_char = date_char
310 plink%info%levels = 1 ! each level is treated as separate obs
311 plink%info%elv = 0.0 ! not used
312 plink%info%lat = info%lat
313 plink%info%lon = info%lon
319 plink%loc%dx = loc%dx
320 plink%loc%dxm = loc%dxm
321 plink%loc%dy = loc%dy
322 plink%loc%dym = loc%dym
324 plink%slp%inv = missing_r
325 plink%slp%qc = missing_data
326 plink%slp%error = xmiss
327 plink%pw%inv = missing_r
328 plink%pw%qc = missing_data
329 plink%pw%error = xmiss
331 plink%obs_global_index = ntotal
334 allocate (plink%gpsref%h (1:nlev))
335 allocate (plink%gpsref%ref(1:nlev))
336 allocate (plink%gpsref%p (1:nlev))
337 allocate (plink%gpsref%t (1:nlev))
338 allocate (plink%gpsref%q (1:nlev))
340 plink%gpsref%h(i) = height
341 plink%gpsref%ref(i)%inv = ref_data
342 plink%gpsref%ref(i)%qc = ref_qc
343 plink%gpsref%ref(i)%error = ref_error
344 plink%gpsref%p(i)%inv = missing_r
345 plink%gpsref%p(i)%qc = missing_data
346 plink%gpsref%p(i)%error = xmiss
347 plink%gpsref%t(i)%inv = missing_r
348 plink%gpsref%t(i)%qc = missing_data
349 plink%gpsref%t(i)%error = xmiss
350 plink%gpsref%q(i)%inv = missing_r
351 plink%gpsref%q(i)%qc = missing_data
352 plink%gpsref%q(i)%error = xmiss
365 iv%info(gpsref)%ntotal=ntotal
366 iv%info(gpsref)%nlocal=nlocal
367 iv%info(gpsref)%max_lev=1
371 if (iv%info(gpsref)%nlocal > 0) allocate(iv%gpsref(1:iv%info(gpsref)%nlocal))
373 if (iv%info(gpsref)%nlocal > 0) then
374 allocate (iv%info(gpsref)%name(iv%info(gpsref)%nlocal))
375 allocate (iv%info(gpsref)%platform(iv%info(gpsref)%nlocal))
376 allocate (iv%info(gpsref)%id(iv%info(gpsref)%nlocal))
377 allocate (iv%info(gpsref)%date_char(iv%info(gpsref)%nlocal))
378 allocate (iv%info(gpsref)%levels(iv%info(gpsref)%nlocal))
379 allocate (iv%info(gpsref)%lat(iv%info(gpsref)%max_lev,iv%info(gpsref)%nlocal))
380 allocate (iv%info(gpsref)%lon(iv%info(gpsref)%max_lev,iv%info(gpsref)%nlocal))
381 allocate (iv%info(gpsref)%elv(iv%info(gpsref)%nlocal))
382 allocate (iv%info(gpsref)%pstar(iv%info(gpsref)%nlocal))
383 allocate (iv%info(gpsref)%slp(iv%info(gpsref)%nlocal))
384 allocate (iv%info(gpsref)%pw(iv%info(gpsref)%nlocal))
385 allocate (iv%info(gpsref)%x (kms:kme,iv%info(gpsref)%nlocal))
386 allocate (iv%info(gpsref)%y (kms:kme,iv%info(gpsref)%nlocal))
387 allocate (iv%info(gpsref)%i (kms:kme,iv%info(gpsref)%nlocal))
388 allocate (iv%info(gpsref)%j (kms:kme,iv%info(gpsref)%nlocal))
389 allocate (iv%info(gpsref)%dx (kms:kme,iv%info(gpsref)%nlocal))
390 allocate (iv%info(gpsref)%dxm(kms:kme,iv%info(gpsref)%nlocal))
391 allocate (iv%info(gpsref)%dy (kms:kme,iv%info(gpsref)%nlocal))
392 allocate (iv%info(gpsref)%dym(kms:kme,iv%info(gpsref)%nlocal))
393 allocate (iv%info(gpsref)%k (iv%info(gpsref)%max_lev,iv%info(gpsref)%nlocal))
394 allocate (iv%info(gpsref)%dz (iv%info(gpsref)%max_lev,iv%info(gpsref)%nlocal))
395 allocate (iv%info(gpsref)%dzm(iv%info(gpsref)%max_lev,iv%info(gpsref)%nlocal))
396 allocate (iv%info(gpsref)%zk (iv%info(gpsref)%max_lev,iv%info(gpsref)%nlocal))
397 allocate (iv%info(gpsref)%proc_domain(iv%info(gpsref)%max_lev,iv%info(gpsref)%nlocal))
398 allocate (iv%info(gpsref)%thinned(iv%info(gpsref)%max_lev,iv%info(gpsref)%nlocal))
399 allocate (iv%info(gpsref)%obs_global_index(iv%info(gpsref)%nlocal))
400 iv%info(gpsref)%proc_domain(:,:) = .false.
401 iv%info(gpsref)%thinned(:,:) = .false.
402 iv%info(gpsref)%zk(:,:) = missing_r
407 do kk=1,num_fgat_time
409 iv%info(gpsref)%ptotal(kk)=0
411 reports2: do ii=1,num_p
413 if (plink%ifgat /= kk) then !sort iv
418 iv%info(gpsref)%name(nlocal) = plink%info%name
419 iv%info(gpsref)%platform(nlocal) = plink%info%platform
420 iv%info(gpsref)%id(nlocal) = plink%info%id
421 iv%info(gpsref)%date_char(nlocal) = plink%info%date_char
422 iv%info(gpsref)%levels(nlocal) = plink%info%levels ! each level is treated as separate obs
423 iv%info(gpsref)%elv(nlocal) = plink%info%elv ! not used
424 iv%info(gpsref)%lat(:,nlocal) = plink%info%lat
425 iv%info(gpsref)%lon(:,nlocal) = plink%info%lon
427 iv%info(gpsref)%x(:,nlocal) = plink%loc%x
428 iv%info(gpsref)%y(:,nlocal) = plink%loc%y
429 iv%info(gpsref)%i(:,nlocal) = plink%loc%i
430 iv%info(gpsref)%j(:,nlocal) = plink%loc%j
431 iv%info(gpsref)%dx(:,nlocal) = plink%loc%dx
432 iv%info(gpsref)%dxm(:,nlocal) = plink%loc%dxm
433 iv%info(gpsref)%dy(:,nlocal) = plink%loc%dy
434 iv%info(gpsref)%dym(:,nlocal) = plink%loc%dym
436 iv%info(gpsref)%slp(nlocal)%inv = plink%slp%inv
437 iv%info(gpsref)%slp(nlocal)%qc = plink%slp%qc
438 iv%info(gpsref)%slp(nlocal)%error = plink%slp%error
439 iv%info(gpsref)%pw(nlocal)%inv = plink%pw%inv
440 iv%info(gpsref)%pw(nlocal)%qc = plink%pw%qc
441 iv%info(gpsref)%pw(nlocal)%error = plink%pw%error
443 iv%info(gpsref)%obs_global_index(nlocal) = plink%obs_global_index
446 allocate (iv%gpsref(nlocal)%h (1:nlev))
447 allocate (iv%gpsref(nlocal)%ref(1:nlev))
448 allocate (iv%gpsref(nlocal)%p (1:nlev))
449 allocate (iv%gpsref(nlocal)%t (1:nlev))
450 allocate (iv%gpsref(nlocal)%q (1:nlev))
453 iv%gpsref(nlocal)%h(i) = plink%gpsref%h(i)
454 iv%gpsref(nlocal)%ref(i)%inv = plink%gpsref%ref(i)%inv
455 iv%gpsref(nlocal)%ref(i)%qc = plink%gpsref%ref(i)%qc
456 iv%gpsref(nlocal)%ref(i)%error = plink%gpsref%ref(i)%error
458 iv%gpsref(nlocal)%p(i)%inv = plink%gpsref%p(i)%inv
459 iv%gpsref(nlocal)%p(i)%qc = plink%gpsref%p(i)%qc
460 iv%gpsref(nlocal)%p(i)%error = plink%gpsref%p(i)%error
461 iv%gpsref(nlocal)%t(i)%inv = plink%gpsref%t(i)%inv
462 iv%gpsref(nlocal)%t(i)%qc = plink%gpsref%t(i)%qc
463 iv%gpsref(nlocal)%t(i)%error = plink%gpsref%t(i)%error
464 iv%gpsref(nlocal)%q(i)%inv = plink%gpsref%q(i)%inv
465 iv%gpsref(nlocal)%q(i)%qc = plink%gpsref%q(i)%qc
466 iv%gpsref(nlocal)%q(i)%error = plink%gpsref%q(i)%error
472 ntotal_ifgat(kk)=ntotal_ifgat(kk)+ntotal_ifgat(kk-1)
473 iv%info(gpsref)%ptotal(kk)=ntotal_ifgat(kk)
474 iv%info(gpsref)%plocal(kk)=nlocal
475 ! thinning is not applied to GPSRO BUFR, simply make a copy from total number
476 iv%info(gpsref)%thin_ptotal(kk)=ntotal_ifgat(kk)
477 iv%info(gpsref)%thin_plocal(kk)=nlocal
480 write(unit=message(1),fmt='(A,3(1x,i7))') &
481 'da_read_obs_bufrgpsro: num_report, num_outside_all, num_outside_time: ', &
482 num_report, num_outside_all, num_outside_time
483 call da_message(message(1:1))
485 if ( nlocal /= iv%info(gpsref)%nlocal ) then
486 call da_error(__FILE__,__LINE__,(/"numbers mismatch between scanning and reading NCEP GSPRO BUFR file"/))
489 ! Release the linked list
492 DO WHILE ( ASSOCIATED (plink) )
494 deallocate (plink%gpsref%h)
495 deallocate (plink%gpsref%ref)
496 deallocate (plink%gpsref%p)
497 deallocate (plink%gpsref%t)
498 deallocate (plink%gpsref%q)
505 if (trace_use) call da_trace_exit("da_read_obs_bufrgpsro")
507 call da_error(__FILE__,__LINE__,(/"must compile with BUFR library"/))
510 end subroutine da_read_obs_bufrgpsro