1module backgroundCheck_mod
2 ! MODULE backgroundCheck_mod (prefix='bgck' category='1. High-level functionality')
3 !
4 !:Purpose: Performs the background check on all conventional observations
5 !
6 use mathPhysConstants_mod
7 use bufr_mod
8 use obsSpaceData_mod
9 use gps_mod
10 use utilities_mod
11 use columnData_mod
12 use obsSpaceDiag_mod
13 use verticalCoord_mod
14 use horizontalCoord_mod
15 use obsSpaceErrorStdDev_mod
16 use obsFamilyList_mod
17 use codtyp_mod
18
19 implicit none
20 private
21
22 ! public procedures
23 public :: bgck_bgcheck_conv
24
25 integer, parameter :: numFamilyToProcess = 11
26 character(len=2), parameter :: familyListToProcess(numFamilyToProcess)= (/ &
27 'UA','AI','SF','SC','SW','PR','RO','GP','RA', &
28 'CH','AL' /)
29
30 contains
31
32 !--------------------------------------------------------------------------
33 ! bgck_bgcheck_conv
34 !--------------------------------------------------------------------------
35 subroutine bgck_bgcheck_conv( columnTrlOnAnlIncLev, columnTrlOnTrlLev, hco_anl, obsSpaceData )
36 !
37 !:Purpose: Do background check on all conventional observations
38 !
39 implicit none
40
41 ! Arguments:
42 type(struct_obs) , intent(inout) :: obsSpaceData ! Observation-related data
43 type(struct_columnData) , intent(inout) :: columnTrlOnAnlIncLev ! column data on analysis levels
44 type(struct_columnData) , intent(inout) :: columnTrlOnTrlLev ! column data on trial levels
45 type(struct_hco), pointer, intent(in) :: hco_anl ! horizontal grid structure
46
47 ! Locals:
48 integer :: familyIndex
49 integer :: nulNam, ier, fnom, fclos
50 logical :: noObsToProcess
51 character(len=*), parameter :: myName = 'bgck_bgcheck_conv'
52
53 ! namelist variables
54 logical :: new_bgck_sw ! choose to use the 'new' background check for SW obs
55 namelist /NAMBGCKCONV/ new_bgck_sw
56
57 write(*,*) myName//' begin conventional data background check'
58
59 ! Check if any observations are present for conventional background check
60 noObsToProcess = .true.
61 do familyIndex = 1, numFamilyToProcess
62 if (obs_famExist(obsSpaceData,familyListToProcess(familyIndex))) then
63 noObsToProcess = .false.
64 end if
65 end do
66 if (noObsToProcess) then
67 write(*,*) myName//': No observations to process'
68 return
69 end if
70
71 call utl_tmg_start(117,'--BgckConventional')
72
73 new_bgck_sw = .false.
74
75 nulNam=0
76 ier = fnom( nulNam, 'flnml', 'r/o', 0 )
77 read( nulNam, nml = NAMBGCKCONV, IOSTAT = ier )
78 if ( ier /= 0 ) write(*,*) myName//': no valid namelist NAMBGCKCONV found, default values will be taken:'
79 write(*,*) myName//': new_bgck_sw = ',new_bgck_sw
80 ier = fclos(nulNam)
81
82
83 ! Obtain or calc OmP-error std dev when requested and possible.
84 ! Otherwise calc HBHT contribution (sigma_B in observation space)
85 ! --------------------------------------------------------------------
86 call ose_computeStddev( columnTrlOnAnlIncLev, hco_anl, & ! IN
87 obsSpaceData ) ! INOUT
88
89 ! DO A BACKGROUND CHECK ON ALL THE OBSERVATIONS
90 ! ----------------------------------------------
91
92 do familyIndex = 1, ofl_numFamily
93 ! For SW only, old and new background check schemes controlled by "new_bgck_sw"
94 if ( obs_famExist( obsSpaceData, ofl_familyList( familyIndex )) ) then
95 call bgck_data( ofl_familyList(familyIndex), obsSpaceData, new_bgck_sw )
96 end if
97 end do
98
99 if (obs_famExist( obsSpaceData, 'RO' )) call bgck_gpsro( columnTrlOnTrlLev , obsSpaceData )
100
101 ! Conduct obs-space post-processing diagnostic tasks (some diagnostic
102 ! computations controlled by NAMOSD namelist in flnml)
103
104 call osd_ObsSpaceDiag( obsSpaceData, columnTrlOnAnlIncLev, hco_anl, analysisMode_opt = .false. )
105
106 call utl_tmg_stop(117)
107
108 end subroutine bgck_bgcheck_conv
109
110 !--------------------------------------------------------------------------
111 ! bgck_data
112 !--------------------------------------------------------------------------
113 subroutine bgck_data( obsFamily, obsData, new_bgck_sw )
114 !
115 !:Purpose: Calculate a background check for a data family and set the
116 ! appropriate quality-control flags in obsSpaceData
117 implicit none
118
119 ! NOTE 1: gps_gb_YSFERRWGT IN MODGPSZTD_MOD (FROM NML FILE) IS USED HERE FOR ERROR WEIGHTING
120 ! OF TIME SERIES (FGAT) GPS MET OBSERVATIONS PS, TS, DPDS. IT IS APPLIED
121 ! (ALONG WITH gps_gb_YZDERRWGT FOR ZTD) IN S/R SETERR AS A MULT. FACTOR TO ERRORS.
122 ! gps_gb_YZDERRWGT AND gps_gb_YSFERRWGT = 1 FOR NORMAL 3D-VAR (3D-THINNING).
123
124 ! Arguments:
125 character(len=2), intent(in) :: obsFamily ! current observation family
126 type(struct_obs), intent(inout) :: obsData ! obsSpaceData
127 logical , intent(in) :: new_bgck_sw
128
129 ! Locals:
130 real(8) :: averageFGE, averageOER
131 integer :: obsFlag, obsVarno, headerIndex, codeType, bodyIndex, obsCount
132 integer :: numberObs, numberObsRejected, INZOBS, INZREJ
133 integer :: INPOBS, INTOBS, INDOBS, INPREJ, INTREJ, INDREJ
134 real(8) :: ZOER,ZOMP,ZFGE,ZOMPER,ZBGCHK,ZVAR,ZLEV,ZLAT,ZLON,ZSOP
135 logical :: LLOK, LLZD
136 character(len=12) :: stnid
137 integer :: i_ass, i_vco, i_oth, bodyIndex_u, bodyIndex_v, bodyIndex_start
138 real(8) :: uu_d, uu_r, uu_f, vv_d, vv_r, vv_f, duv2, duv2_lim, zslev
139 logical :: found_u, found_v
140 character(len=*), parameter :: myName = 'bgck_data'
141
142 write(*,*)' '
143 write(*,*) ' ------------------------------'
144 write(*,*) myName//' background check for', obsFamily, ' data'
145 write(*,*) ' ------------------------------'
146 write(*,*) ' '
147 write(*,'(a55,a74)')' STNID LATITU LONGITU ID Elem Level ', &
148 ' Value Sigmao Sigmap O-P SigmaOP qcflag '
149 write(*,'(a55,a74)')' ----- ------ ------- -- ---- ----- ', &
150 ' ----- ------ ------ --- ------- ------ '
151
152 obsCount = 0
153 averageFGE = 0.d0
154 averageOER=0.d0
155
156 numberObs = 0
157 numberObsRejected = 0
158
159 ! Initialize counters for GP family observations
160
161 if ( obsFamily == 'GP' ) then
162 INZOBS=0
163 INPOBS=0
164 INTOBS=0
165 INDOBS=0
166 INZREJ=0
167 INPREJ=0
168 INTREJ=0
169 INDREJ=0
170 end if
171
172 if ( .not. new_bgck_sw .or. obsFamily /= 'SW' ) then
173
174 ! loop over all header indices of the current observation family
175 call obs_set_current_header_list( obsData, obsFamily )
176 HEADER: do
177 headerIndex = obs_getHeaderIndex( obsData )
178 if ( headerIndex < 0 ) exit HEADER
179
180 stnid = obs_elem_c( obsData, 'STID', headerIndex )
181
182 ! 1. Computation of (HX - Z)**2/(SIGMAo**2 +SIGMAp**2)
183 ! ----------------------------------------------------
184
185 ! loop over all body indices for the current headerIndex
186 call obs_set_current_body_list( obsData, headerIndex )
187 BODY: do
188 bodyIndex = obs_getBodyIndex( obsData )
189 if (bodyIndex < 0 ) exit BODY
190
191 obsVarno = obs_bodyElem_i( obsData, OBS_VNM, bodyIndex )
192 LLOK = ( obs_bodyElem_i( obsData, OBS_ASS, bodyIndex ) == obs_assimilated )
193 if ( LLOK ) then
194 numberObs = numberObs + 1
195 if ( obsFamily == 'GP' ) then
196 if ( obsVarno == BUFR_NEZD ) INZOBS = INZOBS+1
197 if ( obsVarno == BUFR_NEPS ) INPOBS = INPOBS+1
198 if ( obsVarno == BUFR_NETS ) INTOBS = INTOBS+1
199 if ( obsVarno == BUFR_NESS ) INDOBS = INDOBS+1
200 end if
201 ZVAR = obs_bodyElem_r( obsData, OBS_VAR, bodyIndex )
202 ZLEV = obs_bodyElem_r( obsData, OBS_PPP, bodyIndex )
203 ZLAT = obs_headElem_r( obsData, OBS_LAT, headerIndex ) * MPC_DEGREES_PER_RADIAN_R8
204 ZLON = obs_headElem_r( obsData, OBS_LON, headerIndex ) * MPC_DEGREES_PER_RADIAN_R8
205
206 ! BACKGROUND CHECK
207
208 ZOMP = obs_bodyElem_r( obsData, OBS_OMP, bodyIndex )
209
210 ! Get error std dev
211
212 ! std(O-P) (valid/available if > 0.0)
213 zomper = obs_bodyElem_r( obsData, OBS_OMPE, bodyIndex )
214
215 ! std(O)
216 zoer = obs_bodyElem_r( obsData, OBS_OER, bodyIndex )
217 ! std(P)
218 zfge = obs_bodyElem_r( obsData, OBS_HPHT, bodyIndex )
219 ! NOTE: For GB-GPS ZTD observations (GP family), ZFGE is not the FGE but
220 ! rather Std(O-P) set in s/r SETERRGPSGB.
221 if ( obsFamily == 'GP' .and. obsVarno == BUFR_NEZD ) then
222 if ( zomper <= 0.0d0 .and. zfge > 0.0d0 ) zomper = zfge
223 end if
224
225 ! Protect against error std dev values that are too small
226 if ( obsFamily == 'GP' ) then
227 if ( obsVarno == BUFR_NEZD ) then
228 ZOER = ZOER / gps_gb_YZDERRWGT
229 else
230 ZOER = ZOER / gps_gb_YSFERRWGT
231 end if
232 if ( ZOER < 1.0d-3 .and. obsVarno /= BUFR_NEZD ) then
233 write(*,*)' Problem for GP STNID ZOER= ' , stnid, ZOER
234 call utl_abort( myName//': PROBLEM WITH OER.')
235 end if
236 IF ( ZFGE < 1.0d-3 ) then
237 write(*,*)' Problem for GP STNID FGE= ', stnid, ZFGE
238 ZFGE=1.0d-3
239 end if
240 if ( zomper > 0.0d0 .and. zomper < 1.0d-3 ) zomper = 1.0d-3
241 else if ( obsFamily == 'CH' ) then
242 if ( ZFGE**2 + ZOER**2 < 1.0d-60) then
243 write(*,*) ' Problem for STNID FGE ZOER=', stnid, ZFGE, ZOER
244 ZFGE=1.0d30
245 ZOER=1.0d-30
246 end if
247 if ( zomper > 0.0 .and. zomper < 1.0d-30 ) zomper = 1.0d-30
248 else
249 if ( zfge < 0.0d0 ) zfge = 0.0d0
250 if ( ZFGE**2 + ZOER**2 < 1.0d-5)then
251 write(*,*) ' Problem for STNID FGE ZOER=', stnid, ZFGE, ZOER
252 ZFGE=1.0d-5
253 ZOER=1.0d-5
254 end if
255 if ( zomper > 0.0 .and. zomper < 1.0D-5 ) zomper = 1.0d-5
256 end if
257
258 ! Calculate zbgchk
259
260 if ( zomper > 0.0d0 ) then
261 zbgchk = (zomp**2)/(zomper**2)
262 zsop = zomper
263 else
264 ZBGCHK=(ZOMP)**2/(ZFGE**2 + ZOER**2)
265 ZSOP = SQRT(ZFGE**2 + ZOER**2)
266 end if
267
268 ! UPDATE QUALITY CONTROL FLAGS, based on zbgchk
269 ! ( ELEMENT FLAGS + GLOBAL HEADER FLAGS)
270 obsVarno = obs_bodyElem_i( obsData, OBS_VNM, bodyIndex )
271 if( obsVarno == bufr_nees .and. obs_bodyElem_i( obsData, OBS_XTR, bodyIndex ) == 0 ) then
272 averageFGE = averageFGE + zfge * zfge
273 averageOER = averageOER + zoer * zoer
274 obsCount = obsCount + 1
275 end if
276 codeType = obs_headElem_i( obsData, OBS_ITY, headerIndex )
277 obsFlag = ISETFLAG( obsFamily, codeType, obsVarno, ZBGCHK )
278
279 ! CONVERT ZTD VALUES FROM M TO MM FOR PRINTOUT
280
281 LLZD = .FALSE.
282 if ( obsFamily == 'GP' .and. obsVarno == BUFR_NEZD ) then
283 ZVAR = ZVAR * 1000.0D0
284 ZOER = ZOER * 1000.0D0
285 ZFGE = ZFGE * 1000.0D0
286 ZOMP = ZOMP * 1000.0D0
287 ZSOP = ZSOP * 1000.0D0
288 LLZD = .TRUE.
289 end if
290
291 stnid = obs_elem_c( obsData, 'STID', headerIndex )
292 if ( obsFlag >= 2 .or. ( LLZD .and. gps_gb_LTESTOP )) then
293 if ( obsFamily /= 'CH' ) then
294 write(*,122) &
295 stnid, zlat, zlon, codeType, obsVarno, ZLEV, ZVAR, ZOER, &
296 ZFGE, ZOMP, ZSOP, ZBGCHK, obsFlag
297 else
298 write(*,124) &
299 stnid, zlat, zlon, codeType, obsVarno, ZLEV, ZVAR, ZOER, &
300 ZFGE, ZOMP, ZSOP, ZBGCHK, obsFlag
301 end if
302 if ( obsFlag >= 2 ) numberObsRejected = numberObsRejected + 1
303 if ( obsFlag >= 2 .and. obsFamily == 'GP' ) then
304 if ( obsVarno == BUFR_NEZD ) INZREJ = INZREJ+1
305 if ( obsVarno == BUFR_NEPS ) INPREJ = INPREJ+1
306 if ( obsVarno == BUFR_NETS ) INTREJ = INTREJ+1
307 if ( obsVarno == BUFR_NESS ) INDREJ = INDREJ+1
308 end if
309 end if
310
311 if ( obsFlag == 1 ) then
312 call obs_bodySet_i( obsData, OBS_FLG, bodyIndex, ibset( obs_bodyElem_i( obsData, OBS_FLG, bodyIndex ), 13 ))
313 else if ( obsFlag == 2 ) then
314 call obs_bodySet_i( obsData, OBS_FLG, bodyIndex, ibset( obs_bodyElem_i( obsData, OBS_FLG, bodyIndex ), 14 ))
315 call obs_bodySet_i( obsData, OBS_FLG, bodyIndex, ibset( obs_bodyElem_i( obsData, OBS_FLG, bodyIndex ), 16 ))
316 call obs_bodySet_i( obsData, OBS_FLG, bodyIndex, ibset( obs_bodyElem_i( obsData, OBS_FLG, bodyIndex ), 09 ))
317 call obs_headSet_i( obsData, OBS_ST1, headerIndex, ibset( obs_headElem_i( obsData, OBS_ST1, headerIndex ), 06 ))
318
319 else if ( obsFlag == 3 ) then
320 call obs_bodySet_i( obsData, OBS_FLG, bodyIndex, ibset( obs_bodyElem_i( obsData, OBS_FLG, bodyIndex), 15 ))
321 call obs_bodySet_i( obsData, OBS_FLG, bodyIndex, ibset( obs_bodyElem_i( obsData, OBS_FLG, bodyIndex), 16 ))
322 call obs_bodySet_i( obsData, OBS_FLG, bodyIndex, ibset( obs_bodyElem_i( obsData, OBS_FLG, bodyIndex), 09 ))
323 call obs_headSet_i( obsData, OBS_ST1, headerIndex, ibset( obs_headElem_i( obsData, OBS_ST1, headerIndex), 06 ))
324 end if
325 end if
326 end do BODY
327
328124 FORMAT(2x,a9,1x,f6.2,1x,f7.2,1x,I3,1x,I5,7(2x,G11.2),I3 )
329122 FORMAT(2x,a9,1x,f6.2,1x,f7.2,1x,I3,1x,I5,7(2x,F11.2),I3 )
330
331 end do HEADER
332
333 else !IF (.not. new_bgck_sw .or. obsFamily .ne. 'SW') then
334
335 call obs_set_current_body_list( obsData, 'SW' )
336 bodyuv: do
337 bodyIndex = obs_getBodyIndex(obsData)
338 if ( bodyIndex < 0 ) exit bodyuv
339
340 ! Only process pressure level observations flagged to be assimilated
341 i_ass = obs_bodyElem_i ( obsData, OBS_ASS, bodyIndex )
342 i_vco = obs_bodyElem_i ( obsData, OBS_VCO, bodyIndex )
343
344 if( i_ass /= obs_assimilated .or. i_vco /= 2 ) cycle bodyuv
345
346 headerIndex = obs_bodyElem_i( obsData, OBS_HIND, bodyIndex )
347 bodyIndex_start = obs_headElem_i( obsData, OBS_RLN, headerIndex )
348
349 obsVarno = obs_bodyElem_i( obsData, OBS_VNM, bodyIndex )
350 zlev = obs_bodyElem_r( obsData, OBS_PPP, bodyIndex )
351
352 found_u = .false.
353 found_v = .false.
354
355 if ( obsVarno == BUFR_NEUU ) then
356
357 bodyIndex_u = bodyIndex
358 found_u = .true.
359
360 do i_oth = bodyIndex_start, bodyIndex
361 obsVarno = obs_bodyElem_i( obsData, OBS_VNM, i_oth )
362 zslev = obs_bodyElem_r( obsData, OBS_PPP, i_oth )
363 if ( obsVarno == BUFR_NEVV .and. zslev == zlev ) then
364 bodyIndex_v = i_oth
365 found_v = .true.
366 end if
367 end do
368
369 else
370
371 bodyIndex_v = bodyIndex
372 found_v = .true.
373
374 do i_oth = bodyIndex_start, bodyIndex
375 obsVarno = obs_bodyElem_i( obsData, OBS_VNM, i_oth )
376 zslev = obs_bodyElem_r( obsData, OBS_PPP, i_oth )
377 if ( obsVarno == BUFR_NEUU .and. zslev == zlev ) then
378 bodyIndex_u = i_oth
379 found_u = .true.
380 end if
381 end do
382
383 end if
384
385 if ( found_u .and. found_v ) then
386
387 uu_d = obs_bodyElem_r( obsData, OBS_OMP, bodyIndex_u )
388 vv_d = obs_bodyElem_r( obsData, OBS_OMP, bodyIndex_v )
389 uu_r = obs_bodyElem_r( obsData, OBS_OER, bodyIndex_u )
390 vv_r = obs_bodyElem_r( obsData, OBS_OER, bodyIndex_v )
391 uu_f = obs_bodyElem_r( obsData, OBS_HPHT, bodyIndex_u )
392 vv_f = obs_bodyElem_r( obsData, OBS_HPHT, bodyIndex_v )
393
394 duv2 = uu_d**2 + vv_d**2
395
396 obsFlag = 0
397 duv2_lim = (uu_r**2 + uu_f**2 + vv_r**2 + vv_f**2)*1
398 if (duv2 > duv2_lim) then
399 obsFlag = 1
400 end if
401 duv2_lim = (uu_r**2 + uu_f**2 + vv_r**2 + vv_f**2)*2
402 if(duv2 > duv2_lim) then
403 obsFlag = 2
404 end if
405 duv2_lim = (uu_r**2 + uu_f**2 + vv_r**2 + vv_f**2)*4
406 if(duv2 > duv2_lim) then
407 obsFlag = 3
408 end if
409
410 numberObs = numberObs + 2
411 if ( obsFlag >= 2 ) numberObsRejected = numberObsRejected + 2
412
413 if ( obsFlag == 1 ) then
414 call obs_bodySet_i( obsData,OBS_FLG,bodyIndex_u, ibset( obs_bodyElem_i( obsData, OBS_FLG, bodyIndex_u ), 13 ))
415 call obs_bodySet_i( obsData,OBS_FLG,bodyIndex_v, ibset( obs_bodyElem_i( obsData, OBS_FLG, bodyIndex_v ), 13 ))
416
417 else if ( obsFlag == 2 ) then
418 call obs_bodySet_i( obsData, OBS_FLG, bodyIndex_u, ibset( obs_bodyElem_i( obsData, OBS_FLG, bodyIndex_u ), 14 ))
419 call obs_bodySet_i( obsData, OBS_FLG, bodyIndex_u, ibset( obs_bodyElem_i( obsData, OBS_FLG, bodyIndex_u ), 16 ))
420 call obs_bodySet_i( obsData, OBS_FLG, bodyIndex_u, ibset( obs_bodyElem_i( obsData, OBS_FLG, bodyIndex_u ), 09 ))
421 call obs_bodySet_i( obsData, OBS_FLG, bodyIndex_v, ibset( obs_bodyElem_i( obsData, OBS_FLG, bodyIndex_v ), 14 ))
422 call obs_bodySet_i( obsData, OBS_FLG, bodyIndex_v, ibset( obs_bodyElem_i( obsData, OBS_FLG, bodyIndex_v ), 16 ))
423 call obs_bodySet_i( obsData, OBS_FLG, bodyIndex_v, ibset( obs_bodyElem_i( obsData, OBS_FLG, bodyIndex_v ), 09 ))
424 call obs_headSet_i( obsData, OBS_ST1, headerIndex, ibset( obs_headElem_i( obsData, OBS_ST1, headerIndex ), 06 ))
425
426 else if ( obsFlag == 3 ) then
427 call obs_bodySet_i( obsData, OBS_FLG, bodyIndex_u, ibset( obs_bodyElem_i( obsData, OBS_FLG, bodyIndex_u ), 15 ))
428 call obs_bodySet_i( obsData, OBS_FLG, bodyIndex_u, ibset( obs_bodyElem_i( obsData, OBS_FLG, bodyIndex_u ), 16 ))
429 call obs_bodySet_i( obsData, OBS_FLG, bodyIndex_u, ibset( obs_bodyElem_i( obsData, OBS_FLG, bodyIndex_u ), 09 ))
430 call obs_bodySet_i( obsData, OBS_FLG, bodyIndex_v, ibset( obs_bodyElem_i( obsData, OBS_FLG, bodyIndex_v ), 15 ))
431 call obs_bodySet_i( obsData, OBS_FLG, bodyIndex_v, ibset( obs_bodyElem_i( obsData, OBS_FLG, bodyIndex_v ), 16 ))
432 call obs_bodySet_i( obsData, OBS_FLG, bodyIndex_v, ibset( obs_bodyElem_i( obsData, OBS_FLG, bodyIndex_v ), 09 ))
433 call obs_headSet_i( obsData, OBS_ST1, headerIndex, ibset( obs_headElem_i( obsData, OBS_ST1, headerIndex ), 06 ))
434 end if
435
436 end if !if(found_u .and. found_v)
437
438 end do bodyuv
439
440 end if !IF (.not. new_bgck_sw .or. obsFamily .ne. 'SW')
441
442 if ( numberObs > 0 ) then
443 write(*,*)' '
444 write(*,*) myName//': FINISHED BGCHECK OF ', obsFamily, ' DATA'
445 write(*,123) myName//': ', numberObsRejected, ' OBSERVATIONS REJECTED OUT OF ', numberObs
446 write(*,*)' '
447 end if
448
449 if ( numberObs > 0 .and. obsFamily == 'GP' ) then
450 write(*,*)' '
451 write(*,*) ' BGCDATA: REPORT FOR GP FAMILY OF OBSERVATIONS'
452 write(*,123) 'BGCDATA: ',INZREJ, ' ZTD OBSERVATIONS REJECTED OUT OF ', INZOBS
453 write(*,123) 'BGCDATA: ',INPREJ, ' PSFC OBSERVATIONS REJECTED OUT OF ', INPOBS
454 write(*,123) 'BGCDATA: ',INTREJ, ' TSFC OBSERVATIONS REJECTED OUT OF ', INTOBS
455 write(*,123) 'BGCDATA: ',INDREJ, ' DPDS OBSERVATIONS REJECTED OUT OF ', INDOBS
456 write(*,*)' '
457 end if
458
459123 FORMAT(2X,A,I0,A,I0)
460
461 write(*,*)' '
462 write(*,*)' ---------------------------'
463 write(*,*) myName//' DONE '
464 write(*,*)' ---------------------------'
465 write(*,*)' '
466
467 if ( obsCount > 0) then
468 write(*,*) myName//': obsCount: ', obsCount,'; mean(FGE): ', averageFGE / obsCount
469 write(*,*) myName//': obsCount: ', obsCount,'; mean(OER): ', averageOER / obsCount
470 end if
471
472 end subroutine bgck_data
473
474 !--------------------------------------------------------------------------
475 ! bgck_gpsro
476 !--------------------------------------------------------------------------
477 subroutine bgck_gpsro(columnTrlOnTrlLev,obsData)
478 !
479 !:Purpose: Set background-check flag on GPSRO data if ABS(O-P)/P is too
480 ! large
481 !
482 implicit none
483
484 ! Arguments:
485 type(struct_columnData), intent(in) :: columnTrlOnTrlLev
486 type(struct_obs), intent(inout) :: obsData
487
488 ! Locals:
489 type(struct_vco), pointer :: vco_trl
490 real(8) :: HNH1, ZOBS, ZMHX, ZOMF, ZREF, ZOER, Rad
491 integer :: headerIndex
492 integer :: IDATYP, iProfile, varNum
493 integer :: IDATA , IDATEND, bodyIndex
494 integer :: NGPSLEV
495 integer :: iversion
496
497 vco_trl => col_getVco(columnTrlOnTrlLev)
498 iversion = vco_trl%vCode
499
500 write(*,*)'ENTER BGCSGPSRO'
501
502 ! 1. Initializations
503 ! ---------------
504
505 NGPSLEV=col_getNumLev(columnTrlOnTrlLev,'TH')
506
507 ! Loop over all files
508
509 ! loop over all header indices of the 'RO' family
510 call obs_set_current_header_list( obsData, 'RO' )
511 HEADER: do
512 headerIndex = obs_getHeaderIndex(obsData)
513 if (headerIndex < 0) exit HEADER
514
515 ! Process only refractivity data (codtyp 169)
516
517 IDATYP = obs_headElem_i(obsData,OBS_ITY,headerIndex)
518 IF ( IDATYP == 169 ) THEN
519 iProfile = gps_iprofile_from_index(headerIndex)
520 varNum = gps_vRO_IndexPrf(iProfile, 2)
521
522 ! Basic geometric variables of the profile
523
524 Rad = obs_headElem_r(obsData,OBS_TRAD,headerIndex)
525
526 ! Loops over data in the observation
527
528 IDATA = obs_headElem_i(obsData,OBS_RLN,headerIndex)
529 IDATEND = obs_headElem_i(obsData,OBS_NLV,headerIndex) + IDATA - 1
530
531 ! Scan for requested assimilations, and count them
532
533 do bodyIndex= IDATA, IDATEND
534 if ( obs_bodyElem_i( obsData, OBS_ASS, bodyIndex ) == obs_assimilated ) then
535 HNH1 = obs_bodyElem_r( obsData, OBS_PPP, bodyIndex )
536 if ( varNum == bufr_nebd ) HNH1 = HNH1-Rad
537
538 ! Increment OMF = Y - H(x)
539
540 ZOMF = obs_bodyElem_r( obsData, OBS_OMP, bodyIndex )
541
542 ! Observation value Y
543
544 ZOBS = obs_bodyElem_r( obsData, OBS_VAR, bodyIndex )
545 ZOER = obs_bodyElem_r( obsData, OBS_OER, bodyIndex )
546 ZMHX = ZOBS-ZOMF
547
548 ! Reference order of magnitude value:
549
550 if ( varNum == bufr_nebd ) then
551 ZREF = 0.025d0*exp(-HNH1/6500.d0)
552 else
553 if ( .not. gps_roBNorm ) then
554 ZREF = 300.d0*exp(-HNH1/6500.d0)
555 else
556 ZREF = ZMHX
557 end if
558 end if
559
560 ! OMF Tested criteria:
561
562 if ( .not. gps_roBNorm ) then
563 if (DABS(ZOMF)/ZREF > gps_BgckBand .or. DABS(ZOMF)/ZOER > 3.d0) then
564 call obs_bodySet_i(obsData,OBS_FLG,bodyIndex,ibset(obs_bodyElem_i(obsData,OBS_FLG,bodyIndex),16))
565 call obs_bodySet_i(obsData,OBS_FLG,bodyIndex,ibset(obs_bodyElem_i(obsData,OBS_FLG,bodyIndex),9))
566 end if
567 else
568 if ( DABS(ZOMF)/ZREF > gps_BgckBand .or. DABS(ZOMF)/ZOER > gps_roNsigma) then
569 call obs_bodySet_i(obsData,OBS_FLG,bodyIndex,ibset(obs_bodyElem_i(obsData,OBS_FLG,bodyIndex),16))
570 call obs_bodySet_i(obsData,OBS_FLG,bodyIndex,ibset(obs_bodyElem_i(obsData,OBS_FLG,bodyIndex),9))
571 write(*,'(A40,F10.0,3F12.4)') ' REJECT BGCSGPSRO H O P (O-P/ZREF) =',HNH1,ZOBS,ZMHX,(ZOMF)/ZREF
572 end if
573 end if
574
575 end if
576 end do
577 end if
578
579 end do HEADER
580
581 write(*,*)'EXIT BGCSGPSRO'
582 RETURN
583
584 end subroutine bgck_gpsro
585
586 !--------------------------------------------------------------------------
587 ! isetflag
588 !--------------------------------------------------------------------------
589 function isetflag( obsFamily, kodtyp, kvnam, zbgchk )
590 !
591 !:Purpose: Set BACKGROUND-CHECK FLAGS According to values set in a table.
592 ! Original values in table come from ecmwf.
593 !
594 implicit none
595
596 ! Arguments:
597 character(len=2), intent(in) :: obsFamily ! FAMILY NAME ( 'UA' , 'AI' ...etc.. )
598 integer, intent(in) :: kodtyp ! BURP CODE TYPE
599 integer, intent(in) :: kvnam ! VARIABLE NAME ( BURP )
600 real(8), intent(in) :: zbgchk ! NORMALIZED BACKGROUND DEPARTURE
601 ! Result:
602 integer :: isetflag
603
604 ! Locals:
605 real(8), parameter :: zsacrit(3) = (/ 10.00D0, 20.00D0, 30.00D0 /)
606 real(8), parameter :: zttcrit(3) = (/ 9.00D0, 16.00D0, 25.00D0 /)
607 real(8), parameter :: zalcrit(3) = (/ 10.00D0, 20.00D0, 30.00D0 /)
608 real(8), parameter :: zescrit(3) = (/ 10.00D0, 20.00D0, 30.00D0 /)
609 real(8), parameter :: zpscrit(3) = (/ 9.00D0, 16.00D0, 25.00D0 /)
610 real(8), parameter :: zpncrit(3) = (/ 10.00D0, 20.00D0, 30.00D0 /)
611 real(8), parameter :: zswcrit(3) = (/ 10.00D0, 20.00D0, 30.00D0 /)
612 real(8), parameter :: ztscrit(3) = (/ 5.00D0, 25.00D0, 30.00D0 /)
613 real(8), parameter :: zdzcrit(3) = (/ 2.25D0, 5.06D0, 7.56D0 /)
614 real(8), parameter :: zgzcrit(3) = (/ 12.25D0, 25.00D0, 36.00D0 /)
615 real(8), parameter :: zzdcrit(3) = (/ 9.00D0, 16.00D0, 25.00D0 /)
616 real(8), parameter :: zchcrit(3) = (/ 9.00D0, 16.00D0, 25.00D0 /)
617 real(8), parameter :: zLogViscrit(3) = (/ 10.00D0, 20.00D0, 30.00D0 /)
618 ! Temporary hardcoded values for radar Doppler velocity
619 real(8), parameter :: radvelcrit(3) = (/ 8.00D0, 20.00D0, 30.00D0 /)
620 !real(8) :: zuvcrit(3) = (/ 10.00D0, 20.00D0, 30.00D0 /)
621 real(8) :: zuvcrit(3)
622
623 zuvcrit(1) = 10.00D0
624 zuvcrit(3) = 30.00D0
625 if ( kodtyp == 37 ) then
626 zuvcrit(2)=25.00D0
627 else
628 zuvcrit(2)=20.00D0
629 end if
630
631 isetflag=0
632
633 if ( kvnam == BUFR_NEGZ ) then
634
635 ! SET FLAG FOR HEIGHTS
636
637 if ( zbgchk >= zgzcrit(1) .and. zbgchk < zgzcrit(2) ) then
638 isetflag=1
639 else if ( zbgchk >= zgzcrit(2) .and. zbgchk < zgzcrit(3) ) then
640 isetflag=2
641 else if ( zbgchk >= zgzcrit(3) )then
642 isetflag =3
643 end if
644
645 else if ( kvnam == BUFR_NETT ) then
646
647 ! SET FLAG FOR TEMPERATURE
648
649 if ( zbgchk >= zttcrit(1) .and. zbgchk < zttcrit(2) ) then
650 isetflag=1
651 else if ( zbgchk >= zttcrit(2) .and. zbgchk < zttcrit(3) ) then
652 isetflag=2
653 else if ( zbgchk >= zttcrit(3) )then
654 isetflag =3
655 end if
656
657 else if ( kvnam == BUFR_NEDZ ) then
658
659 ! SET FLAG FOR SATEMS
660
661 if ( zbgchk >= zdzcrit(1) .and. zbgchk < zdzcrit(2) ) then
662 isetflag=1
663 else if ( zbgchk >= zdzcrit(2) .and. zbgchk < zdzcrit(3) ) then
664 isetflag=2
665 else if ( zbgchk >= zdzcrit(3) )then
666 isetflag =3
667 end if
668
669 else if ( kvnam == BUFR_NEFS ) then
670
671 ! SET FLAG FOR WIND SPEED
672
673 if ( zbgchk >= zsacrit(1) .and. zbgchk < zsacrit(2) ) then
674 isetflag=1
675 else if ( zbgchk >= zsacrit(2) .and. zbgchk < zsacrit(3) ) then
676 isetflag=2
677 else if ( zbgchk >= zsacrit(3) )then
678 isetflag =3
679 end if
680
681 else if ( kvnam == BUFR_NEUU .or. kvnam == BUFR_NEVV ) then
682
683 ! SET FLAG FOR WIND COMPONENTS
684
685 if ( zbgchk >= zuvcrit(1) .and. zbgchk < zuvcrit(2) ) then
686 isetflag=1
687 else if ( zbgchk >= zuvcrit(2) .and. zbgchk < zuvcrit(3) ) then
688 isetflag=2
689 else if ( zbgchk >= zuvcrit(3) )then
690 isetflag =3
691 end if
692
693 else if ( kvnam == BUFR_NEAL ) then
694
695 ! SET FLAG FOR ALADIN HLOS WIND OBSERVATIONS
696
697 if ( zbgchk >= zalcrit(1) .and. zbgchk < zalcrit(2) ) then
698 isetflag=1
699 else if ( zbgchk >= zalcrit(2) .and. zbgchk < zalcrit(3) ) then
700 isetflag=2
701 else if ( zbgchk >= zalcrit(3) )then
702 isetflag=3
703 end if
704
705 else if ( kvnam == BUFR_NEUS .or. kvnam == BUFR_NEVS ) then
706
707 ! SET FLAG FOR SURFACE WIND COMPONENTS
708
709 if ( zbgchk >= zswcrit(1) .and. zbgchk < zswcrit(2) ) then
710 isetflag=1
711 else if ( zbgchk >= zswcrit(2) .and. zbgchk < zswcrit(3) ) then
712 isetflag=2
713 else if ( zbgchk >= zswcrit(3) )then
714 isetflag =3
715 end if
716
717 else if ( kvnam == bufr_gust ) then
718
719 ! SET FLAG FOR SURFACE WIND GUST
720
721 if ( zbgchk >= zswcrit(1) .and. zbgchk < zswcrit(2) ) then
722 isetflag=1
723 else if ( zbgchk >= zswcrit(2) .and. zbgchk < zswcrit(3) ) then
724 isetflag=2
725 else if ( zbgchk >= zswcrit(3) )then
726 isetflag =3
727 end if
728
729 else if ( kvnam == bufr_nees ) then
730
731 ! SET FLAG FOR DEW POINT DEPRESSION
732
733 if ( zbgchk >= zescrit(1) .and. zbgchk < zescrit(2) ) then
734 isetflag=1
735 else if ( zbgchk >= zescrit(2) .and. zbgchk < zescrit(3) ) then
736 isetflag=2
737 else if ( zbgchk >= zescrit(3) )then
738 isetflag =3
739 end if
740
741 else if ( kvnam == bufr_neps ) then
742
743 ! SET FLAG FOR SURFACE PRESSURE
744
745 if ( zbgchk >= zpscrit(1) .and. zbgchk < zpscrit(2) ) then
746 isetflag=1
747 else if ( zbgchk >= zpscrit(2) .and. zbgchk < zpscrit(3) ) then
748 isetflag=2
749 else if ( zbgchk >= zpscrit(3) )then
750 isetflag =3
751 end if
752
753 else if ( kvnam == bufr_nepn ) then
754
755 ! SET FLAG FOR MEAN SEA LEVEL PRESSURE
756
757 if ( zbgchk >= zpncrit(1) .and. zbgchk < zpncrit(2) ) then
758 isetflag=1
759 else if ( zbgchk >= zpncrit(2) .and. zbgchk < zpncrit(3) ) then
760 isetflag=2
761 else if ( zbgchk >= zpncrit(3) ) then
762 isetflag =3
763 end if
764
765 else if ( kvnam == bufr_nets ) then
766
767 ! SET FLAG FOR SURFACE TEMPERATURE
768
769 if ( zbgchk >= ztscrit(1) .and. zbgchk < ztscrit(2) ) then
770 isetflag=1
771 else if ( zbgchk >= ztscrit(2) .and. zbgchk < ztscrit(3) ) then
772 isetflag=2
773 else if ( zbgchk >= ztscrit(3) ) then
774 isetflag =3
775 end if
776
777 else if ( kvnam == BUFR_NESS ) then
778
779 ! SET FLAG FOR SURFACE DEW POINT DEPRESSION
780
781 if ( zbgchk >= zescrit(1) .and. zbgchk < zescrit(2) ) then
782 isetflag=1
783 else if ( zbgchk >= zescrit(2) .and. zbgchk < zescrit(3) ) then
784 isetflag=2
785 else if ( zbgchk >= zescrit(3) ) then
786 isetflag =3
787 end if
788
789 else if ( kvnam == bufr_vis ) then
790
791 ! SET FLAG FOR VISIBILITY
792
793 if ( zbgchk >= zLogViscrit(1) .and. zbgchk < zLogViscrit(2) ) then
794 isetflag=1
795 else if ( zbgchk >= zLogViscrit(2) .and. zbgchk < zLogViscrit(3) ) then
796 isetflag=2
797 else if ( zbgchk >= zLogViscrit(3) ) then
798 isetflag =3
799 end if
800
801 else if ( kvnam == bufr_nezd ) then
802
803 ! SET FLAG FOR GB-GPS ZENITH DELAY
804
805 if ( zbgchk >= zzdcrit(1) .and. zbgchk < zzdcrit(2) ) then
806 isetflag=1
807 else if ( zbgchk >= zzdcrit(2) .and. zbgchk < zzdcrit(3) ) then
808 isetflag=2
809 else if ( zbgchk >= zzdcrit(3) ) then
810 isetflag =3
811 end if
812
813 else if ( kvnam == bufr_radvel ) then
814
815 ! Set flag for Doppler Velocity (Radvel)
816 if ( zbgchk >= radvelcrit(1) .and. zbgchk < radvelcrit(2) ) then
817 isetflag = 1
818 else if ( zbgchk >= radvelcrit(2) .and. zbgchk < radvelcrit(3) ) then
819 isetflag = 2
820 else if ( zbgchk >= radvelcrit(3) ) then
821 isetflag = 3
822 end if
823
824 else if ( obsFamily == 'CH' ) then
825
826 ! SET FLAG FOR CHEMICAL CONSTITUENTS
827 if ( zbgchk >= zchcrit(1) .and. zbgchk < zchcrit(2) ) then
828 isetflag=1
829 else if ( zbgchk >= zchcrit(2) .and. zbgchk < zchcrit(3) ) then
830 isetflag=2
831 else if ( zbgchk >= zchcrit(3) ) then
832 isetflag =3
833 end if
834
835 end if
836
837 return
838
839 end function isetflag
840
841end module backgroundCheck_mod