IODA Bundle
prepbufr_mod.f90
Go to the documentation of this file.
2 
3 ! adapated from WRFDA/var/da/da_obs_io/da_read_obs_bufr.inc
4 
5 use kinds, only: r_kind, i_kind, r_double
10 use utils_mod, only: da_advance_time
11 use netcdf, only: nf90_int, nf90_float, nf90_char
12 
13 implicit none
14 private
15 public :: read_prepbufr
16 public :: sort_obs_conv
17 public :: filter_obs_conv
18 
19 ! variables for storing data
21  real(r_kind) :: val ! observation value
22  integer(i_kind) :: qm ! observation quality marker
23  real(r_kind) :: err ! observational error
24  contains
25  procedure :: init => init_field
26 end type field_type
27 
29  type (field_type) :: h ! height in m
30  type (field_type) :: u ! Wind x-component in m/s
31  type (field_type) :: v ! Wind y-component in m/s
32  type (field_type) :: p ! Pressure in Pa
33  type (field_type) :: t ! Temperature in K
34  type (field_type) :: tv ! virtual temperature in K
35  type (field_type) :: q ! (kg/kg)
36  real(r_kind) :: lat ! Latitude in degree
37  real(r_kind) :: lon ! Longitude in degree
38  real(r_kind) :: dhr ! obs time minus analysis time in hour
39  real(r_kind) :: pccf ! percent confidence
40  character(len=ndatetime) :: datetime ! ccyy-mm-ddThh:mm:ssZ
41  type (each_level_type), pointer :: next => null()
42  contains
43  procedure :: init => init_each_level
44 end type each_level_type
45 
47  ! data from BUFR file
48  integer(i_kind) :: t29 ! data dump report type
49  integer(i_kind) :: rptype ! prepbufr report type
50  integer(i_kind) :: satid ! satellite id
51  character(len=nstring) :: msg_type ! BUFR message type name
52  character(len=nstring) :: stid ! station identifier
53  character(len=ndatetime) :: datetime ! ccyy-mm-ddThh:mm:ssZ
54  integer(i_kind) :: nlevels ! number of levels
55  real(r_kind) :: lat ! latitude in degree
56  real(r_kind) :: lon ! longitude in degree
57  real(r_kind) :: elv ! elevation in m
58  real(r_kind) :: dhr ! obs time minus analysis time in hour
59  type (field_type) :: ps ! surface pressure
60  type (field_type) :: slp ! sea level pressure
61  type (field_type) :: pw ! precipitable water
62  type (each_level_type), pointer :: each => null()
63  ! derived info
64  character(len=nstring) :: obtype ! ob type, eg sonde, satwnd
65  integer(i_kind) :: obtype_idx ! index of obtype in obtype_list
66  type(each_level_type), pointer :: first => null()
67  type(report_conv), pointer :: next => null()
68  contains
69  procedure :: init => init_report
70 end type report_conv
71 
72 type(report_conv), pointer :: phead=>null(), plink=>null()
73 
74 integer(i_kind), parameter :: lim_qm = 4
75 
76 contains
77 
78 !--------------------------------------------------------------
79 
80 subroutine read_prepbufr(filename, filedate)
81 
82  implicit none
83 
84  character (len=*), intent(in) :: filename
85  character (len=10), intent(out) :: filedate ! ccyymmddhh
86 
87  real(r_kind), parameter :: r8bfms = 9.0e08 ! threshold to check for BUFR missing value
88 
89  logical :: match, end_of_file, drift
90  character(len=8) :: subset, subst2, csid, csid2
91  character(len=40) :: obstr,hdstr,qmstr,oestr, pcstr, drstr
92  real(r_double) :: r8sid, r8sid2
93  real(r_double) :: hdr(7), hdr2(7), hdr_save(7)
94  real(r_double) :: obs(8,255),qms(8,255),oes(8,255),pco(8,255)
95  real(r_double) :: obs2(8,255),qms2(8,255),oes2(8,255),pco2(8,255)
96  real(r_double) :: pmo(2,1), pmo2(2,1), pmo_save(2,1)
97  real(r_double) :: temp(8,255)
98  real(r_double) :: obs_save(8,255)
99  real(r_double) :: pob, pob1, pob2
100  real(r_double) :: drf(8,255), drf2(8,255) ! for balloon drift
101  real(r_double) :: satqc(1), satid(1)
102  equivalence(r8sid, csid), (r8sid2, csid2)
103 
104  character(len=14) :: cdate, dsec, obs_date
105  integer(i_kind) :: idate, idate2
106  integer(i_kind) :: nlevels, nlevels2, lv1, lv2
107  integer(i_kind) :: iyear, imonth, iday, ihour, imin, isec
108  integer(i_kind) :: num_report_infile
109  integer(i_kind) :: iret, iret2, iost, n, i, j, k, i1, i2
110  integer(i_kind) :: kx, t29
111  integer(i_kind) :: tpc
112  integer(i_kind) :: iunit, junit, itype, ivar
113  logical :: use_errtable, combine_mass_wind, do_tv_to_ts
114  real(r_kind) :: oetab(300,33,6) ! 300 ob types, 33 levels (rows), 6 variables (columns)
115  real(r_kind) :: coef
116  real(r_kind) :: qs, tval
117 
118  write(*,*) '--- reading '//trim(filename)//' ---'
119  hdstr='SID XOB YOB DHR TYP ELV T29'
120  obstr='POB QOB TOB ZOB UOB VOB PWO CAT' ! observation
121  qmstr='PQM QQM TQM ZQM WQM NUL PWQ NUL' ! quality marker
122  oestr='POE QOE TOE NUL WOE NUL PWE NUL' ! observation error
123  pcstr='PPC QPC TPC ZPC WPC NUL PWP NUL' ! program code
124  drstr='XDR YDR HRDR ' ! balloon drift code
125 
126  ! initialize variables
127 
128  if ( .not. associated(phead) ) then
129  nullify ( phead )
130  allocate ( phead )
131  nullify ( phead%next )
132  end if
133 
134  use_errtable = .false.
135  combine_mass_wind = .false.
136  do_tv_to_ts = .false.
137 
138  num_report_infile = 0
139 
140  iunit = 96
141  junit = 97
142 
143  ! open bufr file
144  open (unit=iunit, file=trim(filename), &
145  iostat=iost, form='unformatted', status='old')
146  if (iost /= 0) then
147  write(unit=*,fmt='(a,i5,a)') &
148  "Error",iost," opening PREPBUFR obs file "//trim(filename)
149  return
150  end if
151  ! open observation error table if provided.
152  open (unit=junit, file='obs_errtable', form='formatted', &
153  status='old', iostat=iost)
154  if ( iost /= 0 ) then
155  use_errtable = .false.
156  else
157  use_errtable = .true.
158  write(unit=*,fmt='(A)') &
159  "obs_errtable file is found. Will use user-provided obs errors."
160  end if
161  if ( use_errtable ) then
162  read_loop: do
163  read (junit,'(1x,i3)',iostat=iost) itype
164  if ( iost /=0 ) exit read_loop
165  do k = 1, 33
166  read (junit,'(1x,6e12.5)',iostat=iost) (oetab(itype,k,ivar),ivar=1,6)
167  if ( iost /=0 ) exit read_loop
168  end do
169  end do read_loop
170  end if
171 
172  call openbf(iunit,'IN',iunit)
173  call datelen(10)
174 
175  call readns(iunit,subset,idate,iret) ! read in the next subset
176  if ( iret /= 0 ) then
177  write(unit=*,fmt='(A,I5,A)') &
178  "Error",iret," reading PREPBUFR obs file "//trim(filename)
179  call closbf(iunit)
180  return
181  end if
182  rewind(iunit)
183 
184  write(unit=*,fmt='(1x,a,a,i10)') trim(filename), ' file date is: ', idate
185 
186  write(unit=filedate,fmt='(i10)') idate
187 
188  ! read data
189 
190  match = .false.
191  end_of_file = .false.
192  reports: do while ( .not. end_of_file )
193 
194  if ( match ) then
195  call readns(iunit,subset,idate,iret) ! read in the next subset
196  if ( iret /= 0 ) then
197  write(unit=*,fmt='(A,I3,A,I3)') &
198  "return code from readns",iret, &
199  "reach the end of PREPBUFR obs unit",iunit
200  exit reports
201  end if
202  end if
203 
204  num_report_infile = num_report_infile + 1
205 
206  call ufbint(iunit,satqc,1,1,iret,'QIFN')
207  call ufbint(iunit,satid,1,1,iret,'SAID')
208  call ufbint(iunit,hdr,7,1,iret,hdstr)
209  call ufbint(iunit,pmo,2,1,iret,'PMO PMQ')
210  call ufbint(iunit,qms,8,255,nlevels,qmstr)
211  call ufbint(iunit,oes,8,255,nlevels,oestr)
212  call ufbint(iunit,pco,8,255,nlevels,pcstr)
213  call ufbint(iunit,obs,8,255,nlevels,obstr)
214 
215  r8sid = hdr(1)
216  t29 = nint(hdr(7))
217  kx = nint(hdr(5))
218 
219  if ( use_errtable ) then
220  do k = 1, nlevels
221  pob = obs(1,k)
222  do lv1 = 1, 32
223  if ( pob >= oetab(kx,lv1+1,1) .and. pob <= oetab(kx,lv1,1) ) then
224  coef = (pob-oetab(kx,lv1,1))/(oetab(kx,lv1,1)-oetab(kx,lv1+1,1))
225  oes(1,k) = (1.0+coef)*oetab(kx,lv1,5)-coef*oetab(kx,lv1+1,5) !p
226  oes(2,k) = (1.0+coef)*oetab(kx,lv1,3)-coef*oetab(kx,lv1+1,3) !q
227  oes(3,k) = (1.0+coef)*oetab(kx,lv1,2)-coef*oetab(kx,lv1+1,2) !t
228  oes(5,k) = (1.0+coef)*oetab(kx,lv1,4)-coef*oetab(kx,lv1+1,4) !uv
229  oes(7,k) = (1.0+coef)*oetab(kx,lv1,6)-coef*oetab(kx,lv1+1,6) !pw
230  exit
231  end if
232  end do
233  end do
234  end if
235 
236  drift = kx==120.or.kx==220.or.kx==221
237  if ( drift ) call ufbint(iunit,drf,8,255,iret,drstr)
238 
239  call readns(iunit,subst2,idate2,iret)
240 
241  if ( iret /= 0 ) then
242  end_of_file = .true.
243  else
244  if ( combine_mass_wind ) then
245  match_check: do
246  call ufbint(iunit,hdr2,7,1,iret2,hdstr)
247  ! check if this subset and the previous one are matching mass and wind
248  match = .true.
249  if ( subset /= subst2 ) then
250  match = .false.
251  exit match_check
252  end if
253  r8sid2 = hdr2(1)
254  if ( csid /= csid2 ) then ! check SID
255  match = .false.
256  exit match_check
257  end if
258  do i = 2, 4 ! check XOB, YOB, DHR
259  if ( hdr(i) /= hdr2(i) ) then
260  match = .false.
261  exit match_check
262  end if
263  end do
264  if ( hdr(6) /= hdr2(6) ) then ! check ELV
265  match = .false.
266  exit match_check
267  end if
268  !The two headers match, now read data from the second subset
269  call ufbint(iunit,pmo2,2,1,nlevels2,'PMO PMQ')
270  call ufbint(iunit,qms2,8,255,nlevels2,qmstr)
271  call ufbint(iunit,oes2,8,255,nlevels2,oestr)
272  call ufbint(iunit,pco2,8,255,nlevels2,pcstr)
273  call ufbint(iunit,obs2,8,255,nlevels2,obstr)
274  if ( drift ) call ufbint(iunit,drf2,8,255,iret,drstr)
275 
276  if ( use_errtable ) then
277  kx = nint(hdr2(5))
278  do k = 1, nlevels2
279  pob = obs2(1,k)
280  do lv1 = 1, 32
281  if ( pob >= oetab(kx,lv1+1,1) .and. pob <= oetab(kx,lv1,1) ) then
282  coef = (pob-oetab(kx,lv1,1))/(oetab(kx,lv1,1)-oetab(kx,lv1+1,1))
283  oes2(1,k) = (1.0+coef)*oetab(kx,lv1,5)-coef*oetab(kx,lv1+1,5) !p
284  oes2(2,k) = (1.0+coef)*oetab(kx,lv1,3)-coef*oetab(kx,lv1+1,3) !q
285  oes2(3,k) = (1.0+coef)*oetab(kx,lv1,2)-coef*oetab(kx,lv1+1,2) !t
286  oes2(5,k) = (1.0+coef)*oetab(kx,lv1,4)-coef*oetab(kx,lv1+1,4) !uv
287  oes2(7,k) = (1.0+coef)*oetab(kx,lv1,6)-coef*oetab(kx,lv1+1,6) !pw
288  exit
289  end if
290  end do
291  end do
292  end if
293 
294  ! If this is a surface report, the wind subset precedes the
295  ! mass subset - switch the subsets around in order to combine
296  ! the surface pressure properly
297  kx = nint(hdr(5))
298  if ( kx == 280 .or. kx == 281 .or. kx == 284 .or. &
299  kx == 287 .or. kx == 288 ) then
300  pmo_save = pmo2
301  pmo2 = pmo
302  pmo = pmo_save
303  temp = obs2
304  obs2 = obs
305  obs = temp
306  hdr_save = hdr2
307  hdr2 = hdr
308  hdr = hdr_save
309  temp = qms2
310  qms2 = qms
311  qms = temp
312  temp = oes2
313  oes2 = oes
314  oes = temp
315  temp = pco2
316  pco2 = pco
317  pco = temp
318  end if
319 
320  ! combine the two matching subsets
321  do i = 1, 2
322  if ( pmo(i,1) > r8bfms ) then
323  pmo(i,1) = pmo2(i,1)
324  end if
325  end do
326  lev_loop: do lv2 = 1, nlevels2
327  do lv1 = 1, nlevels
328  pob1 = obs(1,lv1)
329  pob2 = obs2(1,lv2)
330  if ( pob1 == pob2 ) then
331  do i = 1, 7 ! skip the CAT
332  if ( obs(i,lv1) > r8bfms ) then
333  obs(i,lv1) = obs2(i,lv2)
334  if ( obs2(i,lv2) <= r8bfms ) then
335  obs(8,lv1) = obs2(8,lv2) ! rewrite CAT
336  end if
337  end if
338  if ( oes(i,lv1) > r8bfms ) then
339  oes(i,lv1) = oes2(i,lv2)
340  end if
341  if ( pco(i,lv1) > r8bfms ) then
342  pco(i,lv1) = pco2(i,lv2)
343  end if
344  end do
345  do i = 1, 8
346  if ( qms(i,lv1) > r8bfms ) then
347  qms(i,lv1) = qms2(i,lv2)
348  end if
349  end do
350  if ( drift) then
351  do i = 1, 3
352  if ( drf(i,lv1) > r8bfms ) then
353  drf(i,lv1) = drf2(i,lv2)
354  end if
355  end do
356  end if
357  cycle lev_loop
358  else if ( (pob2 > pob1) .or. (lv1 .eq. nlevels) ) then
359  nlevels = nlevels + 1
360  obs(:,nlevels) = obs2(:,lv2)
361  qms(:,nlevels) = qms2(:,lv2)
362  oes(:,nlevels) = oes2(:,lv2)
363  pco(:,nlevels) = pco2(:,lv2)
364  if ( drift) then
365  drf(:,nlevels) = drf2(:,lv2)
366  end if
367  cycle lev_loop
368  end if
369  end do
370  end do lev_loop
371  ! sort combined report in descending pressure order
372  do i1 = 1, nlevels-1
373  do i2 = i1+1, nlevels
374  if ( obs(1,i2) .gt. obs(1,i1) ) then
375  temp(:,1) = obs(:,i1)
376  obs(:,i1) = obs(:,i2)
377  obs(:,i2) = temp(:,1)
378  temp(:,1) = qms(:,i1)
379  qms(:,i1) = qms(:,i2)
380  qms(:,i2) = temp(:,1)
381  temp(:,1) = oes(:,i1)
382  oes(:,i1) = oes(:,i2)
383  oes(:,i2) = temp(:,1)
384  temp(:,1) = pco(:,i1)
385  pco(:,i1) = pco(:,i2)
386  pco(:,i2) = temp(:,1)
387  if ( drift ) then
388  temp(:,1) = drf(:,i1)
389  drf(:,i1) = drf(:,i2)
390  drf(:,i2) = temp(:,1)
391  end if
392  end if
393  end do
394  end do
395  exit match_check
396  end do match_check
397  end if ! combine_mass_wind
398 
399  if ( .not. match ) then
400  subset = subst2
401  idate = idate2
402  end if
403 
404  end if ! readns iret=0
405 
406  ! skip some types
407  ! 61: Satellite soundings/retrievals/radiances
408  ! 66: SSM/I rain rate product
409  ! 72: NEXTRAD VAD winds
410  if ( t29 == 61 .or. t29 == 66 .or. t29 == 72 ) cycle reports
411 
412  ! OSLK (elv=48) reported Ps=341hPa
413  !if ( csid(1:4) == 'OSLK' ) cycle reports
414 
415  ! station 78383 (kx=184/t29=511) has station elevation=9999.0 and valid height quality markers
416  ! a few other stations have station elevation=9999.0 and height quality markers = 15
417  ! to do: this check could be done in filter_obs_conv by implementing blacklist
418  if ( abs(hdr(6) - 9999.0) < 0.01 .and. t29 /= 41 ) cycle reports ! aircraft could have elv=9999.0
419 
420  ! the following (as in GSI read_prepbufr.f90) could reject reports at the poles
421  if ( abs(hdr(2)) > 360.0 .or. abs(hdr(3)) > 90.0 ) cycle reports
422  ! the following allows reports at the poles
423  !if ( abs(hdr(2)-360.0) < 0.01 .or. abs(hdr(3)-90.0) < 0.01 ) cycle reports
424 
425  write(dsec,'(i6,a1)') int(hdr(4)*60.0*60.0), 's' ! seconds
426  write(cdate,'(i10)') idate
427  call da_advance_time (cdate(1:10), trim(dsec), obs_date)
428  read (obs_date(1:14),'(i4,5i2)') iyear, imonth, iday, ihour, imin, isec
429  if ( iyear < 1900 .or. iyear > 3000 .or. &
430  imonth < 1 .or. imonth > 12 .or. &
431  iday < 1 .or. iday > 31 .or. &
432  ihour < 0 .or. ihour >= 24 .or. &
433  imin < 0 .or. imin >= 60 .or. &
434  isec < 0 .or. isec >= 60 ) then
435  cycle reports
436  end if
437 
438  if (.not. associated(plink)) then
439  plink => phead
440  else
441  allocate ( plink%next )
442  plink => plink%next
443  nullify ( plink%next )
444  end if
445 
446  ! initialize plink with missing values
447  call plink % init()
448 
449  plink % msg_type(1:8) = subset
450  plink % stid(1:5) = csid(1:5)
451  plink % rptype = kx
452  plink % t29 = t29
453  plink % lon = hdr(2)
454  plink % lat = hdr(3)
455  plink % dhr = hdr(4) ! difference in hour
456  plink % elv = hdr(6)
457 
458  write(unit=plink%datetime, fmt='(i4,a,i2.2,a,i2.2,a,i2.2,a,i2.2,a,i2.2,a)') &
459  iyear, '-', imonth, '-', iday, 'T', ihour, ':', imin, ':', isec, 'Z'
460 
461  if ( satid(1) < r8bfms ) then
462  plink % satid = nint(satid(1))
463  end if
464 
465  if ( pmo(1,1) < r8bfms ) then
466  plink % slp % val = pmo(1,1)*100.0
467  plink % slp % qm = nint(pmo(2,1))
468  end if
469  if ( obs(7,1) < r8bfms ) then
470  plink % pw % val = obs(7,1) * 0.1 ! convert to cm
471  if ( qms(7,1) < r8bfms ) then
472  plink % pw % qm = nint(qms(7,1))
473  end if
474  if ( oes(7,1) < r8bfms ) then
475  plink % pw % err = oes(7,1)
476  end if
477  end if
478 
479  plink % nlevels = 0 ! initialize
480 
481  loop_nlevels: do k = 1, nlevels
482 
483  ! pressure and height quality markers do not carry over to ioda
484  ! qm=8: Observed surface pressure is > 1100 mb or < 450 mb,
485  ! or is more than 100 mb above or below model (guess) surface pressure,
486  ! or an observed pressure on any level is <= 0 mb or more than 100 mb
487  ! above or below model (guess) pressure at same level,
488  ! or a non-pressure observation failed a limit check
489  ! qm=15: Observation is flagged for non-use by analysis
490  if ( qms(1,k) < r8bfms ) then ! pressure
491  if ( nint(qms(1,k)) == 8 .or. nint(qms(1,k)) == 15 ) cycle loop_nlevels
492  end if
493  if ( qms(4,k) < r8bfms ) then ! height
494  if ( nint(qms(4,k)) == 8 .or. nint(qms(4,k)) == 15 ) cycle loop_nlevels
495  end if
496 
497  plink % nlevels = plink % nlevels + 1
498 
499  if ( .not. associated(plink % each) ) then
500  allocate ( plink % each )
501  plink % first => plink % each
502  else
503  allocate ( plink % each % next)
504  plink % each => plink % each % next
505  nullify ( plink % each % next )
506  end if
507 
508  call plink % each % init()
509 
510  if ( satqc(1) < r8bfms ) then
511  plink % each % pccf = satqc(1)
512  end if
513 
514  if ( drift ) then
515  if ( drf(1,k) < r8bfms ) plink % each % lon = drf(1,k)
516  if ( drf(2,k) < r8bfms ) plink % each % lat = drf(2,k)
517  if ( drf(3,k) < r8bfms ) then
518  plink % each % dhr = drf(3,k)
519  write(dsec,'(i6,a1)') int(drf(3,k)*60.0*60.0), 's' ! seconds
520  call da_advance_time (cdate(1:10), trim(dsec), obs_date)
521  read (obs_date(1:14),'(i4,5i2)') iyear, imonth, iday, ihour, imin, isec
522  write(unit=plink%each%datetime, fmt='(i4,a,i2.2,a,i2.2,a,i2.2,a,i2.2,a,i2.2,a)') &
523  iyear, '-', imonth, '-', iday, 'T', ihour, ':', imin, ':', isec, 'Z'
524  end if
525  end if
526 
527  if ( obs(1,k) > 0.0 .and. obs(1,k) < r8bfms ) then
528  plink % each % p % val = obs(1,k)*100.0 ! convert to Pa
529  if ( qms(1,k) < r8bfms ) then
530  plink % each % p % qm = nint(qms(1,k))
531  end if
532  if ( oes(1,k) < r8bfms ) then
533  plink % each % p % err = oes(1,k)*100.0 ! convert to Pa
534  end if
535  ! obs(8,k) == CAT (Data Level Category)
536  ! CAT=0: Surface level (mass reports only)
537  if ( nint(obs(8,k)) == 0 ) then
538  plink % ps % val = plink % each % p % val
539  plink % ps % qm = plink % each % p % qm
540  plink % ps % err = plink % each % p % err
541  end if
542  end if
543 
544  if ( obs(4,k) < r8bfms ) then
545  plink % each % h % val = obs(4,k)
546  if ( qms(4,k) < r8bfms ) then
547  plink % each % h % qm = nint(qms(4,k))
548  end if
549  end if
550 
551  tpc = missing_i
552  if ( obs(3,k) < r8bfms ) then
553  obs(3,k) = obs(3,k) + t_kelvin
554  if ( pco(3,k) < r8bfms ) tpc = nint(pco(3,k))
555  end if
556 
557  ! scale q and compute t from tv, if they aren't missing
558  if (obs(2,k) > 0.0 .and. obs(2,k) < r8bfms) then
559  obs(2,k) = obs(2,k)*1e-6 ! mg/kg to kg/kg
560  if (obs(3,k) > -200.0 .and. obs(3,k) < 350.0) then
561  if ( do_tv_to_ts .and. tpc == 8 ) then ! program code 008 VIRTMP
562  ! 0.61 is used in NCEP prepdata.f to convert T to Tv
563  obs(3,k) = obs(3,k) / (1.0 + 0.61 * obs(2,k))
564  end if
565  end if
566  end if
567 
568  if ( do_tv_to_ts .or. tpc /= 8 ) then ! program code 008 VIRTMP
569  ! sensible temperature
570  if ( obs(3,k) < r8bfms ) then
571  plink % each % t % val = obs(3,k)
572  if ( qms(3,k) < r8bfms ) then
573  plink % each % t % qm = nint(qms(3,k))
574  end if
575  if ( oes(3,k) < r8bfms ) then
576  plink % each % t % err = oes(3,k)
577  end if
578  end if
579  else
580  ! virtual temperature
581  if ( obs(3,k) < r8bfms ) then
582  plink % each % tv % val = obs(3,k)
583  if ( qms(3,k) < r8bfms ) then
584  plink % each % tv % qm = nint(qms(3,k))
585  end if
586  if ( oes(3,k) < r8bfms ) then
587  plink % each % tv % err = oes(3,k)
588  end if
589  end if
590  end if
591 
592  if (obs(5,k) < r8bfms .and. obs(6,k) < r8bfms ) then
593  plink % each % u % val = obs(5,k)
594  plink % each % v % val = obs(6,k)
595  if ( qms(5,k) < r8bfms ) then
596  plink % each % u % qm = nint(qms(5,k))
597  end if
598  if ( qms(6,k) < r8bfms ) then
599  plink % each % v % qm = nint(qms(6,k))
600  else
601  plink % each % v % qm = plink % each % u % qm
602  end if
603  if ( oes(5,k) < r8bfms ) then
604  plink % each % u % err = oes(5,k)
605  end if
606  if ( oes(6,k) < r8bfms ) then
607  plink % each % v % err = oes(6,k)
608  else
609  plink % each % v % err = plink % each % u % err
610  end if
611  end if
612 
613  if ( obs(2,k)>0.0 .and. obs(2,k)<r8bfms ) then
614  plink % each % q % val = obs(2,k)
615  if ( qms(2,k) < r8bfms ) then
616  plink % each % q % qm = nint(qms(2,k))
617  end if
618  if ( oes(2,k) < r8bfms ) then
619  if ( abs(plink%each%p%val - missing_r) > 0.01 ) then
620  if ( abs(plink%each%t%val - missing_r) > 0.01 ) then
621  call calc_qs(plink%each%t%val, plink%each%p%val, qs)
622  else if ( abs(plink%each%tv%val - missing_r) > 0.01 ) then
623  tval = plink%each%tv%val / (1.0 + 0.61 * obs(2,k))
624  call calc_qs(tval, plink%each%p%val, qs)
625  end if
626  plink % each % q % err = oes(2,k)*10.0 ! convert to % from PREPBUFR percent divided by 10
627  plink % each % q % err = plink % each % q % err * qs * 0.01 ! convert from RH to q
628  end if
629  end if
630  end if
631 
632  end do loop_nlevels
633 
634  end do reports
635 
636  write(*,*) 'num_report_infile ', trim(filename), ' : ', num_report_infile
637 
638  call closbf(iunit)
639  close(iunit)
640  if ( use_errtable ) then
641  close(junit)
642  end if
643 
644 end subroutine read_prepbufr
645 
646 !--------------------------------------------------------------
647 
648 subroutine sort_obs_conv
649 
650  implicit none
651 
652  integer(i_kind) :: i, iv, k, ii
653  integer(i_kind) :: ityp, irec, ivar
654  integer(i_kind), dimension(nobtype) :: nrecs
655  integer(i_kind), dimension(nobtype) :: nlocs
656  integer(i_kind), dimension(nobtype) :: nvars
657  integer(i_kind), dimension(nobtype) :: iloc
658  character(len=12) :: obtype
659  logical, dimension(nvar_met) :: vmask ! for counting available variables for one obtype
660 ! logical, dimension(nvar_info) :: imask ! for counting dimension of one var type
661 ! integer(i_kind) :: ninfo_int
662 ! integer(i_kind) :: ninfo_float
663 ! integer(i_kind) :: ninfo_char
664 
665  nrecs(:) = 0
666  nlocs(:) = 0
667  nvars(:) = 0
668 
669  write(*,*) '--- sorting conv obs...'
670 
671  ! set obtype from dump data type t29 and
672  ! and count the numbers
673  plink => phead
674  set_obtype_loop: do while ( associated(plink) )
675 
676  call set_obtype_conv(plink%t29, plink%obtype)
677 
678  ! find index of obtype in obtype_list
679  plink%obtype_idx = ufo_vars_getindex(obtype_list, plink%obtype)
680  if ( plink % obtype_idx > 0 ) then
681  ! obtype assigned, advance ob counts
682  nrecs(plink%obtype_idx) = nrecs(plink%obtype_idx) + 1
683  nlocs(plink%obtype_idx) = nlocs(plink%obtype_idx) + plink%nlevels
684  !else
685  !found undefined t29=534/kx=180,280 in file
686  !write(*,*) 't29 = ', plink%t29
687  !write(*,*) 'kx = ', plink%rptype
688  end if
689 
690  plink => plink%next
691  end do set_obtype_loop
692 
693  !write(*,*) 'num_report_decoded = ', sum(nrecs(:))
694  write(*,'(1x,20x,2a10)') 'nrecs', 'nlocs'
695  do i = 1, nobtype
696  write(*,'(1x,a20,2i10)') obtype_list(i), nrecs(i), nlocs(i)
697  end do
698 
699  ! allocate data arrays with the just counted numbers
700  allocate (xdata(nobtype))
701  do i = 1, nobtype
702  xdata(i) % nrecs = nrecs(i)
703  xdata(i) % nlocs = nlocs(i)
704  vmask = vflag(:,i) == itrue
705  nvars(i) = count(vmask)
706  xdata(i) % nvars = nvars(i)
707 
708  if ( nlocs(i) > 0 ) then
709 
710  allocate (xdata(i)%xinfo_int (nlocs(i), nvar_info))
711  allocate (xdata(i)%xinfo_float(nlocs(i), nvar_info))
712  allocate (xdata(i)%xinfo_char (nlocs(i), nvar_info))
713  xdata(i)%xinfo_int (:,:) = missing_i
714  xdata(i)%xinfo_float(:,:) = missing_r
715  xdata(i)%xinfo_char (:,:) = ''
716 
717  if ( nvars(i) > 0 ) then
718  allocate (xdata(i)%xfield(nlocs(i), nvars(i)))
719  allocate (xdata(i)%var_idx(nvars(i)))
720  xdata(i)%xfield(:,:)%val = missing_r ! initialize
721  xdata(i)%xfield(:,:)%qm = missing_i ! initialize
722  xdata(i)%xfield(:,:)%err = missing_r ! initialize
723  ivar = 0
724  do iv = 1, nvar_met
725  if ( vflag(iv,i) == ifalse ) cycle
726  ivar = ivar + 1
727  xdata(i)%var_idx(ivar) = iv
728  end do
729  end if
730  end if
731  end do
732 
733  ! transfer data from plink to xdata
734 
735  iloc(:) = 0
736  irec = 0
737 
738  plink => phead
739  reports: do while ( associated(plink) )
740  irec = irec + 1
741  ityp = plink%obtype_idx
742  if ( ityp < 0 ) then
743  plink => plink%next
744  cycle reports
745  end if
746  plink % each => plink % first
747  levels: do while ( associated(plink % each) )
748  iloc(ityp) = iloc(ityp) + 1
749 
750  do i = 1, nvar_info
751  if ( type_var_info(i) == nf90_int ) then
752  if ( name_var_info(i) == 'record_number' ) then
753  xdata(ityp)%xinfo_int(iloc(ityp),i) = irec
754  end if
755  else if ( type_var_info(i) == nf90_float ) then
756  if ( name_var_info(i) == 'time' ) then
757  if ( plink%each%dhr > missing_r ) then ! time drift
758  xdata(ityp)%xinfo_float(iloc(ityp),i) = plink%each%dhr
759  else
760  xdata(ityp)%xinfo_float(iloc(ityp),i) = plink%dhr
761  end if
762  else if ( trim(name_var_info(i)) == 'station_elevation' ) then
763  xdata(ityp)%xinfo_float(iloc(ityp),i) = plink%elv
764  else if ( trim(name_var_info(i)) == 'latitude' ) then
765  if ( plink%each%lat > missing_r ) then ! drift
766  xdata(ityp)%xinfo_float(iloc(ityp),i) = plink%each%lat
767  else
768  xdata(ityp)%xinfo_float(iloc(ityp),i) = plink%lat
769  end if
770  else if ( trim(name_var_info(i)) == 'longitude' ) then
771  if ( plink%each%lon > missing_r ) then ! drift
772  xdata(ityp)%xinfo_float(iloc(ityp),i) = plink%each%lon
773  else
774  xdata(ityp)%xinfo_float(iloc(ityp),i) = plink%lon
775  end if
776  else if ( trim(name_var_info(i)) == 'height' ) then
777  xdata(ityp)%xinfo_float(iloc(ityp),i) = plink%each%h%val
778  else if ( trim(name_var_info(i)) == trim(var_prs) ) then
779  xdata(ityp)%xinfo_float(iloc(ityp),i) = plink%each%p%val
780  end if
781  else if ( type_var_info(i) == nf90_char ) then
782  if ( trim(name_var_info(i)) == 'datetime' ) then
783  if ( plink%each%dhr > missing_r ) then ! time drift
784  xdata(ityp)%xinfo_char(iloc(ityp),i) = plink%each%datetime
785  else
786  xdata(ityp)%xinfo_char(iloc(ityp),i) = plink%datetime
787  end if
788  else if ( trim(name_var_info(i)) == 'station_id' ) then
789  xdata(ityp)%xinfo_char(iloc(ityp),i) = plink%stid
790  end if
791  end if ! type_var_info
792  end do
793 
794  do i = 1, nvars(ityp)
795  ivar = xdata(ityp)%var_idx(i)
796  if ( name_var_met(ivar) == trim(var_prs) ) then
797  xdata(ityp)%xfield(iloc(ityp),i)%val = plink%each%p%val
798  xdata(ityp)%xfield(iloc(ityp),i)%qm = plink%each%p%qm
799  xdata(ityp)%xfield(iloc(ityp),i)%err = plink%each%p%err
800  else if ( name_var_met(ivar) == trim(var_u) ) then
801  xdata(ityp)%xfield(iloc(ityp),i)%val = plink%each%u%val
802  xdata(ityp)%xfield(iloc(ityp),i)%qm = plink%each%u%qm
803  xdata(ityp)%xfield(iloc(ityp),i)%err = plink%each%u%err
804  else if ( name_var_met(ivar) == trim(var_v) ) then
805  xdata(ityp)%xfield(iloc(ityp),i)%val = plink%each%v%val
806  xdata(ityp)%xfield(iloc(ityp),i)%qm = plink%each%v%qm
807  xdata(ityp)%xfield(iloc(ityp),i)%err = plink%each%v%err
808  else if ( name_var_met(ivar) == trim(var_ts) ) then
809  xdata(ityp)%xfield(iloc(ityp),i)%val = plink%each%t%val
810  xdata(ityp)%xfield(iloc(ityp),i)%qm = plink%each%t%qm
811  xdata(ityp)%xfield(iloc(ityp),i)%err = plink%each%t%err
812  else if ( name_var_met(ivar) == trim(var_tv) ) then
813  xdata(ityp)%xfield(iloc(ityp),i)%val = plink%each%tv%val
814  xdata(ityp)%xfield(iloc(ityp),i)%qm = plink%each%tv%qm
815  xdata(ityp)%xfield(iloc(ityp),i)%err = plink%each%tv%err
816  else if ( name_var_met(ivar) == trim(var_q) ) then
817  xdata(ityp)%xfield(iloc(ityp),i)%val = plink%each%q%val
818  xdata(ityp)%xfield(iloc(ityp),i)%qm = plink%each%q%qm
819  xdata(ityp)%xfield(iloc(ityp),i)%err = plink%each%q%err
820  else if ( name_var_met(ivar) == trim(var_ps) ) then
821  xdata(ityp)%xfield(iloc(ityp),i)%val = plink%ps%val
822  xdata(ityp)%xfield(iloc(ityp),i)%qm = plink%ps%qm
823  xdata(ityp)%xfield(iloc(ityp),i)%err = plink%ps%err
824  end if
825  xdata(ityp)%xfield(iloc(ityp),i)%rptype = plink%rptype
826  end do
827  plink % each => plink % each % next
828  end do levels
829  plink => plink%next
830  end do reports
831 
832  ! done with plink
833  ! release the linked list
834  plink => phead
835  do while ( associated(plink) )
836  phead => plink%next
837  do while ( associated(plink % each) )
838  if ( associated(plink % each) ) deallocate (plink % each)
839  end do
840  nullify (plink%first)
841  if ( associated (plink) ) deallocate (plink)
842  plink => phead
843  end do
844  nullify (phead)
845 
846 end subroutine sort_obs_conv
847 
848 !--------------------------------------------------------------
849 
850 subroutine filter_obs_conv
851 
852 ! refer to GSI/read_prepbufr.f90
853 !
854 ! iuse information is extracted from global_convinfo.txt
855 ! to do: come up with a better way to handle iuse
856 
857  implicit none
858 
859  logical :: adjust_obserr
860  integer(i_kind) :: zqm
861  integer(i_kind) :: k
862  integer(i_kind) :: iuse_ps
863  integer(i_kind) :: iuse_uv
864  integer(i_kind) :: iuse_t
865  integer(i_kind) :: iuse_tv
866  integer(i_kind) :: iuse_q
867  real(r_kind) :: hpa500 = 50000.0
868  real(r_kind) :: hpa100 = 10000.0
869  real(r_kind) :: inflate_factor = 1.2
870 
871  adjust_obserr = .false.
872 
873  write(*,*) '--- filtering conv obs ---'
874  plink => phead
875  link_loop: do while ( associated(plink) )
876 
877  plink % each => plink % first
878 
879  do while ( associated(plink % each) )
880 
881  if ( trim(plink%obtype) == 'sfc' ) then
882 
883  ! initialize as not used
884  iuse_ps = ifalse
885 
886  if ( plink%rptype == 120 .or. &
887  plink%rptype == 180 .or. &
888  plink%rptype == 181 .or. &
889  plink%rptype == 182 .or. &
890  plink%rptype == 187 ) then
891 
892  iuse_ps = itrue
893 
894  zqm = plink % each % h % qm
895  if ( zqm >= lim_qm .and. zqm /= 15 .and. zqm /= 9 ) then
896  plink % ps % qm = 9
897  end if
898 
899  if ( plink % ps % val < hpa500 .or. plink % ps % qm >= lim_qm .or. &
900  zqm >= lim_qm ) then
901  iuse_ps = ifalse
902  end if
903 
904  if ( adjust_obserr ) then
905  if ( plink % ps % qm == 3 .or. plink % ps % qm == 7 ) then
906  plink % ps % err = plink % ps % err * inflate_factor
907  end if
908  end if
909  end if
910 
911  if ( iuse_ps == ifalse .and. plink % ps % qm /= missing_i ) then
912  plink % ps % qm = plink % ps % qm + not_use
913  end if
914  end if
915 
916  ! initialize as not used
917  iuse_uv = ifalse
918  iuse_t = ifalse
919  iuse_tv = ifalse
920  iuse_q = ifalse
921 
922  ! adjust observation height for wind reports
923  if ( plink % rptype >= 280 .and. plink % rptype < 300 ) then
924  plink % each % h % val = plink % elv + 10.0
925  if ( plink % rptype == 280 ) then
926  if ( plink % t29 == 522 .or. &
927  plink % t29 == 523 .or. &
928  plink % t29 == 531 ) then
929  plink % each % h % val = 20.0
930  end if
931  end if
932  if ( plink % rptype == 282 ) then
933  plink % each % h % val = plink % elv + 20.0
934  end if
935  if ( plink % rptype == 285 .or. &
936  plink % rptype == 286 .or. &
937  plink % rptype == 289 .or. &
938  plink % rptype == 290 ) then
939  plink % each % h % val = plink % elv
940  plink % elv = 0.0
941  end if
942  else
943  if ( plink % rptype >= 221 .and. plink % rptype <= 229 ) then
944  if ( abs(plink % each % h % val - missing_r) > 0.01 ) then
945  if ( plink % elv >= plink % each % h % val ) then
946  plink % each % h % val = plink % elv + 10.0
947  end if
948  end if
949  end if
950  end if ! wind types
951 
952  if ( plink%rptype == 120 .or. &
953  plink%rptype == 132 .or. &
954  plink%rptype == 133 .or. &
955  plink%rptype == 180 .or. &
956  plink%rptype == 182 ) then
957  if ( plink % each % q % qm < lim_qm ) iuse_q = itrue
958  end if
959 
960  if ( plink%rptype == 120 .or. &
961  plink%rptype == 130 .or. &
962  plink%rptype == 132 .or. &
963  plink%rptype == 133 .or. &
964  plink%rptype == 180 .or. &
965  plink%rptype == 182 ) then
966  if ( plink % each % t % qm < lim_qm ) iuse_t = itrue
967  if ( plink % each % tv % qm < lim_qm ) iuse_tv = itrue
968  end if
969 
970  if ( plink%rptype == 220 .or. &
971  plink%rptype == 221 .or. &
972  plink%rptype == 223 .or. &
973  plink%rptype == 224 .or. &
974  plink%rptype == 229 .or. &
975  plink%rptype == 230 .or. &
976  plink%rptype == 231 .or. &
977  plink%rptype == 232 .or. &
978  plink%rptype == 233 .or. &
979  plink%rptype == 280 .or. &
980  plink%rptype == 282 .or. &
981  plink%rptype == 289 .or. &
982  plink%rptype == 290 ) then
983  if ( plink % each % u % qm < lim_qm .and. plink % each % v % qm < lim_qm ) iuse_uv = itrue
984  else if ( plink%rptype >= 241 .and. plink%rptype <= 260 ) then
985  if ( plink%rptype == 242 ) then
986  if ( plink % satid == 171 .or. &
987  plink % satid == 172 .or. &
988  plink % satid == 173 .or. &
989  plink % satid == 174 ) then
990  if ( plink % each % u % qm < lim_qm .and. plink % each % v % qm < lim_qm ) iuse_uv = itrue
991  end if
992  else if ( plink%rptype == 243 ) then
993  if ( plink % satid == 55 .or. &
994  plink % satid == 70 ) then
995  if ( plink % each % u % qm < lim_qm .and. plink % each % v % qm < lim_qm ) iuse_uv = itrue
996  end if
997  else if ( plink%rptype == 244 ) then
998  if ( plink % satid == 3 .or. &
999  plink % satid == 4 .or. &
1000  plink % satid == 206 .or. &
1001  plink % satid == 207 .or. &
1002  plink % satid == 209 .or. &
1003  plink % satid == 223 ) then
1004  if ( plink % each % u % qm < lim_qm .and. plink % each % v % qm < lim_qm ) iuse_uv = itrue
1005  end if
1006  else if ( plink%rptype == 245 ) then
1007  if ( plink % satid == 259 .or. &
1008  plink % satid == 270 ) then
1009  if ( plink % each % u % qm < lim_qm .and. plink % each % v % qm < lim_qm ) iuse_uv = itrue
1010  end if
1011  else if ( plink%rptype == 246 ) then
1012  if ( plink % satid == 259 .or. &
1013  plink % satid == 270 ) then
1014  if ( plink % each % u % qm < lim_qm .and. plink % each % v % qm < lim_qm ) iuse_uv = itrue
1015  end if
1016  else if ( plink%rptype == 247 ) then
1017  if ( plink % satid == 259 .or. &
1018  plink % satid == 270 ) then
1019  if ( plink % each % u % qm < lim_qm .and. plink % each % v % qm < lim_qm ) iuse_uv = itrue
1020  end if
1021  else if ( plink%rptype == 250 ) then
1022  if ( plink % satid == 171 .or. &
1023  plink % satid == 172 .or. &
1024  plink % satid == 173 .or. &
1025  plink % satid == 174 ) then
1026  if ( plink % each % u % qm < lim_qm .and. plink % each % v % qm < lim_qm ) iuse_uv = itrue
1027  end if
1028  else if ( plink%rptype == 252 ) then
1029  if ( plink % satid == 171 .or. &
1030  plink % satid == 172 .or. &
1031  plink % satid == 173 .or. &
1032  plink % satid == 174 ) then
1033  if ( plink % each % u % qm < lim_qm .and. plink % each % v % qm < lim_qm ) iuse_uv = itrue
1034  end if
1035  else if ( plink%rptype == 253 ) then
1036  if ( plink % satid == 55 .or. &
1037  plink % satid == 70 ) then
1038  if ( plink % each % u % qm < lim_qm .and. plink % each % v % qm < lim_qm ) iuse_uv = itrue
1039  end if
1040  else if ( plink%rptype == 254 ) then
1041  if ( plink % satid == 55 .or. &
1042  plink % satid == 70 ) then
1043  if ( plink % each % u % qm < lim_qm .and. plink % each % v % qm < lim_qm ) iuse_uv = itrue
1044  end if
1045  else if ( plink%rptype == 257 ) then
1046  if ( plink % satid == 783 .or. &
1047  plink % satid == 784 ) then
1048  if ( plink % each % u % qm < lim_qm .and. plink % each % v % qm < lim_qm ) iuse_uv = itrue
1049  end if
1050  else if ( plink%rptype == 258 ) then
1051  if ( plink % satid == 783 .or. &
1052  plink % satid == 784 ) then
1053  if ( plink % each % u % qm < lim_qm .and. plink % each % v % qm < lim_qm ) iuse_uv = itrue
1054  end if
1055  else if ( plink%rptype == 259 ) then
1056  if ( plink % satid == 783 .or. &
1057  plink % satid == 784 ) then
1058  if ( plink % each % u % qm < lim_qm .and. plink % each % v % qm < lim_qm ) iuse_uv = itrue
1059  end if
1060  else if ( plink%rptype == 260 ) then
1061  if ( plink % satid == 224 ) then
1062  if ( plink % each % u % qm < lim_qm .and. plink % each % v % qm < lim_qm ) iuse_uv = itrue
1063  end if
1064  end if
1065  end if
1066 
1067  if ( plink%rptype == 243 .or. &
1068  plink%rptype == 253 .or. &
1069  plink%rptype == 254 ) then
1070  if ( iuse_uv == itrue .and. plink % each % pccf < 85.0 ) then
1071  iuse_uv = ifalse
1072  end if
1073  end if
1074 
1075  if ( plink % each % p % qm >= lim_qm ) then
1076  iuse_uv = ifalse
1077  iuse_t = ifalse
1078  iuse_tv = ifalse
1079  iuse_q = ifalse
1080  end if
1081 
1082  if ( iuse_uv == ifalse .and. plink % each % u % qm /= missing_i ) then
1083  plink % each % u % qm = plink % each % u % qm + not_use
1084  end if
1085  if ( iuse_uv == ifalse .and. plink % each % v % qm /= missing_i ) then
1086  plink % each % v % qm = plink % each % v % qm + not_use
1087  end if
1088  if ( iuse_t == ifalse .and. plink % each % t % qm /= missing_i ) then
1089  plink % each % t % qm = plink % each % t % qm + not_use
1090  end if
1091  if ( iuse_tv == ifalse .and. plink % each % tv % qm /= missing_i ) then
1092  plink % each % tv % qm = plink % each % tv % qm + not_use
1093  end if
1094  if ( iuse_q == ifalse .and. plink % each % q % qm /= missing_i ) then
1095  plink % each % q % qm = plink % each % q % qm + not_use
1096  end if
1097 
1098  if ( adjust_obserr ) then
1099  if ( plink % each % p % val < hpa100 ) then
1100  if ( abs(plink % each%t%err - missing_r) > 0.01 ) then
1101  plink % each % t % err = plink % each % t % err * inflate_factor
1102  end if
1103  if ( abs(plink % each%tv%err - missing_r) > 0.01 ) then
1104  plink % each % tv % err = plink % each % tv % err * inflate_factor
1105  end if
1106  end if
1107  if ( plink % each % t % qm == 3 .or. &
1108  plink % each % t % qm == 7 ) then
1109  plink % each % t % err = plink % each % t % err * inflate_factor
1110  end if
1111  if ( plink % each % tv % qm == 3 .or. &
1112  plink % each % tv % qm == 7 ) then
1113  plink % each % tv % err = plink % each % tv % err * inflate_factor
1114  end if
1115  if ( plink % each % u % qm == 3 .or. &
1116  plink % each % u % qm == 7 ) then
1117  plink % each % u % err = plink % each % u % err * inflate_factor
1118  end if
1119  if ( plink % each % v % qm == 3 .or. &
1120  plink % each % v % qm == 7 ) then
1121  plink % each % v % err = plink % each % v % err * inflate_factor
1122  end if
1123  if ( plink % each % q % qm == 3 .or. &
1124  plink % each % q % qm == 7 ) then
1125  plink % each % q % err = plink % each % q % err * inflate_factor
1126  end if
1127  end if
1128 
1129  plink % each => plink % each%next
1130 
1131  end do ! nlevels
1132 
1133  plink => plink%next
1134  end do link_loop
1135 
1136 end subroutine filter_obs_conv
1137 
1138 !--------------------------------------------------------------
1139 
1140 subroutine init_field(self)
1141  implicit none
1142  class(field_type), intent(inout) :: self
1143  real(r_kind) :: rfill
1144  integer(i_kind) :: ifill
1145 
1146  rfill = missing_r
1147  ifill = missing_i
1148 
1149  self % val = rfill
1150  self % qm = ifill
1151  self % err = rfill
1152 end subroutine init_field
1153 
1154 !--------------------------------------------------------------
1155 
1156 subroutine init_each_level(self)
1157  implicit none
1158  class(each_level_type), intent(inout) :: self
1159  real(r_kind) :: rfill
1160  integer(i_kind) :: ifill
1161 
1162  rfill = missing_r
1163  ifill = missing_i
1164 
1165  self % lat = rfill
1166  self % lon = rfill
1167  self % dhr = rfill
1168  self % pccf = rfill
1169  self % datetime = ''
1170  call self % h % init()
1171  call self % u % init()
1172  call self % v % init()
1173  call self % t % init()
1174  call self % tv % init()
1175  call self % p % init()
1176  call self % q % init()
1177 
1178 end subroutine init_each_level
1179 
1180 !--------------------------------------------------------------
1181 
1182 subroutine init_report(self)
1183  implicit none
1184  class(report_conv), intent(inout) :: self
1185  real(r_kind) :: rfill
1186  integer(i_kind) :: ifill
1187 
1188  rfill = missing_r
1189  ifill = missing_i
1190 
1191  self % msg_type = ''
1192  self % stid = ''
1193  self % datetime = ''
1194  self % lon = rfill
1195  self % lat = rfill
1196  self % dhr = rfill
1197  self % elv = rfill
1198  self % rptype = ifill
1199  self % t29 = ifill
1200  self % satid = ifill
1201 
1202  call self % ps % init()
1203  call self % slp % init()
1204  call self % pw % init()
1205 
1206 end subroutine init_report
1207 
1208 !--------------------------------------------------------------
1209 
1210 subroutine calc_qs (t, p, qs, wrt_ice)
1211 
1212 ! calculate saturation vapor pressure and saturation specific humidity
1213 ! given temperature and pressure
1214 
1215  implicit none
1216 
1217  real(r_kind), intent(in) :: t, p
1218  real(r_kind), intent(out) :: qs
1219  logical, intent(in), optional :: wrt_ice
1220 
1221  real(r_kind), parameter :: t_kelvin = 273.15
1222  real(r_kind), parameter :: t_triple = 273.16 ! triple point of water
1223  real(r_kind), parameter :: gas_constant = 287.0
1224  real(r_kind), parameter :: gas_constant_v = 461.6
1225  real(r_kind), parameter :: rd_over_rv = gas_constant/gas_constant_v
1226  real(r_kind), parameter :: rd_over_rv1 = 1.0 - rd_over_rv
1227  real(r_kind), parameter :: es_alpha = 611.2
1228  real(r_kind), parameter :: es_beta = 17.67
1229  real(r_kind), parameter :: es_gamma = 243.5
1230  real(r_kind), parameter :: t_c_ref1 = 0.0 ! C
1231  real(r_kind), parameter :: t_c_ref2 = -20.0 ! C
1232  real(r_kind), parameter :: a0 = 6.107799961
1233  real(r_kind), parameter :: a1 = 4.436518521e-01
1234  real(r_kind), parameter :: a2 = 1.428945805e-02
1235  real(r_kind), parameter :: a3 = 2.650648471e-04
1236  real(r_kind), parameter :: a4 = 3.031240396e-06
1237  real(r_kind), parameter :: a5 = 2.034080948e-08
1238  real(r_kind), parameter :: a6 = 6.136820929e-11
1239  real(r_kind), parameter :: c1 = 9.09718
1240  real(r_kind), parameter :: c2 = 3.56654
1241  real(r_kind), parameter :: c3 = 0.876793
1242  real(r_kind), parameter :: c4 = 6.1071
1243  real(r_kind) :: t_c, t1_c ! T in degree C
1244  real(r_kind) :: es
1245  logical :: ice
1246 
1247  ice = .false.
1248  if ( present(wrt_ice) ) then
1249  if ( wrt_ice ) ice = .true.
1250  end if
1251 
1252  t_c = t - t_kelvin
1253  t1_c = t - t_triple
1254 
1255  ! Calculate saturation vapor pressure es
1256 
1257  if ( .not. ice ) then ! over water only
1258 
1259  es = es_alpha * exp( es_beta * t_c / ( t_c + es_gamma ) )
1260 
1261  else ! consider ice-water and ice effects
1262 
1263  if ( t1_c > t_c_ref1 ) then ! vapor pressure over water
1264  es = es_alpha * exp( es_beta * t_c / ( t_c + es_gamma ) )
1265  else if ( (t1_c <= t_c_ref1) .and. (t1_c >= t_c_ref2) ) then ! vapor pressure over water below 0C
1266  es = a0 + t1_c * (a1 + t1_c * (a2 + t1_c * (a3 + t1_c * (a4 + t1_c * (a5 + t1_c * a6)))))
1267  es = es * 100.0 ! to Pa
1268  else ! vapor pressure over ice
1269  es = 10.0 ** ( -c1 * (t_triple / t - 1.0) - c2 * alog10(t_triple / t) + &
1270  c3 * (1.0 - t / t_triple) + alog10(c4))
1271  es = es * 100.0 ! to Pa
1272  end if
1273 
1274  end if
1275 
1276  ! Calculate saturation specific humidity qs
1277 
1278  qs = rd_over_rv * es / ( p - rd_over_rv1 * es )
1279 
1280 end subroutine calc_qs
1281 
1282 end module prepbufr_mod
1283 
static void count(void *counter, const double *data, size_t n)
Definition: UnitTests.cc:531
integer(i_kind), parameter nstring
Definition: define_mod.f90:15
integer(i_kind), parameter nvar_met
Definition: define_mod.f90:19
character(len=nstring), dimension(nobtype) obtype_list
Definition: define_mod.f90:28
character(len=nstring), dimension(nvar_info) name_var_info
Definition: define_mod.f90:96
integer(i_kind), parameter nobtype
Definition: define_mod.f90:17
integer(i_kind), parameter itrue
Definition: define_mod.f90:13
real(r_kind), parameter t_kelvin
Definition: define_mod.f90:9
integer(i_kind), parameter ifalse
Definition: define_mod.f90:14
integer(i_kind), parameter not_use
Definition: define_mod.f90:12
integer(i_kind), parameter missing_i
Definition: define_mod.f90:11
integer(i_kind), parameter ndatetime
Definition: define_mod.f90:16
integer(i_kind), parameter nvar_info
Definition: define_mod.f90:20
character(len=nstring), dimension(nvar_met) name_var_met
Definition: define_mod.f90:38
subroutine set_obtype_conv(t29, obtype)
Definition: define_mod.f90:190
real(r_kind), parameter missing_r
Definition: define_mod.f90:10
type(xdata_type), dimension(:), allocatable xdata
Definition: define_mod.f90:185
integer(i_kind), dimension(nvar_met, nobtype) vflag
Definition: define_mod.f90:49
integer(i_kind), dimension(nvar_info) type_var_info
Definition: define_mod.f90:108
Definition: kinds.f90:1
integer, parameter, public i_kind
Definition: kinds.f90:71
integer, parameter, public r_kind
Definition: kinds.f90:100
integer, parameter, public r_double
Definition: kinds.f90:80
subroutine, public sort_obs_conv
integer(i_kind), parameter lim_qm
subroutine, public read_prepbufr(filename, filedate)
subroutine init_field(self)
type(report_conv), pointer phead
subroutine calc_qs(t, p, qs, wrt_ice)
type(report_conv), pointer plink
subroutine init_each_level(self)
subroutine, public filter_obs_conv
subroutine init_report(self)
integer function, public ufo_vars_getindex(vars, varname)
character(len=maxvarlen), parameter, public var_prs
character(len=maxvarlen), parameter, public var_q
character(len=maxvarlen), parameter, public var_v
character(len=maxvarlen), parameter, public var_ts
character(len=maxvarlen), parameter, public var_u
character(len=maxvarlen), parameter, public var_ps
character(len=maxvarlen), parameter, public var_tv
subroutine, public da_advance_time(date_in, dtime, date_out)
Definition: utils_mod.f90:12