1 subroutine da_read_obs_bufr_satwnd(filename, iv, ob)
5 character(len=*), intent(in) :: filename
6 type (iv_type), intent(inout) :: iv
7 type (y_type), intent(inout) :: ob
9 integer, parameter :: i_kind = selected_int_kind(8)
10 integer, parameter :: r_double = selected_real_kind(15) ! double precision
11 integer, parameter :: r_kind = selected_real_kind(15) ! double precision
13 integer(i_kind), parameter :: missing_i = -999
14 real(r_kind), parameter :: missing_r = -999.0
16 integer(i_kind), parameter :: nstring = 50
17 integer(i_kind), parameter :: nmeta = 3 ! number of metadata
18 integer(i_kind), parameter :: nvars = 2 ! number of obs variables
20 character(len=nstring), dimension(nmeta) :: name_meta = &
27 character(len=nstring), dimension(nvars) :: name_vars = &
33 integer(i_kind) :: idx_p = 1
34 integer(i_kind) :: idx_lat = 2
35 integer(i_kind) :: idx_lon = 3
36 integer(i_kind) :: idx_u = 1
37 integer(i_kind) :: idx_v = 2
40 character(len=nstring) :: stid ! station identifier
41 character(len=nstring) :: name ! instrument name
42 character(len=nstring) :: date_char ! ccyy-mm-dd_hh:mm:ss
43 integer(i_kind) :: satid ! satellite identifier
44 integer(i_kind) :: rptype ! prepbufr report type
45 integer(i_kind) :: ifgat ! index of time slot
46 integer(i_kind) :: itg ! index of thinning grid
47 integer(i_kind) :: qm ! quality marker
48 real(r_double) :: tdiff ! time difference between obs_time and analysis_time
49 real(r_kind) :: err ! ob error
50 real(r_kind) :: lat ! latitude in degree
51 real(r_kind) :: lon ! longitude in degree
52 real(r_kind) :: prs ! pressure
53 real(r_kind) :: landsea ! land sea qualifier 0:land, 1:sea, 2:coast
54 real(r_kind) :: satzen ! satellite zenith angle in degree
59 real(r_kind) :: cvwd ! coefficient of variation
60 real(r_kind) :: pccf1 ! percent confidence, Quality Index without forecast (qifn)
61 real(r_kind) :: pccf2 ! percent confidence, Estimated Error (EE) in m/s converted to percent confidence
63 type (datalink_satwnd), pointer :: next ! pointer to next data
64 end type datalink_satwnd
66 type(datalink_satwnd), pointer :: rhead=>null(), rlink=>null()
68 real(r_kind), parameter :: r8bfms = 9.0E08 ! threshold to check for BUFR missing value
69 real(r_kind), parameter :: pi = acos(-1.0)
71 integer(i_kind), parameter :: ntime = 6 ! number of data to read in timestr
72 integer(i_kind), parameter :: ninfo = 5 ! number of data to read in infostr
73 integer(i_kind), parameter :: nlalo = 2 ! number of data to read in lalostr
74 integer(i_kind), parameter :: ndata = 3 ! number of data to read in datastr
75 integer(i_kind), parameter :: nqc1 = 2 ! number of data to read in qc1str
76 integer(i_kind), parameter :: nqc2 = 2 ! number of data to read in qc2str
78 character(len=80) :: timestr, infostr, lalostr, datastr, qc1str, qc2str
80 real(r_double), dimension(ntime) :: timedat
81 real(r_double), dimension(ninfo) :: infodat
82 real(r_double), dimension(nlalo) :: lalodat
83 real(r_double), dimension(ndata) :: wdata
84 real(r_double), dimension(nqc1,2) :: qc1dat
85 real(r_double), dimension(nqc2,4) :: qc2dat
87 integer(i_kind), parameter :: nmsgtyp = 10 ! number of message types to process
88 ! message types that are not processed into prepbufr
89 character(len=8), dimension(nmsgtyp) :: message_types = &
96 'NC005081', & ! not tested
101 character(len=8) :: subset
103 integer(i_kind) :: iunit, iost, iret
104 integer(i_kind) :: k, kx, ilev, itype, ivar
105 integer(i_kind) :: idate
106 integer(i_kind) :: num_report_infile
107 integer(i_kind) :: ireadmg, ireadsb
109 integer(i_kind) :: iyear, imonth, iday, ihour, imin, isec
110 real(r_double) :: obs_time, analysis_time
112 logical :: outside, outside_all
113 logical :: use_errtable
116 real(r_kind) :: xlat, xlon, prs
117 real(r_kind) :: angearth
118 type(info_type) :: xinfo
119 type(model_loc_type) :: xloc1
121 integer, allocatable :: itmp(:)
122 character(len=nstring), allocatable :: str_stid(:)
123 character(len=nstring), allocatable :: str_name(:)
124 character(len=nstring), allocatable :: date_char(:) ! date_time string in wrf format
125 type(model_loc_type), allocatable :: xloc(:)
126 logical, allocatable :: inside_domain(:)
127 logical, allocatable :: inside_patch(:)
128 integer(i_kind), allocatable :: iwindow(:)
129 integer(i_kind), allocatable :: rptype(:)
130 real(r_kind), allocatable :: tdiff_avg(:)
131 real(r_kind), allocatable :: num_val(:)
132 real(r_kind), allocatable :: num_err(:)
133 real(r_kind), allocatable :: num_meta(:)
134 real(r_kind), allocatable :: sdata_val(:,:)
135 real(r_kind), allocatable :: sdata_err(:,:)
136 real(r_kind), allocatable :: smeta(:,:)
137 character(len=14) :: cdate14 ! ccyymmddhhnnss used in da_advance_time
138 character(len=10) :: adate10 ! ccyymmddhh used in da_advance_time
139 character(len=14) :: tdiff_char
141 integer(i_kind) :: i, ii, kk, n, isize
142 integer(i_kind) :: num_outside_domain, num_outside_time
143 integer(i_kind) :: num_qc_fail
144 integer(i_kind) :: ntotal, nlocal, max_lev, nlev, nlevel
145 integer(i_kind) :: itotal, ilocal, ifgat
146 integer(i_kind) :: ntotal_ifgat(0:num_fgat_time)
149 real(r_kind) :: err_val
150 real(r_kind) :: uob, vob
151 real(r_kind) :: u_grid, v_grid
154 real(r_kind) :: dlat_earth, dlon_earth, crit
155 integer(i_kind) :: nobs, icnt, num_date
156 integer(i_kind) :: iobs, itt, itx, iout
157 integer(i_kind) :: num_thinned, num_keep
160 real(r_kind) :: c1, c2
161 ! for superobbing in vertical
163 integer(i_kind) :: nplev
164 real(r_kind), allocatable :: plev(:)
166 continue ! end of declaration
168 inquire(file=trim(filename), exist=fexist)
169 if ( .not. fexist ) then
170 write(unit=message(1),fmt='(a)') trim(filename)//' does not exist.'
171 call da_warning(__FILE__,__LINE__,message(1:1))
175 if ( thin_conv_opt(polaramv) == thin_single ) then
176 thin_conv_opt(polaramv) = thin_multi
177 write(unit=message(1),fmt='(a,2i5)') 'thin_conv_opt(polaramv)=1 is not implemented, resetting to thin_conv_opt(polaramv)=2'
178 call da_message(message(1:1))
181 timestr = 'YEAR MNTH DAYS HOUR MINU SECO'
182 infostr = 'SAID LSQL SAZA OGCE SWCM'
183 lalostr = 'CLATH CLONH'
184 datastr = 'PRLC WDIR WSPD'
186 qc2str = 'GNAPS PCCF'
188 ! oetab(300,33,6) processed in da_setup_obs_structures_bufr.inc
189 use_errtable = allocated(oetab)
191 num_report_infile = 0
193 allocate (itmp(1)) ! for broadcasting nobs
195 ! only rootproc reads from file
196 ! thinning check is also done on rootproc only
199 write(unit=message(1),fmt='(a)') 'Reading from '//trim(filename)
200 call da_message(message(1:1))
203 call da_get_unit(iunit)
204 open (unit=iunit, file=trim(filename), &
205 iostat=iost, form='unformatted', status='old')
207 write(unit=message(1),fmt='(a,i5,a)') &
208 "Error",iost," opening BUFR obs file "//trim(filename)
209 call da_warning(__FILE__,__LINE__,message(1:1))
213 call openbf(iunit,'IN',iunit)
215 call readmg(iunit,subset,idate,iret)
217 if ( iret /= 0 ) then
218 write(unit=message(1),fmt='(A,I5,A)') &
219 "Error",iret," reading BUFR obs file "//trim(filename)
222 call da_free_unit(iunit)
223 call da_warning(__FILE__,__LINE__,message(1:1))
228 write(unit=message(1),fmt='(a,i10)') 'da_read_obs_bufr_satwnd: '//trim(filename)//' file date is: ', idate
229 call da_message(message(1:1))
231 read (analysis_date,'(i4,4(1x,i2))') iyear, imonth, iday, ihour, imin
232 call da_get_julian_time (iyear,imonth,iday,ihour,imin,analysis_time)
233 adate10 = analysis_date(1:4)//analysis_date(6:7)//analysis_date(9:10)//analysis_date(12:13)
235 ! initialize counters
236 num_outside_domain = 0
242 if ( thin_conv_opt(polaramv) > no_thin ) then
243 call cleangrids_conv(polaramv)
244 iobs = 0 ! initialize an intent(inout) variable used by map2grids_conv
245 ! itxmax is calculated in subroutine make3grids called in da_setup_obs_structures_bufr
246 ! itxmax is horizontal thinning grids when thin_conv_opt/=thin_superob_hv
247 ! itxmax is horizontal*vertical thinning grids when thin_conv_opt==thin_superob_hv
248 write(unit=message(1),fmt='(a,i8)') &
249 'da_read_obs_bufr_satwnd: number of thinning grids = ', thinning_grid_conv(polaramv)%itxmax
250 call da_message(message(1:1))
251 if ( thin_conv_opt(polaramv) == thin_superob_hv ) then
252 !to-do: nplev and plev should be set in make3grids and stored in thinning_grid_conv structure
253 nplev = int(1200/thin_mesh_vert_conv(polaramv))
254 allocate (plev(nplev))
256 plev(k) = 1200.0 - (k-1)*thin_mesh_vert_conv(polaramv)
261 if ( .not. associated(rhead) ) then
264 nullify ( rhead%next )
267 if ( .not. associated(rlink) ) then
270 allocate ( rlink%next )
272 nullify ( rlink%next )
275 msg_loop: do while (ireadmg(iunit,subset,idate)==0)
277 if ( ufo_vars_getindex(message_types, subset) <= 0 ) then
278 ! skip types other than GOES-16/17, AVHRR (METOP/NOAA), VIIRS (NPP/NOAA-20) AMVs
279 ! that are included in prepbufr
282 read_loop_subset: do while (ireadsb(iunit)==0)
284 num_report_infile = num_report_infile + 1
286 call fill_datalink(rlink, missing_r, missing_i)
288 call ufbint(iunit,timedat,ntime,1,iret,timestr)
290 iyear = nint(timedat(1))
291 imonth = nint(timedat(2))
292 iday = nint(timedat(3))
293 ihour = nint(timedat(4))
294 imin = nint(timedat(5))
295 isec = min(59, nint(timedat(6))) ! raw BUFR data that has SECO = 60.0 SECOND
296 ! that was probably rounded from 59.x seconds
297 ! reset isec to 59 rather than advancing one minute
298 write(unit=rlink%date_char, fmt='(i4,a,i2.2,a,i2.2,a,i2.2,a,i2.2,a,i2.2)') &
299 iyear, '-', imonth, '-', iday, '_', ihour, ':', imin, ':', isec
300 call da_get_julian_time (iyear,imonth,iday,ihour,imin,obs_time)
301 if ( obs_time < time_slots(0) .or. &
302 obs_time >= time_slots(num_fgat_time) ) then
303 num_outside_time = num_outside_time + 1
304 cycle read_loop_subset
306 ! determine fgat index
307 do ifgat = 1, num_fgat_time
308 if ( obs_time >= time_slots(ifgat-1) .and. &
309 obs_time < time_slots(ifgat) ) then
314 if ( num_fgat_time > 1 ) then
315 rlink%tdiff = obs_time + float(isec)/60.0 - &
316 (time_slots(0) + (ifgat-1)*(time_slots(num_fgat_time)-time_slots(0))/float(num_fgat_time-1))
318 rlink%tdiff = obs_time + float(isec)/60.0 - analysis_time
320 rlink%tdiff = rlink%tdiff/60.0 ! minute to hour
322 if ( subset == 'NC005080' .or. &
323 subset == 'NC005090' ) then
324 call ufbint(iunit,lalodat,nlalo,1,iret,'CLAT CLON')
326 call ufbint(iunit,lalodat,nlalo,1,iret,lalostr) ! CLATH CLONH
331 if ( abs(xlat) > 90.0 .or. abs(xlon) > 360.0 ) cycle read_loop_subset
332 if ( xlon > 180.0 ) xlon = xlon - 360.0
335 xinfo%lat = max(xinfo%lat, -89.995)
336 xinfo%lat = min(xinfo%lat, 89.995)
337 call da_llxy(xinfo, xloc1, outside, outside_all)
338 if ( outside_all ) then
339 num_outside_domain = num_outside_domain + 1
340 cycle read_loop_subset
345 call ufbint(iunit,infodat,ninfo,1,iret,infostr) ! SAID LSQL SAZA OGCE SWCM
346 call ufbint(iunit,wdata,ndata,1,iret,datastr) ! PRLC WDIR WSPD
347 call ufbrep(iunit,qc1dat,nqc1,2,iret,qc1str) ! 2 replications TCOV CVWD
348 call ufbrep(iunit,qc2dat,nqc2,4,iret,qc2str) ! 4 replications GNAPS PCCF
350 if ( wdata(1) > r8bfms ) cycle read_loop_subset ! missing pressure
352 rlink % satid = nint(infodat(1)) ! SAID satellite identifier
353 ! construct rptype and stid from subset and satid
354 call set_rptype_satwnd(subset, rlink%satid, rlink%rptype, rlink%stid, rlink%name)
356 if ( wdata(1) < r8bfms ) rlink % prs = wdata(1) ! PRLC pressure in Pa
357 if ( wdata(2) < r8bfms ) rlink % wdir = wdata(2)
358 if ( wdata(3) < r8bfms ) rlink % wspd = wdata(3)
360 if ( infodat(4) < r8bfms ) rlink % landsea = infodat(4) ! LSQL land sea qualifier 0:land, 1:sea, 2:coast
361 if ( infodat(5) < r8bfms ) rlink % satzen = infodat(5) ! SAZA satellite zenith angle (degree)
363 if ( qc1dat(2,1) < r8bfms ) rlink % cvwd = qc1dat(2,1)
364 if ( qc2dat(2,2) < r8bfms ) rlink % pccf1 = qc2dat(2,2)
365 if ( qc2dat(2,4) < r8bfms ) rlink % pccf2 = qc2dat(2,4)
367 call filter_obs_satwnd(rlink%qm, rlink%rptype, rlink%prs, & ! set rlink%qm
368 rlink%satzen, rlink%landsea, rlink%pccf1, rlink%pccf2, rlink%cvwd, rlink%wspd)
370 if ( rlink%qm > qmarker_retain ) then
371 num_qc_fail = num_qc_fail + 1
372 cycle read_loop_subset
375 if ( thin_conv_opt(polaramv) > no_thin ) then
376 !crit = abs(tdiff(ii))
378 dlat_earth = rlink%lat
379 dlon_earth = rlink%lon
380 if ( dlon_earth < 0.0 ) dlon_earth = dlon_earth + 360.0
381 if ( dlon_earth >= 360.0 ) dlon_earth = dlon_earth - 360.0
382 dlat_earth = dlat_earth * deg2rad
383 dlon_earth = dlon_earth * deg2rad
384 if ( thin_conv_opt(polaramv) /= thin_superob_hv ) then
385 call map2grids_conv(polaramv,dlat_earth,dlon_earth,crit,iobs,itx,1,itt,iout,iuse)
387 zk = get_zk(nplev, plev, rlink%prs*0.01) ! 0.01 for Pa to hPa
388 call map2grids_conv(polaramv,dlat_earth,dlon_earth,crit,iobs,itx,1,itt,iout,iuse,zk=zk,thin_3d=.true.,nlev=nplev)
390 if ( thin_conv_opt(polaramv) /= thin_superob .and. &
391 thin_conv_opt(polaramv) /= thin_superob_hv ) then
392 if ( .not. iuse ) then
393 num_thinned = num_thinned + 1
394 if ( print_detail_obs ) then
395 write(unit=message(1),fmt='(a,2(1x,f8.3),1x,f8.3,a)') &
396 rlink%stid, rlink%lat, rlink%lon, rlink%prs*0.01, ' -> thinned'
398 cycle read_loop_subset
400 end if ! thin_conv_opt /= thin_superob, thin_superob_hv
402 end if ! thin_conv_opt(polaramv) > nothin
404 num_keep = num_keep + 1
406 if ( rlink%wdir >= 0.0 .and. rlink%wdir <= 360.0 .and. &
407 rlink%wspd < r8bfms ) then
408 angearth = rlink%wdir * pi / 180.0
409 rlink%uwind = -1.0 * rlink%wspd * sin(angearth)
410 rlink%vwind = -1.0 * rlink%wspd * cos(angearth)
413 if ( use_errtable ) then
415 pob = rlink % prs * 0.01 ! Pa to hPa
417 if ( pob >= oetab(kx,ilev+1,1) .and. pob <= oetab(kx,ilev,1) ) then
418 coef = (pob-oetab(kx,ilev,1))/(oetab(kx,ilev,1)-oetab(kx,ilev+1,1))
419 rlink % err = (1.0+coef)*oetab(kx,ilev,4)-coef*oetab(kx,ilev+1,4) !uv
423 ! in case errors are not set for some report types, use uv_error_val from namelist
424 if ( rlink % err > 100.0 ) rlink % err = uv_error_val(polaramv) ! m/s
426 rlink % err = uv_error_val(polaramv) ! m/s
429 allocate ( rlink%next )
431 nullify ( rlink%next )
433 end do read_loop_subset ! ireadsb
434 end do msg_loop ! ireadmg
436 if ( thin_conv_opt(polaramv) == thin_superob_hv ) then
442 call da_free_unit(iunit)
444 write(message(1),'(a,a,a,i10)') 'da_read_obs_bufr_satwnd: num_report_infile ', trim(filename), ' : ', num_report_infile
445 call da_message(message(1:1))
446 if ( thin_conv_opt(polaramv) == thin_superob .or. &
447 thin_conv_opt(polaramv) == thin_superob_hv ) then
448 write(unit=message(1),fmt='(a, 5i8)') &
449 'da_read_obs_bufr_satwnd: num_outside_domain, num_outside_time, num_qc_fail, num_superob = ', &
450 num_outside_domain, num_outside_time, num_qc_fail, iobs
451 call da_message(message(1:1))
453 write(unit=message(1),fmt='(a, 5i8)') &
454 'da_read_obs_bufr_satwnd: num_outside_domain, num_outside_time, num_qc_fail, num_thinned = ', &
455 num_outside_domain, num_outside_time, num_qc_fail, num_thinned
456 call da_message(message(1:1))
458 if ( thin_conv_opt(polaramv) == no_thin .or. &
459 thin_conv_opt(polaramv) == thin_multi ) then
468 call wrf_dm_bcast_integer(itmp, 1)
472 !print*, 'nobs = ', nobs
473 if ( nobs <= 0 ) then
474 write(unit=message(1),fmt='(a)') ' No valid obs found'
475 call da_warning(__FILE__,__LINE__,message(1:1))
479 ! superobbing is done on rootproc
482 allocate (sdata_val(nobs, nvars))
483 allocate (sdata_err(nobs, nvars))
484 allocate (smeta(nobs, nmeta))
485 allocate (iwindow(nobs))
486 allocate (date_char(nobs))
487 allocate (str_stid(nobs))
488 allocate (str_name(nobs))
490 if ( thin_conv_opt(polaramv) == no_thin .or. &
491 thin_conv_opt(polaramv) == thin_multi ) then
492 allocate (rptype(nobs))
495 do while ( associated(rlink) )
497 sdata_val(icnt,idx_u) = rlink%uwind
498 sdata_val(icnt,idx_v) = rlink%vwind
499 sdata_err(icnt,idx_u) = rlink%err
500 sdata_err(icnt,idx_v) = rlink%err
501 smeta(icnt,idx_p) = rlink%prs
502 smeta(icnt,idx_lat) = rlink%lat
503 smeta(icnt,idx_lon) = rlink%lon
504 iwindow(icnt) = rlink%ifgat
505 rptype(icnt) = rlink%rptype
506 date_char(icnt) = rlink%date_char
507 str_stid(icnt) = rlink%stid
508 str_name(icnt) = rlink%name
511 else if ( thin_conv_opt(polaramv) == thin_superob .or. &
512 thin_conv_opt(polaramv) == thin_superob_hv ) then
513 sdata_val = missing_r ! initialize
514 sdata_err = missing_r ! initialize
515 smeta = missing_r ! initialize
516 allocate (tdiff_avg(nobs))
519 iobs = 0 ! re-use this counter
520 allocate (num_val(nvars))
521 allocate (num_err(nvars))
522 allocate (num_meta(nmeta))
523 ! loop over thinning grids
524 itx_loop: do i = 1, thinning_grid_conv(polaramv)%itxmax
525 if ( thinning_grid_conv(polaramv)%icount(i) <= 0 ) cycle itx_loop
526 ! increment the counter for the thinning grid that has obs
528 ! reset counter for obs within each thinning grid
534 ! loop over nobs to process the obs within the thinning grid
536 nobs_loop_1: do while ( associated(rlink) )
537 if ( rlink%itg /= i ) then
542 if ( icnt == 1 ) then ! first ob in the thinning grid
544 str_stid(iobs) = rlink%stid
545 str_name(iobs) = rlink%name
547 ! only average obs in the same time window
548 if ( rlink%ifgat /= ifgat ) then
553 num_date = num_date + 1
556 tdiff_avg(iobs) = c2*tdiff_avg(iobs) + rlink%tdiff*c1
558 if ( trim(name_vars(ivar)) == 'eastward_wind' ) then
560 else if ( trim(name_vars(ivar)) == 'northward_wind' ) then
563 if ( abs(xval-missing_r) > 0.1 ) then
564 num_val(ivar) = num_val(ivar) + 1
565 c1 = 1.0/num_val(ivar)
566 c2 = (num_val(ivar)-1)*c1
567 sdata_val(iobs, ivar) = c2*sdata_val(iobs, ivar) + xval*c1
570 if ( abs(xval-missing_r) > 0.1 ) then
571 num_err(ivar) = num_err(ivar) + 1
572 c1 = 1.0/num_err(ivar)
573 c2 = (num_err(ivar)-1)*c1
574 sdata_err(iobs, ivar) = c2*sdata_err(iobs, ivar) + xval*c1
578 if ( trim(name_meta(ivar)) == 'air_pressure' ) then
580 else if ( trim(name_meta(ivar)) == 'latitude' ) then
582 else if ( trim(name_meta(ivar)) == 'longitude' ) then
585 if ( abs(xval-missing_r) > 0.1 ) then
586 num_meta(ivar) = num_meta(ivar) + 1
587 c1 = 1.0/num_meta(ivar)
588 c2 = (num_meta(ivar)-1)*c1
589 smeta(iobs, ivar) = c2*smeta(iobs, ivar) + xval*c1
592 if ( icnt == thinning_grid_conv(polaramv)%icount(i) ) then
598 iwindow(iobs) = ifgat
600 write(tdiff_char,'(i4,a1)') int(tdiff_avg(iobs)*60.0), 'm'
601 call da_advance_time(adate10, trim(adjustl(tdiff_char)), cdate14)
602 date_char(iobs) = cdate14(1:4)//'-'//cdate14(5:6)//'-'//cdate14(7:8)// &
603 '_'//cdate14(9:10)//':'//cdate14(11:12)//':'//cdate14(13:14)
605 deallocate (num_meta)
608 deallocate (tdiff_avg)
609 end if ! thin_conv_opt(polaramv)
612 ! release the linked list
614 do while ( associated(rlink) )
616 if ( associated (rlink) ) deallocate (rlink)
623 if ( .not. allocated(sdata_val) ) then
624 allocate (sdata_val(nobs, nvars))
627 call wrf_dm_bcast_real(sdata_val, isize)
628 if ( .not. allocated(sdata_err) ) then
629 allocate (sdata_err(nobs, nvars))
631 call wrf_dm_bcast_real(sdata_err, isize)
632 if ( .not. allocated(smeta) ) then
633 allocate (smeta(nobs, nmeta))
636 call wrf_dm_bcast_real(smeta, isize)
638 if ( .not. allocated(iwindow) ) then
639 allocate (iwindow(nobs))
641 call wrf_dm_bcast_integer(iwindow, isize)
642 if ( thin_conv_opt(polaramv) == no_thin .or. &
643 thin_conv_opt(polaramv) == thin_multi ) then
644 if ( .not. allocated(rptype) ) then
645 allocate (rptype(nobs))
647 call wrf_dm_bcast_integer(rptype, isize)
649 if ( .not. allocated(str_stid) ) then
650 allocate (str_stid(nobs))
652 if ( .not. allocated(str_name) ) then
653 allocate (str_name(nobs))
655 if ( .not. allocated(date_char) ) then
656 allocate (date_char(nobs))
659 call wrf_dm_bcast_string(str_stid(i), nstring)
660 call wrf_dm_bcast_string(str_name(i), nstring)
661 call wrf_dm_bcast_string(date_char(i), nstring)
664 allocate (xloc(nobs))
665 allocate (inside_domain(nobs))
666 allocate (inside_patch(nobs))
667 inside_domain(:) = .false.
668 inside_patch(:) = .false.
672 ntotal_ifgat(0:num_fgat_time) = 0
674 check_loop_2: do ii = 1, nobs
677 if ( abs(smeta(ii,idx_lat)) > 90.0 .or. abs(smeta(ii,idx_lon)) > 360.0 ) then
680 if ( smeta(ii,idx_lon) > 180.0 ) smeta(ii,idx_lon) = smeta(ii,idx_lon) - 360.0
681 xinfo%lat = smeta(ii,idx_lat)
682 xinfo%lon = smeta(ii,idx_lon)
683 xinfo%lat = max(xinfo%lat, -89.995)
684 xinfo%lat = min(xinfo%lat, 89.995)
685 call da_llxy(xinfo, xloc(ii), outside, outside_all)
686 if ( outside_all ) then
689 inside_domain(ii) = .true.
691 if ( ifgat < 0 ) cycle check_loop_2
693 ntotal_ifgat(ifgat) = ntotal_ifgat(ifgat) + 1
697 inside_patch(ii) = .true.
702 ! transfer data arrays to iv structures
704 iv%info(polaramv)%ntotal = ntotal
705 iv%info(polaramv)%nlocal = nlocal
707 iv%info(polaramv)%max_lev = max_lev
709 !allocate iv and iv%info
710 if ( nlocal > 0 ) then
711 allocate (iv%polaramv(1:nlocal))
712 allocate (iv%info(polaramv)%name(nlocal))
713 allocate (iv%info(polaramv)%platform(nlocal))
714 allocate (iv%info(polaramv)%id(nlocal))
715 allocate (iv%info(polaramv)%date_char(nlocal))
716 allocate (iv%info(polaramv)%levels(nlocal))
717 allocate (iv%info(polaramv)%lat(max_lev,nlocal))
718 allocate (iv%info(polaramv)%lon(max_lev,nlocal))
719 allocate (iv%info(polaramv)%elv(nlocal))
720 allocate (iv%info(polaramv)%pstar(nlocal))
721 allocate (iv%info(polaramv)%slp(nlocal))
722 allocate (iv%info(polaramv)%pw(nlocal))
723 allocate (iv%info(polaramv)%x (kms:kme,nlocal))
724 allocate (iv%info(polaramv)%y (kms:kme,nlocal))
725 allocate (iv%info(polaramv)%i (kms:kme,nlocal))
726 allocate (iv%info(polaramv)%j (kms:kme,nlocal))
727 allocate (iv%info(polaramv)%dx (kms:kme,nlocal))
728 allocate (iv%info(polaramv)%dxm(kms:kme,nlocal))
729 allocate (iv%info(polaramv)%dy (kms:kme,nlocal))
730 allocate (iv%info(polaramv)%dym(kms:kme,nlocal))
731 allocate (iv%info(polaramv)%k (max_lev,nlocal))
732 allocate (iv%info(polaramv)%dz (max_lev,nlocal))
733 allocate (iv%info(polaramv)%dzm(max_lev,nlocal))
734 allocate (iv%info(polaramv)%zk (max_lev,nlocal))
735 allocate (iv%info(polaramv)%proc_domain(max_lev,nlocal))
736 allocate (iv%info(polaramv)%thinned(max_lev,nlocal))
737 allocate (iv%info(polaramv)%obs_global_index(nlocal))
738 iv%info(polaramv)%elv(:) = missing_r
739 iv%info(polaramv)%proc_domain(:,:) = .false.
740 iv%info(polaramv)%thinned(:,:) = .false.
741 iv%info(polaramv)%zk(:,:) = missing_r
742 iv%info(polaramv)%slp(:) = field_type(missing_r, missing_data, xmiss, missing_r, missing_r)
743 iv%info(polaramv)%pw(:) = field_type(missing_r, missing_data, xmiss, missing_r, missing_r)
746 do ilocal = 1, nlocal
747 allocate (iv%polaramv(ilocal)%p(1:nlev))
748 allocate (iv%polaramv(ilocal)%u(1:nlev))
749 allocate (iv%polaramv(ilocal)%v(1:nlev))
750 iv%polaramv(ilocal)%p(:) = missing_r
751 iv%polaramv(ilocal)%u(:) = field_type(missing_r, missing_data, xmiss, missing_r, missing_r)
752 iv%polaramv(ilocal)%v(:) = field_type(missing_r, missing_data, xmiss, missing_r, missing_r)
759 do kk = 1, num_fgat_time
761 iv%info(polaramv)%ptotal(kk)=0
763 nobs_loop_2: do ii=1, nobs
765 if ( .not. inside_domain(ii) ) cycle nobs_loop_2
768 if ( .not. inside_patch(ii) ) cycle nobs_loop_2
770 if ( iwindow(ii) /= kk ) then
774 iv%info(polaramv)%platform(ilocal) = 'FM-88 SATWND'
775 if ( thin_conv_opt(polaramv) == thin_superob .or. &
776 thin_conv_opt(polaramv) == thin_superob_hv ) then
777 iv%info(polaramv)%name(ilocal) = 'satwnd'
778 iv%info(polaramv)%id(ilocal) = 'SUPEROB'
780 write(iv%info(polaramv)%name(ilocal), '(a,a,i3)') &
781 trim(str_name(ii)),' ',rptype(ii)
782 iv%info(polaramv)%id(ilocal) = str_stid(ii)
784 iv%info(polaramv)%date_char(ilocal) = date_char(ii)
785 iv%info(polaramv)%levels(ilocal) = nlev ! = 1
786 iv%info(polaramv)%lat(:,ilocal) = smeta(ii,idx_lat)
787 iv%info(polaramv)%lon(:,ilocal) = smeta(ii,idx_lon)
789 iv%info(polaramv)%x(:,ilocal) = xloc(ii)%x
790 iv%info(polaramv)%y(:,ilocal) = xloc(ii)%y
791 iv%info(polaramv)%i(:,ilocal) = xloc(ii)%i
792 iv%info(polaramv)%j(:,ilocal) = xloc(ii)%j
793 iv%info(polaramv)%dx(:,ilocal) = xloc(ii)%dx
794 iv%info(polaramv)%dxm(:,ilocal) = xloc(ii)%dxm
795 iv%info(polaramv)%dy(:,ilocal) = xloc(ii)%dy
796 iv%info(polaramv)%dym(:,ilocal) = xloc(ii)%dym
798 iv%info(polaramv)%obs_global_index(ilocal) = itotal
800 iv%polaramv(ilocal)%p(1) = smeta(ii,idx_p)
802 uob = sdata_val(ii,idx_u)
803 if ( abs(uob - missing_r) > 1.0 ) then
804 iv%polaramv(ilocal)%u(1)%inv = uob
805 iv%polaramv(ilocal)%u(1)%qc = 0
806 err_val = sdata_err(ii,idx_u)
807 if ( err_val > 0.0 ) then
808 iv%polaramv(ilocal)%u(1)%error = err_val
811 vob = sdata_val(ii,idx_v)
812 if ( abs(vob - missing_r) > 1.0 ) then
813 iv%polaramv(ilocal)%v(1)%inv = vob
814 iv%polaramv(ilocal)%v(1)%qc = 0
815 err_val = sdata_err(ii,idx_v)
816 if ( err_val > 0.0 ) then
817 iv%polaramv(ilocal)%v(1)%error = err_val
821 if ( uv_error_opt(polaramv) == error_opt_nml ) then
822 iv%polaramv(ilocal)%u(1)%error = uv_error_val(polaramv)
823 iv%polaramv(ilocal)%v(1)%error = uv_error_val(polaramv)
826 ! u/v-earth to u/v-grid
827 if ( abs(uob - missing_r) > 1.0 .and. &
828 abs(vob - missing_r) > 1.0 ) then
829 call da_earth_2_model_wind ( uob, vob, u_grid, v_grid, &
830 iv%info(polaramv)%lon(1,ilocal) )
831 iv%polaramv(ilocal)%u(1)%inv = u_grid
832 iv%polaramv(ilocal)%v(1)%inv = v_grid
835 end if ! inside time window
838 ntotal_ifgat(kk) = ntotal_ifgat(kk) + ntotal_ifgat(kk-1)
839 iv%info(polaramv)%ptotal(kk) = ntotal_ifgat(kk)
840 iv%info(polaramv)%plocal(kk) = ilocal
841 end do ! num_fgat_time
843 deallocate (inside_patch)
844 deallocate (inside_domain)
846 if ( thin_conv_opt(polaramv) == no_thin .or. &
847 thin_conv_opt(polaramv) == thin_multi ) then
852 deallocate (sdata_err)
853 deallocate (sdata_val)
854 deallocate (str_stid)
855 deallocate (str_name)
857 ! transfer iv to a smaller ob structure
859 ob % nlocal(polaramv) = iv%info(polaramv)%nlocal
860 ob % ntotal(polaramv) = iv%info(polaramv)%ntotal
861 if ( nlocal > 0) then
862 allocate (ob % polaramv(1:nlocal))
864 nlevel = iv%info(polaramv)%levels(n)
865 allocate (ob % polaramv(n)%u(1:nlevel))
866 allocate (ob % polaramv(n)%v(1:nlevel))
868 ob % polaramv(n) % u(k) = iv % polaramv(n) % u(k) % inv
869 ob % polaramv(n) % v(k) = iv % polaramv(n) % v(k) % inv
876 !--------------------------------------------------------------
878 subroutine filter_obs_satwnd(qm, rptype, prs, satzen, landsea, pccf1, pccf2, cvwd, wspd)
880 ! refer to GSI/read_satwnd.f90
884 integer(i_kind), intent(out) :: qm
885 integer(i_kind), intent(in) :: rptype
886 real(r_kind), intent(in) :: prs
887 real(r_kind), intent(in) :: satzen
888 real(r_kind), intent(in) :: landsea
889 real(r_kind), intent(in) :: pccf1
890 real(r_kind), intent(in) :: pccf2
891 real(r_kind), intent(in) :: cvwd
892 real(r_kind), intent(in) :: wspd
894 real(r_kind) :: experr_norm
895 logical :: EC_AMV_QC = .true.
896 integer(i_kind) :: iland = 0
898 qm = 2 ! neutral or not checked
900 if ( satzen > 68.0_r_kind ) qm = 15
902 if ( rptype == 260 ) then
903 if ( pccf1 < 85.0_r_kind ) qm = 15
906 if ( rptype == 240 .or. &
912 if ( pccf1 < 80.0_r_kind .or. pccf1 > 100.0_r_kind ) qm = 15 ! reject data with low QI
914 if ( prs < 12500.0_r_kind ) qm = 15 ! reject data above 125hPa
916 experr_norm = 10.0_r_kind - 0.1_r_kind * pccf2
917 if ( wspd > 0.1_r_kind ) then
918 experr_norm = experr_norm / wspd
920 experr_norm = 100.0_r_kind
922 if ( experr_norm > 0.9_r_kind ) qm = 15 ! reject data with estimated error/spd>0.9
924 if ( rptype == 240 .or. &
928 if ( cvwd < 0.04_r_kind ) qm = 15
929 if ( cvwd > 0.50_r_kind ) qm = 15
932 if ( EC_AMV_QC ) then
933 if ( pccf1 < 90_r_kind .or. pccf1 > 100.0_r_kind ) qm = 15 ! stricter QI
934 if ( prs < 15000.0_r_kind) qm = 15 ! all high level
935 if ( rptype == 251 .and. prs < 70000.0_r_kind ) qm = 15 ! VIS
936 if ( rptype == 246 .and. prs > 30000.0_r_kind ) qm = 15 ! WVCA
937 if ( nint(landsea) == iland .and. prs > 85000.0_r_kind) qm = 15 ! low over land
939 end if ! rptype 240, 245, 246, 247, 251
941 end subroutine filter_obs_satwnd
943 !--------------------------------------------------------------
945 subroutine fill_datalink (datalink, rfill, ifill)
949 type (datalink_satwnd), intent(inout) :: datalink
950 real(r_kind), intent(in) :: rfill ! fill value in real
951 integer(i_kind), intent(in) :: ifill ! fill value in integer
955 datalink % lat = rfill
956 datalink % lon = rfill
957 datalink % satid = ifill
958 datalink % itg = ifill
959 datalink % ifgat = ifill
960 datalink % landsea = rfill
961 datalink % satzen = rfill
962 datalink % prs = rfill
963 datalink % wdir = rfill
964 datalink % wspd = rfill
965 datalink % cvwd = rfill
966 datalink % uwind = rfill
967 datalink % vwind = rfill
968 datalink % pccf1 = rfill
969 datalink % pccf2 = rfill
970 datalink % err = rfill
971 datalink % qm = ifill
973 end subroutine fill_datalink
975 !--------------------------------------------------------------
977 subroutine set_rptype_satwnd(subset, satid, rptype, stid, name)
980 character(len=*), intent(in) :: subset ! bufr message subset
981 integer(i_kind), intent(in) :: satid ! satellite id
982 integer(i_kind), intent(out) :: rptype ! report type
983 character(len=nstring), intent(out) :: stid ! station id
984 character(len=nstring), intent(out) :: name ! instrument name
986 character(len=3) :: csatid
990 write(csatid, '(i3.3)') satid
992 select case ( trim(subset) )
993 case ( 'NC005030' ) ! GOES IR LW
997 case ( 'NC005039' ) ! GOES IR SW
1001 case ( 'NC005032' ) ! GOES VIS
1005 case ( 'NC005034' ) ! GOES WV cloud top
1008 name = 'GOES WV cloud top'
1009 case ( 'NC005031' ) ! GOES WV clear sky/deep layer
1012 name = 'GOES WV clear sky/depp layer'
1013 case ( 'NC005080', 'NC005081' ) ! AVHRR (METOP-a/b/c, NOAA-15/18/19)
1017 case ( 'NC005090', 'NC005091' ) ! VIIRS (NPP, NOAA-20)
1021 case ( 'NC005072' ) ! LEOGEO (non-specific mixture of geostationary and low earth orbiting satellites)
1023 stid = 'IR'//csatid ! satid=854
1027 end subroutine set_rptype_satwnd
1029 !--------------------------------------------------------------
1031 integer function ufo_vars_getindex(vars, varname)
1033 character(len=*), intent(in) :: vars(:)
1034 character(len=*), intent(in) :: varname
1038 ufo_vars_getindex = -1
1040 do ivar = 1, size(vars)
1041 if (trim(vars(ivar)) == trim(varname)) then
1042 ufo_vars_getindex = ivar
1047 end function ufo_vars_getindex
1049 !--------------------------------------------------------------
1051 real function get_zk (nlev, levels, val)
1054 integer, intent(in) :: nlev
1055 real, intent(in) :: levels(nlev)
1056 real, intent(in) :: val
1058 integer :: level_index
1059 logical :: decreasing
1061 if ( levels(nlev) < levels(1) ) then
1064 decreasing = .false.
1067 level_index = 0 ! initialize
1069 if ( decreasing ) then
1070 if ( val >= levels(1) ) then
1072 else if ( val < levels(nlev-1) .and. val >= levels(nlev) ) then
1076 if ( val >= levels(k) ) then
1083 if ( val <= levels(1) ) then
1085 else if ( val > levels(nlev-1) .and. val <= levels(nlev) ) then
1089 if ( val <= levels(k) ) then
1095 end if ! decreasing or not
1097 get_zk = real(level_index) + &
1098 (val-levels(level_index))/(levels(level_index+1)-levels(level_index))
1102 end subroutine da_read_obs_bufr_satwnd