1module obsSpaceErrorStdDev_mod
2 ! MODULE obsSpaceErrorStdDev_mod (prefix='ose' category='1. High-level functionality')
3 !
4 !:Purpose: Contains subroutines for computing background-error and OmP-error
5 ! standard deviations in observation space
6 !
7 use midasMpi_mod
8 use obsSpaceData_mod
9 use columnData_mod
10 use bufr_mod
11 use utilities_mod
12 use earthConstants_mod
13 use MathPhysConstants_mod
14 use stateToColumn_mod
15 use gridStateVector_mod
16 use verticalCoord_mod
17 use horizontalCoord_mod
18 use bmatrixhi_mod
19 use obsOperators_mod
20 use gps_mod
21 use codtyp_mod
22 use bCovarSetupChem_mod
23 use timeCoord_mod
24 use obsTimeInterp_mod
25 use bMatrixEnsemble_mod
26 use varNameList_mod
27 use obsOperatorsChem_mod
28 use obsFamilyList_mod
29 use calcHeightAndPressure_mod
30
31 implicit none
32 private
33
34 ! public procedures
35 public :: ose_computeStddev
36
37 ! module structures
38 ! -----------------
39
40 type :: struct_OmPStdDevCH
41 !
42 ! Structure containing information retrieved from auxiliary file for holding
43 ! OmP std dev information
44 !
45 ! Variable Description
46 ! -------- -----------
47 ! n_stnid Number of sub-families (identified via STNIDs)
48 ! stnids Sub-families (STNIDs; * are wild cards)
49 ! element BUFR element in data block
50 ! source 0: Set entirely from the auxiliary file being read
51 ! as a function latitude, vertical level, and month.
52 ! 1: Values to be calculated from OmP differences
53 ! (requires a large data set size for each assim)
54 ! using read in latitudes and vertical levels
55 ! 2: Values to be calculated from OBS_OER and estimated
56 ! OBS_HPHT (default in absence of stnid and element)
57 ! std_type Index of std dev being read for source=0 or calculated for source=1
58 ! 0: absolute value
59 ! 1: fraction of measurement value (% / 100)
60 ! ibegin Position index of start of data for given
61 ! sub-family in the arrays OmPstd,levels,lat,month
62 ! n_lvl Number of vertical levels (max number when source=2)
63 ! levels Vertical levels (in coordinate of sub-family data)
64 ! n_lat Number of latitudes
65 ! lat Latitudes (degrees; ordered in increasing size)
66 ! n_month Number of months (requires n_lat>1 to be >1)
67 ! month Months numbered between 1 and 12.
68 ! std OmP error std dev (or fraction)
69
70 integer :: n_stnid
71 character(len=12), allocatable :: stnids(:)
72 integer, allocatable :: element(:),n_lat(:),n_month(:),std_type(:)
73 integer, allocatable :: source(:),ibegin(:),n_lvl(:)
74 real(8), allocatable :: std(:)
75 real(8), allocatable :: levels(:),lat(:),month(:)
76
77 end type struct_OmPStdDevCH
78
79 type(struct_OmPStdDevCH) :: OmPstdCH
80 type(struct_hco), pointer :: hco_anl => null()
81 real*8 , allocatable :: ose_vRO_Jacobian(:,:,:)
82 logical, allocatable :: ose_vRO_lJac(:)
83
84 contains
85
86 !--------------------------------------------------------------------------
87 ! ose_computeStddev
88 !--------------------------------------------------------------------------
89 subroutine ose_computeStddev(columnTrlOnAnlIncLev,hco_anl_in,obsSpaceData)
90 !
91 !:Purpose: To set OmP-error std dev when possible. Otherwise
92 ! compute background-error stddev in observation space to
93 ! estimate OmP-error std dev.
94 !
95 implicit none
96
97 ! Arguments:
98 type(struct_columnData), intent(inout) :: columnTrlOnAnlIncLev ! Background columns on anl levels, obs horiz locations
99 type(struct_hco), pointer, intent(in) :: hco_anl_in
100 type(struct_obs), intent(inout) :: obsSpaceData ! Observation-related data
101
102 ! Locals:
103 real(8) :: HBHT_static, HBHT_ensemble, HBHT_hybrid
104 logical :: staticHBHT = .false.
105 logical :: staticOMPE = .false.
106 logical :: staticHBHT_ch = .false.
107 logical :: staticOMPE_ch = .false.
108 logical :: ensemble = .false.
109 integer :: index_body
110 integer :: fnom, fclos, ierr, nulnam
111
112 ! Namelist variables:
113 character(len=12) :: hybrid_mode ! can be 'WEIGHTED_SUM' or 'MAX_VALUE'
114 NAMELIST /NAMHBHT/hybrid_mode
115
116 ! set the module variable hco_anl
117 hco_anl => hco_anl_in
118
119 ! return if there is no observation.
120 if ( obs_numheader(obsSpaceData) == 0 ) return
121
122 !- 1. Compute HBHT (sigma_b in observation space) or OmP error std dev
123
124 !- 1.1 Compute error std dev from static statistics
125 ! OmP error std dev (OBS_OMPE) when possible and required.
126 ! Otherwise, compute HBHT
127 ! obsSpaceData - INOUT ( OmP error std dev outputted in OBS_OMPE or/and
128 ! sqrt(diag(H*B*H^T)) with B_static_chm outputted in OBS_HPHT )
129
130 call ose_setStaticErrorStddev( columnTrlOnAnlIncLev, obsSpaceData, staticHBHT, staticHBHT_ch, staticOMPE_ch )
131
132 !- 1.2 HBHT from the Bens
133 ! obsSpaceData - INOUT (HBensHT std. dev. outputted in OBS_WORK)
134
135 call ose_compute_hbht_ensemble( columnTrlOnAnlIncLev, &
136 obsSpaceData, &
137 ensemble )
138
139 if ( .not. staticHBHT .and. .not. staticOMPE .and. .not. ensemble .and. &
140 .not. staticHBHT_ch .and. .not. staticOMPE_ch ) &
141 call utl_abort('ose_computeStddev: no OmP std dev or sqrt(HBHT) was initialized')
142
143 !- 2. Select/Blend HBHT.
144
145 if ( staticHBHT .and. .not. ensemble ) then
146 ! Bnmc only
147 write(*,*)
148 write(*,*) 'ose_computeStddev: Using B_static ONLY'
149 ! HBnmcHT std. dev. already in OBS_HPHT
150 else if ( .not. staticHBHT .and. ensemble ) then
151 write(*,*)
152 write(*,*) 'ose_computeStddev: Using B_ensemble ONLY'
153 ! Transfer HBensHT std. dev. values in OBS_WORK to OBS_HPHT
154 do index_body = 1, obs_numBody(obsSpaceData)
155 HBHT_ensemble = obs_bodyElem_r(obsSpaceData,OBS_WORK,index_body)
156 call obs_bodySet_r(obsSpaceData,OBS_HPHT,index_body, HBHT_ensemble)
157 end do
158 else if ( staticHBHT .and. ensemble ) then
159 ! Read Namelist first
160 hybrid_mode = 'WEIGHTED_SUM' ! default value
161 nulnam = 0
162 ierr = fnom(nulnam,'./flnml','FTN+SEQ+R/O',0)
163 read(nulnam,nml=namhbht,iostat=ierr)
164 if ( ierr /= 0) call utl_abort('ose_computeStddev: Error reading namelist')
165 if ( mmpi_myid == 0 ) write(*,nml=namhbht)
166 ierr = fclos(nulnam)
167
168 write(*,*)
169 write(*,*) 'ose_computeStddev: Using hybrid approach (blend of B_static and B_ensemble) in mode = ', trim(hybrid_mode)
170
171 do index_body = 1, obs_numBody(obsSpaceData)
172 HBHT_static = obs_bodyElem_r(obsSpaceData,OBS_HPHT,index_body)
173 HBHT_ensemble = obs_bodyElem_r(obsSpaceData,OBS_WORK,index_body)
174 if ( HBHT_static <= 0.0d0 ) then
175 call obs_bodySet_r(obsSpaceData,OBS_HPHT,index_body, HBHT_ensemble)
176 else
177 select case ( trim(hybrid_mode) )
178 case ('WEIGHTED_SUM')
179 HBHT_hybrid = sqrt(HBHT_static**2 + HBHT_ensemble**2)
180 case ('MAX_VALUE')
181 HBHT_hybrid = max(HBHT_static,HBHT_ensemble)
182 case default
183 write(*,*)
184 write(*,*) 'ose_computeStddev: Unknown hybrid_mode ', trim(hybrid_mode)
185 call utl_abort('ose_compute_HBHT')
186 end select
187 call obs_bodySet_r(obsSpaceData,OBS_HPHT,index_body, HBHT_hybrid)
188 end if
189 end do
190
191 end if
192
193 end subroutine ose_computeStddev
194
195 !--------------------------------------------------------------------------
196 ! ose_setStaticErrorStddev
197 !--------------------------------------------------------------------------
198 subroutine ose_setStaticErrorStddev( columnTrlOnAnlIncLev, obsSpaceData, statusHBHT, statusHBHT_ch, statusOMPE_ch )
199 !
200 !:Purpose: To assign or compute the OmP error standard deviations in
201 ! observation space where requested. If not possible or available,
202 ! compute background-error standard deviation.
203 !
204 !:Note: OmP error std dev assigment currently only available for the CH obs family.
205 !
206 !-------------------------------------------------------------------------
207 implicit none
208
209 ! Arguments:
210 type(struct_columnData), intent(inout) :: columnTrlOnAnlIncLev
211 type(struct_obs), intent(inout) :: obsSpaceData ! observation-space data, output saved in OBS_HPHT column
212 logical, intent(inout) :: statusHBHT
213 logical, intent(inout) :: statusHBHT_ch
214 logical, intent(inout) :: statusOMPE_ch
215
216 ! Locals:
217 integer :: famIndex
218 character(len=4), allocatable :: availableOMPE(:)
219
220 allocate(availableOMPE(ofl_numFamily))
221 availableOMPE(:) = ' '
222
223 ! Assignment of OBS_OMPE in obsSpaceData according to obs family where possible and required
224
225 do famIndex=1,ofl_numFamily
226 if ( .not. obs_famExist(obsSpaceData,ofl_familyList(famIndex),localMPI_opt=.true.) ) cycle
227
228 if ( ofl_familyList(famIndex) == 'CH' ) then
229 write(*,*)
230 write(*,*) 'ose_setStaticErrorStddev: Setting of OmP error std dev begins for family ',ofl_familyList(famIndex)
231 availableOMPE(famIndex) = ose_setOmPstddevCH(obsSpaceData)
232 else
233 ! Not available
234 availableOMPE(famIndex) = 'None'
235 end if
236 if ( trim(availableOMPE(famIndex)) == 'Some' .or. &
237 trim(availableOMPE(famIndex)) == 'All' ) statusOMPE_ch = .true.
238
239 if ( trim(availableOMPE(famIndex)) == '' ) then
240 write(*,*) 'ose_setStaticErrorStddev: No ',ofl_familyList(famIndex),' obs. Setting of error std dev not required.'
241 else if ( trim(availableOMPE(famIndex)) == 'None' ) then
242 if ( ofl_familyList(famIndex) == 'CH' ) then
243 write(*,*) 'ose_setStaticErrorStddev: Setting of ',ofl_familyList(famIndex),' OmP error std dev to be estimated via HBHT calc for all obs'
244 end if
245 else if ( trim(availableOMPE(famIndex)) == 'Some' ) then
246 write(*,*) 'ose_setStaticErrorStddev: Setting of ',ofl_familyList(famIndex),' OmP error std dev partially completed (some HBHT calc needed to complete)'
247 else
248 write(*,*) 'ose_setStaticErrorStddev: Setting of ',ofl_familyList(famIndex),' OmP error std dev completed (no HBHT calc needed)'
249 end if
250
251 end do
252
253 ! Computation of background-error standard deviation for obs families or groups of families when required
254
255 ! HBHT from the Bnmc matrix for weather
256 ! obsSpaceData - INOUT (HBnmcHT std. dev. output in OBS_HPHT)
257
258 if ( any(ofl_familyList /= 'CH' .and. ofl_familyList /= 'TO' .and. &
259 ( availableOMPE == 'Some' .or. availableOMPE == 'None' ) ) ) &
260 call ose_compute_hbht_static( columnTrlOnAnlIncLev, obsSpaceData, statusHBHT )
261
262 ! HBHT from the B matrix for constituents
263
264 if ( any(ofl_familyList == 'CH' .and. ( availableOMPE == 'Some' .or. availableOMPE == 'None' ) ) ) &
265 call ose_compute_hbht_static_chem( columnTrlOnAnlIncLev, obsSpaceData, statusHBHT_ch )
266
267 deallocate(availableOMPE)
268
269 end subroutine ose_setStaticErrorStddev
270
271 !--------------------------------------------------------------------------
272 ! ose_compute_hbht_static
273 !--------------------------------------------------------------------------
274 subroutine ose_compute_hbht_static(columnTrlOnAnlIncLev,lobsSpaceData,active)
275 !
276 !:Purpose: To compute background-error stddev in observation space using
277 ! fixed statistics specific in stats file.
278 !
279 implicit none
280
281 ! Arguments:
282 type(struct_obs), intent(inout) :: lobsSpaceData
283 type(struct_columnData), intent(in) :: columnTrlOnAnlIncLev
284 logical, intent(out) :: active
285
286 ! Locals:
287 type(struct_vco), pointer :: vco_anl
288 type(struct_columnData) :: column
289 type(struct_gsv) :: statevector
290 INTEGER JLAT, JLON, JLEV, JOBS
291 CHARACTER*12 CLETIKET
292 CHARACTER*2 CLTYPVAR
293 CHARACTER*1 CLGRTYP
294 CHARACTER*4 CLNOMVAR
295 INTEGER IULSSF,IDATEO
296 INTEGER FSTPRM,FNOM,FSTOUV
297 INTEGER IKEY,IERR,IDATE
298 REAL*8, allocatable :: ZBUFFER(:,:)
299 real*8, pointer :: height_column(:), tt_column(:), field_ptr(:,:,:)
300 INTEGER INI,INJ,INK, INPAS, INBITS, IDATYP, IDEET
301 INTEGER IP1,IP2,IP3,IG1,IG2,IG3,IG4,ISWA,ILENGTH,IDLTF
302 INTEGER IUBC,IEXTR1,IEXTR2,IEXTR3
303 integer :: nLev_M,nLev_T,shift_level,Vcode_anl
304 integer :: cvdim
305 real(8), allocatable :: scaleFactor(:)
306
307 !- Get the appropriate Vertical Coordinate
308 vco_anl => col_getVco(columnTrlOnAnlIncLev)
309
310 ! Note : Here we can use the global B_hi even if we are in LAM mode since,
311 ! in BackgroundCheck mode, the only purpose of bhi_setup is to read
312 ! the scaleFactor and to check the consistency between the vco from
313 ! analysisgrid and cov file
314 call bhi_setup( hco_anl,vco_anl, & ! IN
315 cvdim, & ! OUT
316 mode_opt='BackgroundCheck' ) ! IN
317
318 if ( cvdim > 0 ) then
319 write(*,*)
320 write(*,*) 'Computing HBHT from Bnmc - Start'
321 active = .true.
322 else
323 if ( mmpi_myid == 0 ) write(*,*) 'ose_compute_hbht_static: option NOT ACTIVATED'
324 active = .false.
325 return
326 end if
327
328 nlev_T = col_getNumLev(columnTrlOnAnlIncLev,'TH')
329 nlev_M = col_getNumLev(columnTrlOnAnlIncLev,'MM')
330
331 allocate(scaleFactor(max(nLev_M,nLev_T)))
332 call bhi_getScaleFactor(scaleFactor)
333
334 Vcode_anl = vco_anl%Vcode
335 if ( Vcode_anl == 5001 ) then
336 shift_level = 0
337 else if ( Vcode_anl == 5002) then
338 shift_level = 1
339 else if ( Vcode_anl == 5005 ) then
340 shift_level = 0
341 else
342 write(*,*) 'Vcode_anl = ',Vcode_anl
343 call utl_abort('ose_compute_hbht_static: unknown vertical coordinate type!')
344 end if
345
346 allocate(ZBUFFER(HCO_ANL%NI,HCO_ANL%NJ))
347
348 call gsv_allocate(statevector, 1, hco_anl, vco_anl, &
349 allocHeight_opt=.false., allocPressure_opt=.false.)
350 call gsv_zero(statevector)
351
352 call col_setVco(column,col_getVco(columnTrlOnAnlIncLev))
353 call col_allocate(column,col_getNumCol(columnTrlOnAnlIncLev))
354
355 ! Set the value of OBS_LYR required by setfge routines
356
357 call oop_vobslyrs(columnTrlOnAnlIncLev,lobsSpaceData,beSilent=.false.)
358
359 ! 1. Opening the statistics file
360
361 IULSSF=0
362 IERR=FNOM(iulssf,'./bgcov','RND+OLD+R/O',0)
363 IF ( IERR .EQ. 0 ) THEN
364 write(*,*) 'IBGST - File : ./bgcov'
365 write(*,*) ' opened as unit file ',iulssf
366 ierr = fstouv(iulssf,'RND+OLD')
367 ELSE
368 CALL utl_abort('HBHT_static:NO BACKGROUND STAT FILE!!')
369 ENDIF
370
371 ! 2.1 Background error standard deviations
372
373 CLETIKET = 'BGCK_STDDEV'
374 write(*,*) 'HBHT_static: CLETIKET = ',CLETIKET
375 IDATE = -1
376 IP2 = -1
377 IP3 = -1
378 CLTYPVAR =' '
379
380 ! READ IN STANDARD DEVIATION FOR EACH OBSERVATION TYPE
381
382 clnomvar = 'UU'
383 write(*,*) clnomvar
384 call gsv_getField(statevector,field_ptr,'UU')
385 do jlev = 1, nlev_M
386 ip1 = vco_anl%ip1_M(jlev)
387 ikey = utl_fstlir(zbuffer,iulssf,ini,inj,ink,idate,cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
388 ierr = fstprm(ikey,idateo,ideet,inpas &
389 ,ini,inj,ink, inbits, idatyp &
390 ,ip1,ip2,ip3,cltypvar,clnomvar,cletiket,clgrtyp &
391 ,ig1,ig2,ig3,ig4,iswa,ilength,idltf &
392 ,iubc,iextr1,iextr2,iextr3)
393 if (ini /= hco_anl%ni .or. inj /= hco_anl%nj .or. ink /= 1) then
394 write(*,*)
395 write(*,*) 'HBHT_static: Invalid dimensions for...'
396 write(*,*) 'nomvar =', trim(clnomvar)
397 write(*,*) 'etiket =', trim(cletiket)
398 write(*,*) 'Found ni,nj,nk =', ini, inj, ink
399 write(*,*) 'Should be =', hco_anl%ni, hco_anl%nj, nlev_M
400 call utl_abort('ose_compute_hbht_static')
401 end if
402 do jlat = 1, hco_anl%nj
403 do jlon = 1, hco_anl%ni
404 field_ptr(jlon,jlat,jlev) = scaleFactor(jlev+shift_level)*zbuffer(jlon,jlat)*MPC_M_PER_S_PER_KNOT_R8
405 end do
406 end do
407 end do
408
409 clnomvar = 'VV'
410 write(*,*) clnomvar
411 call gsv_getField(statevector,field_ptr,'VV')
412 do jlev = 1, nlev_M
413 ip1 = vco_anl%ip1_M(jlev)
414 ikey = utl_fstlir(zbuffer,iulssf,ini,inj,ink,idate,cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
415 if (ini /= hco_anl%ni .or. inj /= hco_anl%nj .or. ink /= 1) then
416 write(*,*)
417 write(*,*) 'HBHT_static: Invalid dimensions for...'
418 write(*,*) 'nomvar =', trim(clnomvar)
419 write(*,*) 'etiket =', trim(cletiket)
420 write(*,*) 'Found ni,nj,nk =', ini, inj, ink
421 write(*,*) 'Should be =', hco_anl%ni, hco_anl%nj, nlev_M
422 call utl_abort('ose_compute_hbht_static')
423 end if
424
425 do jlat = 1, hco_anl%nj
426 do jlon = 1, hco_anl%ni
427 field_ptr(jlon,jlat,jlev) = scalefactor(jlev+shift_level)*zbuffer(jlon,jlat)*MPC_M_PER_S_PER_KNOT_R8
428 end do
429 end do
430 end do
431
432 clnomvar = 'ES'
433 write(*,*) clnomvar
434 call gsv_getField(statevector,field_ptr,'HU')
435 do jlev = 1, nlev_T
436 ip1 = vco_anl%ip1_T(jlev)
437 ikey = utl_fstlir(zbuffer,iulssf,ini,inj,ink,idate,cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
438 if (ini /= hco_anl%ni .or. inj /= hco_anl%nj .or. ink /= 1) then
439 write(*,*)
440 write(*,*) 'HBHT_static: Invalid dimensions for...'
441 write(*,*) 'nomvar =', trim(clnomvar)
442 write(*,*) 'etiket =', trim(cletiket)
443 write(*,*) 'Found ni,nj,nk =', ini, inj, ink
444 write(*,*) 'Should be =', hco_anl%ni, hco_anl%nj, nlev_T
445 call utl_abort('ose_compute_hbht_static')
446 end if
447 do jlat = 1, hco_anl%nj
448 do jlon = 1, hco_anl%ni
449 field_ptr(jlon,jlat,jlev) = scaleFactor(jlev)*zbuffer(jlon,jlat)
450 end do
451 end do
452 end do
453
454 ! height is put into TT slot in gridStateVector
455 clnomvar = 'GZ'
456 write(*,*) clnomvar
457 call gsv_getField(statevector,field_ptr,'TT')
458 do jlev = 1, nlev_T
459 ip1 = vco_anl%ip1_T(jlev)
460 ikey = utl_fstlir(zbuffer,iulssf,ini,inj,ink,idate,cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
461 if (ini /= hco_anl%ni .or. inj /= hco_anl%nj .or. ink /= 1) then
462 write(*,*)
463 write(*,*) 'HBHT_static: Invalid dimensions for...'
464 write(*,*) 'nomvar =', trim(clnomvar)
465 write(*,*) 'etiket =', trim(cletiket)
466 write(*,*) 'Found ni,nj,nk =', ini, inj, ink
467 write(*,*) 'Should be =', hco_anl%ni, hco_anl%nj, nlev_T
468 call utl_abort('ose_compute_hbht_static')
469 end if
470 do jlat = 1, hco_anl%nj
471 do jlon = 1, hco_anl%ni
472 field_ptr(jlon,jlat,jlev) = scaleFactor(jlev)*zbuffer(jlon,jlat)*ec_rg*10.d0
473 end do
474 end do
475 end do
476
477 call s2c_bgcheck_bilin(column,statevector,lobsSpaceData)
478
479 ! copy height data from TT to height slot in columnData
480 do jobs= 1, col_getNumCol(column)
481 height_column => col_getColumn(column,jobs,'Z_T')
482 tt_column => col_getColumn(column,jobs,'TT')
483 do jlev = 1,col_getNumLev(column,'TH')
484 height_column(jlev)=tt_column(jlev)
485 enddo
486 enddo
487
488 ! SET THE FIRST-GUESS ERRORS FOR CONVENTIONAL DATA ON PRESSURE LEVELS
489 ! --------------------------------------------------------------------
490
491 call setfgefam('AI',column,columnTrlOnAnlIncLev,lobsSpaceData)
492 call setfgefam('SW',column,columnTrlOnAnlIncLev,lobsSpaceData)
493 call setfgefam('UA',column,columnTrlOnAnlIncLev,lobsSpaceData)
494 call setfgefam('SF',column,columnTrlOnAnlIncLev,lobsSpaceData)
495 call setfgefam('HU',column,columnTrlOnAnlIncLev,lobsSpaceData)
496 call setfgefamz('PR',column,columnTrlOnAnlIncLev,lobsSpaceData)
497 call setfgefamz('AL',column,columnTrlOnAnlIncLev,lobsSpaceData)
498 call setfgefamz('RA',column,columnTrlOnAnlIncLev,lobsSpaceData)
499
500 ! SET THE FIRST-GUESS ERRORS FOR RADIO OCCULTATION DATA
501 ! -----------------------------------------------------
502
503 call setfgedif('RO',columnTrlOnAnlIncLev,lobsSpaceData)
504
505 ! DO TEMPERATURE FIRST-GUESS ERROR
506 ! ---------------------------------
507
508 clnomvar = 'TT'
509 write(*,*) clnomvar
510 call gsv_getField(statevector,field_ptr,'TT')
511 do jlev = 1, nlev_T
512 ip1 = vco_anl%ip1_T(jlev)
513 ikey = utl_fstlir(zbuffer,iulssf,ini,inj,ink,idate,cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
514 if (ini /= hco_anl%ni .or. inj /= hco_anl%nj .or. ink /= 1) then
515 write(*,*)
516 write(*,*) 'HBHT_static: Invalid dimensions for...'
517 write(*,*) 'nomvar =', trim(clnomvar)
518 write(*,*) 'etiket =', trim(cletiket)
519 write(*,*) 'Found ni,nj,nk =', ini, inj, ink
520 write(*,*) 'Should be =', hco_anl%ni, hco_anl%nj, nlev_T
521 call utl_abort('ose_compute_hbht_static')
522 end if
523 do jlat = 1, hco_anl%nj
524 do jlon = 1, hco_anl%ni
525 field_ptr(jlon,jlat,jlev) = scaleFactor(jlev)*zbuffer(jlon,jlat)
526 end do
527 end do
528 end do
529
530 call s2c_bgcheck_bilin(column,statevector,lobsSpaceData)
531 call setfgett(column,columnTrlOnAnlIncLev,lobsSpaceData)
532
533 ! RELOAD DATA TO DO SURFACE FIRST-GUESS ERRORS
534 ! ---------------------------------------------
535
536 clnomvar = 'P0'
537 write(*,*) clnomvar
538 ip1 = -1
539 ikey = utl_fstlir(zbuffer,iulssf,ini,inj,ink,idate,cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
540 if (ini /= hco_anl%ni .or. inj /= hco_anl%nj .or. ink /= 1) then
541 write(*,*)
542 write(*,*) 'HBHT_static: Invalid dimensions for...'
543 write(*,*) 'nomvar =', trim(CLNOMVAR)
544 write(*,*) 'etiket =', trim(CLETIKET)
545 write(*,*) 'Found ni,nj,nk =', ini, inj, ink
546 write(*,*) 'Should be =', hco_anl%ni, hco_anl%nj, 1
547 call utl_abort('ose_compute_hbht_static')
548 end if
549 call gsv_getField(statevector,field_ptr,'P0')
550 do jlev = 1, ink
551 do jlat = 1, hco_anl%nj
552 do jlon = 1, hco_anl%ni
553 field_ptr(jlon,jlat,jlev) = scaleFactor(max(nLev_M,nLev_T))*zbuffer(jlon,jlat)*MPC_PA_PER_MBAR_R8
554 end do
555 end do
556 end do
557
558 clnomvar = 'UU'
559 write(*,*) clnomvar
560 call gsv_getField(statevector,field_ptr,'UU')
561 do jlev = 1, nlev_M
562 ip1 = vco_anl%ip1_M(jlev)
563 ikey = utl_fstlir(zbuffer,iulssf,ini,inj,ink,idate,cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
564 if (ini /= hco_anl%ni .or. inj /= hco_anl%nj .or. ink /= 1) then
565 write(*,*)
566 write(*,*) 'HBHT_static: Invalid dimensions for...'
567 write(*,*) 'nomvar =', trim(clnomvar)
568 write(*,*) 'etiket =', trim(cletiket)
569 write(*,*) 'Found ni,nj,nk =', ini, inj, ink
570 write(*,*) 'Should be =', hco_anl%ni, hco_anl%nj, nlev_M
571 call utl_abort('ose_compute_hbht_static')
572 end if
573 do jlat = 1, hco_anl%nj
574 do jlon = 1, hco_anl%ni
575 field_ptr(jlon,jlat,jlev) = scaleFactor(jlev+shift_level)*zbuffer(jlon,jlat)*MPC_M_PER_S_PER_KNOT_R8
576 end do
577 end do
578 end do
579
580 clnomvar = 'VV'
581 write(*,*) clnomvar
582 call gsv_getField(statevector,field_ptr,'VV')
583 do jlev = 1, nlev_M
584 ip1 = vco_anl%ip1_M(jlev)
585 ikey = utl_fstlir(zbuffer,iulssf,ini,inj,ink,idate,cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
586 if (ini /= hco_anl%ni .or. inj /= hco_anl%nj .or. ink /= 1) then
587 write(*,*)
588 write(*,*) 'HBHT_static: Invalid dimensions for...'
589 write(*,*) 'nomvar =', trim(clnomvar)
590 write(*,*) 'etiket =', trim(cletiket)
591 write(*,*) 'Found ni,nj,nk =', ini, inj, ink
592 write(*,*) 'Should be =', hco_anl%ni, hco_anl%nj, nlev_M
593 call utl_abort('ose_compute_hbht_static')
594 end if
595 do jlat = 1, hco_anl%nj
596 do jlon = 1, hco_anl%ni
597 field_ptr(jlon,jlat,jlev) = scaleFactor(jlev+shift_level)*zbuffer(jlon,jlat)*MPC_M_PER_S_PER_KNOT_R8
598 end do
599 end do
600 end do
601
602 clnomvar = 'TT'
603 write(*,*) clnomvar
604 call gsv_getField(statevector,field_ptr,'TT')
605 do jlev = 1, nlev_T
606 ip1 = vco_anl%ip1_T(jlev)
607 ikey = utl_fstlir(zbuffer,iulssf,ini,inj,ink,idate,cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
608 if (ini /= hco_anl%ni .or. inj /= hco_anl%nj .or. ink /= 1) then
609 write(*,*)
610 write(*,*) 'HBHT_static: Invalid dimensions for...'
611 write(*,*) 'nomvar =', trim(clnomvar)
612 write(*,*) 'etiket =', trim(cletiket)
613 write(*,*) 'Found ni,nj,nk =', ini, inj, ink
614 write(*,*) 'Should be =', hco_anl%ni, hco_anl%nj, nlev_T
615 call utl_abort('ose_compute_hbht_static')
616 end if
617 do jlat = 1, hco_anl%nj
618 do jlon = 1, hco_anl%ni
619 field_ptr(jlon,jlat,jlev) = scaleFactor(jlev)*zbuffer(jlon,jlat)
620 end do
621 end do
622 end do
623
624 clnomvar = 'ES'
625 write(*,*) clnomvar
626 call gsv_getField(statevector,field_ptr,'HU')
627 do jlev = 1, nlev_T
628 ip1 = vco_anl%ip1_T(jlev)
629 ikey = utl_fstlir(zbuffer,iulssf,ini,inj,ink,idate,cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
630 if (ini /= hco_anl%ni .or. inj /= hco_anl%nj .or. ink /= 1) then
631 write(*,*)
632 write(*,*) 'HBHT_static: Invalid dimensions for...'
633 write(*,*) 'nomvar =', trim(clnomvar)
634 write(*,*) 'etiket =', trim(cletiket)
635 write(*,*) 'Found ni,nj,nk =', ini, inj, ink
636 write(*,*) 'Should be =', hco_anl%ni, hco_anl%nj, nlev_T
637 call utl_abort('ose_compute_hbht_static')
638 end if
639 do jlat = 1, hco_anl%nj
640 do jlon = 1, hco_anl%ni
641 field_ptr(jlon,jlat,jlev) = scaleFactor(jlev)*zbuffer(jlon,jlat)
642 end do
643 end do
644 end do
645
646 clnomvar = 'LVIS'
647 if (gsv_varExist(statevector,clnomvar)) then
648 write(*,*) clnomvar
649 call gsv_getField(statevector,field_ptr,clnomvar)
650 do jlev = 1, nlev_T
651 ip1 = vco_anl%ip1_T(jlev)
652 ikey = utl_fstlir(zbuffer,iulssf,ini,inj,ink,idate,cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
653 if (ini /= hco_anl%ni .or. inj /= hco_anl%nj .or. ink /= 1) then
654 write(*,*)
655 write(*,*) 'HBHT_static: Invalid dimensions for...'
656 write(*,*) 'nomvar =', trim(clnomvar)
657 write(*,*) 'etiket =', trim(cletiket)
658 write(*,*) 'Found ni,nj,nk =', ini, inj, ink
659 write(*,*) 'Should be =', hco_anl%ni, hco_anl%nj, nlev_T
660 call utl_abort('ose_compute_hbht_static')
661 end if
662 do jlat = 1, hco_anl%nj
663 do jlon = 1, hco_anl%ni
664 field_ptr(jlon,jlat,jlev) = scaleFactor(jlev)*zbuffer(jlon,jlat)
665 end do
666 end do
667 end do
668 end if
669
670 clnomvar = 'WGE'
671 if (gsv_varExist(statevector,clnomvar)) then
672 write(*,*) clnomvar
673 ip1 = -1
674 ikey = utl_fstlir(zbuffer,iulssf,ini,inj,ink,idate,cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
675 if (ini /= hco_anl%ni .or. inj /= hco_anl%nj .or. ink /= 1) then
676 write(*,*)
677 write(*,*) 'HBHT_static: Invalid dimensions for...'
678 write(*,*) 'nomvar =', trim(CLNOMVAR)
679 write(*,*) 'etiket =', trim(CLETIKET)
680 write(*,*) 'Found ni,nj,nk =', ini, inj, ink
681 write(*,*) 'Should be =', hco_anl%ni, hco_anl%nj, 1
682 call utl_abort('ose_compute_hbht_static')
683 end if
684 call gsv_getField(statevector,field_ptr,clnomvar)
685 do jlev = 1, ink
686 do jlat = 1, hco_anl%nj
687 do jlon = 1, hco_anl%ni
688 field_ptr(jlon,jlat,jlev) = scaleFactor(max(nLev_M,nLev_T))*zbuffer(jlon,jlat)
689 end do
690 end do
691 end do
692 end if
693
694 call s2c_bgcheck_bilin(column,statevector,lobsSpaceData)
695
696 ! SET THE FIRST-GUESS ERRORS FOR THE SURFACE DATA
697 ! ------------------------------------------------
698
699 call setfgesurf(column,columnTrlOnAnlIncLev,lobsSpaceData)
700
701 ! READ IN LN Q FIRST-GUESS ERRORS FOR SETFGEGPS
702 ! ---------------------------------------------
703
704 clnomvar = 'LQ'
705 write(*,*) clnomvar
706 call gsv_getField(statevector,field_ptr,'HU')
707 do jlev = 1, nlev_T
708 ip1 = vco_anl%ip1_T(jlev)
709 ikey = utl_fstlir(zbuffer,iulssf,ini,inj,ink,idate,cletiket,ip1,ip2,ip3,cltypvar,clnomvar)
710 if (ini /= hco_anl%ni .or. inj /= hco_anl%nj .or. ink /= 1) then
711 write(*,*)
712 write(*,*) 'HBHT_static: Invalid dimensions for...'
713 write(*,*) 'nomvar =', trim(clnomvar)
714 write(*,*) 'etiket =', trim(cletiket)
715 write(*,*) 'Found ni,nj,nk =', ini, inj, ink
716 write(*,*) 'Should be =', hco_anl%ni, hco_anl%nj, nlev_T
717 call utl_abort('ose_compute_hbht_static')
718 end if
719 do jlat = 1, hco_anl%nj
720 do jlon = 1, hco_anl%ni
721 field_ptr(jlon,jlat,jlev) = scaleFactor(jlev)*zbuffer(jlon,jlat)
722 end do
723 end do
724 end do
725
726 call s2c_bgcheck_bilin(column,statevector,lobsSpaceData)
727
728 ! OPTIONAL TEST OF THE GB-GPS ZTD OPERATOR JACOBIAN
729 ! -------------------------------------------------
730
731 if (gps_gb_ltestop) call setfgegps(column,columnTrlOnAnlIncLev,lobsSpaceData)
732
733 deallocate(scaleFactor)
734 call col_deallocate(column)
735 deallocate(zbuffer)
736
737 write(*,*)
738 write(*,*) 'Computing HBHT from Bnmc - END'
739
740 end subroutine ose_compute_hbht_static
741
742 !--------------------------------------------------------------------------
743 ! ose_compute_hbht_static_chem
744 !--------------------------------------------------------------------------
745 subroutine ose_compute_hbht_static_chem(columnTrlOnAnlIncLev,obsSpaceData,active)
746 !
747 !:Purpose: To compute the background error standard deviations in
748 ! observation space, sqrt(diag(H*B_static*H^T)).
749 !
750 implicit none
751
752 ! Arguments:
753 type(struct_columnData), intent(in) :: columnTrlOnAnlIncLev ! column at observation location
754 type(struct_obs), intent(inout) :: obsSpaceData ! observation-space data, output saved in OBS_HPHT column
755 logical, intent(out) :: active ! flag to indicate if chemical constituents are to be used
756
757 ! Locals:
758 type(struct_vco), pointer :: vco_anl
759
760 !- Get the appropriate Vertical Coordinate
761 vco_anl => col_getVco(columnTrlOnAnlIncLev)
762
763 call bcsc_setupCH( hco_anl,vco_anl,active,'BackgroundCheck' )
764
765 if (active) then
766 write(*,*)
767 write(*,*) 'Computing H*B*H^T using B_static_chm - Start'
768 else
769 if ( mmpi_myid == 0 ) write(*,*) 'ose_compute_HBHT_static_chem: option NOT ACTIVATED'
770 return
771 end if
772
773 call oopc_CHobsoperators(columnTrlOnAnlIncLev,obsSpaceData,'HBHT')
774
775 write(*,*)
776 write(*,*) 'Computing H*B*H^T using B_static_chm - End'
777
778 RETURN
779 end subroutine ose_compute_hbht_static_chem
780
781 !--------------------------------------------------------------------------
782 ! ose_compute_hbht_ensemble
783 !--------------------------------------------------------------------------
784 subroutine ose_compute_hbht_ensemble(columnTrlOnAnlIncLev,obsSpaceData,active)
785 !
786 !:Purpose: To compute background-error stddev in observation space using
787 ! ensemble-based statistics.
788 !
789 implicit none
790
791 ! Arguments:
792 type(struct_columnData), intent(inout) :: columnTrlOnAnlIncLev ! Background columns interpolated to anl levels, obs locations
793 type(struct_obs), intent(inout) :: obsSpaceData ! Observation-related data
794 logical, intent(out) :: active
795
796 ! Locals:
797 type(struct_columnData) :: column
798 type(struct_gsv) :: statevector
799 type(struct_vco), pointer :: vco_anl
800 real(8), allocatable :: HBHT_ens(:)
801 integer :: memberIndex, index_body
802 integer, allocatable :: cvdim(:)
803
804 !
805 !- 1. Initialization
806 !
807
808 !- 1.1 Get vertical analysis grid attributes
809 vco_anl => col_getVco(columnTrlOnAnlIncLev)
810
811 !- 1.2 Initialize/Read the flow-dependent ensemble perturbations
812 call ben_Setup( hco_anl, hco_anl, & ! IN
813 vco_anl, & ! IN
814 cvdim, & ! OUT
815 'BackgroundCheck' ) ! IN
816
817 if ( cvdim(1) > 0 ) then
818 write(*,*)
819 write(*,*) 'Computing HBHT from ensemble perturbations - START'
820 active = .true.
821 else
822 if ( mmpi_myid == 0 ) write(*,*) 'ose_compute_hbht_ensemble: option NOT ACTIVATED'
823 active = .false.
824 return
825 end if
826
827 !- 1.3 Create a gridstatevector to store the ensemble perturbations
828 call gsv_allocate(statevector, tim_nstepobsinc, hco_anl, vco_anl, &
829 mpi_local_opt=.true., allocHeight_opt=.false., allocPressure_opt=.false.)
830
831 !- 1.4 Create column vectors to store the ens perturbation interpolated to obs horizontal locations
832 call col_setVco(column,vco_anl)
833 call col_allocate(column,col_getNumCol(columnTrlOnAnlIncLev),mpiLocal_opt=.true.)
834
835 !- 1.5 Create a working a array to sum H ensPert HT
836 allocate(HBHT_ens(obs_numBody(obsSpaceData)))
837 HBHT_ens(:) = 0.d0
838
839 !- 1.6
840 call oti_timeBinning(obsSpaceData,tim_nstepobsinc)
841
842 !
843 !- 2. Compute HBHT from the ensemble perturbations
844 !
845 do memberIndex = 1, ben_getnEns()
846
847 !- 2.1 Extract perturbations from the current memberIndex
848 write(*,*)
849 write(*,*) 'Reading ensemble perturbation from member = ', memberIndex
850 call ben_getPerturbation( statevector, &
851 memberIndex, &
852 'ConstantValue' )
853
854 !- 2.2 Interpolation to the observation horizontal locations
855 ! column - OUT (H_horiz EnsPert)
856 call s2c_tl( statevector, &
857 column, &
858 columnTrlOnAnlIncLev, obsSpaceData )
859
860 !- 2.3 Interpolation to observation space
861 ! obsSpaceData - OUT (Save as OBS_WORK: H_vert H_horiz EnsPert = H EnsPert)
862 call oop_Htl( column, columnTrlOnAnlIncLev, &
863 obsSpaceData, &
864 1 )
865
866 !- 2.4 alpha * HBH^T = sum(OBS_WORK^2)
867 do index_body = 1, obs_numBody(obsSpaceData)
868 HBHT_ens(index_body) = HBHT_ens(index_body) + &
869 (obs_bodyElem_r(obsSpaceData,OBS_WORK,index_body))**2
870 end do
871
872 end do
873
874 !- 2.5 Insert the standard deviations in OBS_WORK
875 do index_body = 1, obs_numBody(obsSpaceData)
876 call obs_bodySet_r(obsSpaceData,OBS_WORK,index_body,sqrt(HBHT_ens(index_body)))
877 end do
878
879 !
880 !- 3. Ending/Deallocation
881 !
882 deallocate(HBHT_ens)
883 call col_deallocate(column)
884 call gsv_deallocate(statevector)
885
886 write(*,*)
887 write(*,*) 'Computing HBHT from ensemble perturbations - END'
888
889 end subroutine ose_compute_hbht_ensemble
890
891 !-------------------- Weather obs FGE std dev routines --------------------
892
893 !--------------------------------------------------------------------------
894 ! setfgefam
895 !--------------------------------------------------------------------------
896 subroutine setfgefam(cdfam,column,columnTrlOnAnlIncLev,lobsSpaceData)
897 !
898 !:Purpose: To interpolate vertically the contents of "column" to
899 ! the pressure levels of the observations. Then to compute
900 ! THE FIRST GUESS ERROR VARIANCES. A linear interpolation in ln(p)
901 ! is performed.
902 !
903 implicit none
904
905 ! Arguments:
906 character(len=2), intent(in) :: cdfam
907 type(struct_columnData), intent(in) :: column
908 type(struct_columnData), intent(in) :: columnTrlOnAnlIncLev
909 type(struct_obs), intent(inout) :: lobsSpaceData
910
911 ! Locals:
912 INTEGER IPB,IPT
913 INTEGER INDEX_HEADER,ITYP,IK
914 INTEGER INDEX_BODY
915 REAL*8 ZWB,ZWT, columnElem
916 REAL*8 ZLEV,ZPB,ZPT
917 character(len=4) :: varLevel
918
919 ! loop over all header indices of the CDFAM family
920 call obs_set_current_header_list(lobsSpaceData,CDFAM)
921 HEADER: do
922 index_header = obs_getHeaderIndex(lobsSpaceData)
923 if (index_header < 0) exit HEADER
924
925 ! loop over all body indices for this index_header
926 call obs_set_current_body_list(lobsSpaceData, index_header)
927 BODY: do
928 index_body = obs_getBodyIndex(lobsSpaceData)
929 if (index_body < 0) exit BODY
930 !
931 !* 1. Computation of sigmap
932 ! . -----------------------------
933 !
934 IF ( obs_bodyElem_i(lobsSpaceData,OBS_ASS,index_body) == obs_assimilated .AND. &
935 obs_bodyElem_i(lobsSpaceData,OBS_VCO,index_body) .EQ. 2 ) then
936 IF (obs_bodyElem_i(lobsSpaceData,OBS_XTR,index_body) .NE. 0) THEN
937 ITYP = obs_bodyElem_i(lobsSpaceData,OBS_VNM,index_body)
938 varLevel = vnl_varLevelFromVarnum(ityp)
939 IK = col_getNumLev(columnTrlOnAnlIncLev,varLevel)
940 IPB = IK + col_getOffsetFromVarno(columnTrlOnAnlIncLev,ityp)
941 if(ITYP .ne. BUFR_NEGZ) then
942 call obs_bodySet_r(lobsSpaceData,OBS_HPHT,index_body,col_getElem(column,IPB,INDEX_HEADER))
943 else
944 call obs_bodySet_r(lobsSpaceData,OBS_HPHT,index_body,col_getHeight(column,IK,INDEX_HEADER,'TH'))
945 endif
946 ELSE
947 ITYP = obs_bodyElem_i(lobsSpaceData,OBS_VNM,index_body)
948 varLevel = vnl_varLevelFromVarnum(ityp)
949 ZLEV = obs_bodyElem_r(lobsSpaceData,OBS_PPP,index_body)
950 IK = obs_bodyElem_i(lobsSpaceData,OBS_LYR,index_body)
951 IPT = IK + col_getOffsetFromVarno(columnTrlOnAnlIncLev,ityp)
952 IPB = IPT+1
953 ZPT = col_getPressure(columnTrlOnAnlIncLev,IK,INDEX_HEADER,varLevel)
954 ZPB = col_getPressure(columnTrlOnAnlIncLev,IK+1,INDEX_HEADER,varLevel)
955 ZWB = LOG(ZLEV/ZPT)/LOG(ZPB/ZPT)
956 ZWT = 1.0D0 - ZWB
957
958 ! FIRST GUESS ERROR VARIANCE
959
960 if(ITYP .ne. BUFR_NEGZ) then
961 call obs_bodySet_r(lobsSpaceData,OBS_HPHT,index_body, &
962 (ZWB*col_getElem(column,IPB,INDEX_HEADER) + ZWT*col_getElem(column,IPT,INDEX_HEADER)))
963 else
964 call obs_bodySet_r(lobsSpaceData,OBS_HPHT,index_body, &
965 (ZWB*col_getHeight(column,IK+1,INDEX_HEADER,'TH') + ZWT*col_getHeight(column,IK,INDEX_HEADER,'TH')))
966 endif
967 if(obs_bodyElem_r(lobsSpaceData,OBS_HPHT,index_body).le.0.d0) then
968 write(*,*) 'SETFGEFAM: CDFAM = ',CDFAM
969 write(*,*) 'SETFGEFAM: IPB,IPT,ZWB,ZWT,ITYP,ZLEV=',IPB,IPT,ZWB,ZWT,ITYP,ZLEV
970 columnElem = col_getElem(column,IPB,INDEX_HEADER)
971 write(*,*) 'SETFGEFAM: column_all(IPB,INDEX_HEADER)=',columnElem
972 columnElem = col_getElem(column,IPT,INDEX_HEADER)
973 write(*,*) 'SETFGEFAM: column_all(IPT,INDEX_HEADER)=',columnElem
974 columnElem = col_getHeight(column,IK+1,INDEX_HEADER,'TH')
975 write(*,*) 'SETFGEFAM: get_height(IK+1,INDEX_HEADER)=',columnElem
976 columnElem = col_getHeight(column,IK ,INDEX_HEADER,'TH')
977 write(*,*) 'SETFGEFAM: get_height(IK ,INDEX_HEADER)=',columnElem
978 CALL utl_abort('SETFGEFAM: First-guess stdev bad value')
979 endif
980 ENDIF
981 ENDIF
982
983 END DO BODY
984
985 END DO HEADER
986
987 end subroutine setfgefam
988
989 !--------------------------------------------------------------------------
990 ! setfgefamz
991 !--------------------------------------------------------------------------
992 subroutine setfgefamz(cdfam, column, columnTrlOnAnlIncLev, obsSpaceData)
993 !
994 !:Purpose: To interpolate vertically the contents of "column" to the levels
995 ! of the observations (in meters). Then to compute THE FIRST GUESS
996 ! ERROR VARIANCES. A linear interpolation in z is performed.
997 !
998 implicit none
999
1000 ! Arguments:
1001 character(len=2), intent(in) :: cdfam
1002 type(struct_columnData), intent(in) :: column
1003 type(struct_columnData), intent(in) :: columnTrlOnAnlIncLev
1004 type(struct_obs), intent(inout) :: obsSpaceData
1005
1006 ! Locals:
1007 integer :: IPB, IPT
1008 integer :: headerIndex, ITYP, IK
1009 integer :: bodyIndex
1010 integer :: bodyIndexStart, bodyIndexEnd, bodyIndex2
1011 real*8 :: ZWB, ZWT, sigmap_uuT, sigmap_vvT , sigmap_uuB, sigmap_vvB
1012 real*8 :: ZLEV, ZPB, ZPT
1013 real(8) :: azimuth, fge_uu, fge_vv, fge_fam
1014 character(len=4) :: varLevel
1015
1016 ! loop over all header indices of the CDFAM family
1017 call obs_set_current_header_list(obsSpaceData, CDFAM)
1018 HEADER: do
1019 headerIndex = obs_getHeaderIndex(obsSpaceData)
1020 if ( headerIndex < 0 ) exit HEADER
1021
1022 if ( cdfam == 'RA' ) then
1023 ! Azimuth of the radar beam
1024 azimuth = obs_headElem_r(obsSpaceData, OBS_RZAM, headerIndex )
1025 end if
1026
1027 ! loop over all body indices for this headerIndex
1028 call obs_set_current_body_list(obsSpaceData, headerIndex)
1029 BODY: do
1030 bodyIndex = obs_getBodyIndex(obsSpaceData)
1031 if ( bodyIndex < 0 ) exit BODY
1032
1033 !* 1. Computation of sigmap
1034 ! . -----------------------------
1035 if ( obs_bodyElem_i(obsSpaceData, OBS_ASS, bodyIndex) == obs_assimilated .and. &
1036 obs_bodyElem_i(obsSpaceData, OBS_VCO, bodyIndex) == 1 )then
1037 ITYP = obs_bodyElem_i(obsSpaceData, OBS_VNM, bodyIndex)
1038 if ( ITYP == bufr_radarPrecip ) cycle BODY
1039 varLevel = vnl_varLevelFromVarnum(ityp)
1040
1041 ! Interpolate the background-covariance statistics
1042 if ( obs_bodyElem_i(obsSpaceData, OBS_XTR, bodyIndex) /= 0 ) then
1043 IK=col_getNumLev(columnTrlOnAnlIncLev, varLevel)-1
1044 IPT = IK + col_getOffsetFromVarno(columnTrlOnAnlIncLev, ityp)
1045 IPB = IPT +1
1046 fge_uu = col_getElem(column, IPB, headerIndex, 'UU')
1047 fge_vv = col_getElem(column, IPB, headerIndex, 'VV')
1048
1049 else
1050 ZLEV = obs_bodyElem_r(obsSpaceData, OBS_PPP, bodyIndex)
1051 IK = obs_bodyElem_i(obsSpaceData, OBS_LYR, bodyIndex)
1052 IPT = IK + col_getOffsetFromVarno(columnTrlOnAnlIncLev, ityp)
1053 IPB = IPT+1
1054 ZPT = col_getHeight(columnTrlOnAnlIncLev, IK, headerIndex, varLevel)
1055 ZPB = col_getHeight(columnTrlOnAnlIncLev, IK+1, headerIndex, varLevel)
1056 ZWB = (ZPT-ZLEV)/(ZPT-ZPB)
1057 ZWT = 1.d0 - ZWB
1058 fge_uu = ZWB*col_getElem(column, IPB, headerIndex, 'UU') &
1059 + ZWT*col_getElem(column, IPT, headerIndex, 'UU')
1060 fge_vv = ZWB*col_getElem(column, IPB, headerIndex, 'VV') &
1061 + ZWT*col_getElem(column, IPT, headerIndex, 'VV')
1062 end if
1063
1064 ! First-Guess Error Variance
1065 if ( cdfam == 'AL' )then
1066 ! Scan body indices for the azimuth
1067 bodyIndexStart = obs_headElem_i(obsSpaceData, OBS_RLN, headerIndex)
1068 bodyIndexEnd = obs_headElem_i(obsSpaceData, OBS_NLV, headerIndex) &
1069 + bodyIndexStart - 1
1070 BODY_SUPP: do bodyIndex2 = bodyIndexStart, bodyIndexEnd
1071 if(obs_bodyElem_i(obsSpaceData, OBS_VNM, bodyIndex2) == 5021)then
1072 azimuth=obs_bodyElem_r(obsSpaceData, OBS_VAR, bodyIndex2) * MPC_RADIANS_PER_DEGREE_R8
1073 exit BODY_SUPP
1074 end if
1075 end do BODY_SUPP
1076
1077 fge_fam = sqrt((fge_vv*cos(azimuth))**2 + (fge_uu*sin(azimuth))**2)
1078
1079 else if( cdfam == 'PR' )then
1080 fge_fam = ZWB*col_getElem(column, IPB, headerIndex) &
1081 + ZWT*col_getElem(column, IPT, headerIndex)
1082
1083 else if( cdfam == 'RA' .and. ITYP == bufr_radvel ) then
1084
1085 ! Calculation of sigmap^2 = diag(H*P*H^t) to save sigmap in OBS_HPHT
1086 !
1087 ! H includes vertical interpolation
1088 ! and projection of U and V wind components along the direction of the beam
1089 !
1090 ! P forecast error covariance
1091 !
1092 ! H = [ ZWT*sin(az) ZWT*cos(az) ZWB*sin(az) ZWB*cos(az) ]
1093 ! diag(P) = [ sigmap_uuT^2 sigmap_vvT^2 sigmap_uuB^2 sigmap_vvB^2 ]
1094 sigmap_uuT = col_getElem(column, IPT, headerIndex, 'UU')
1095 sigmap_uuB = col_getElem(column, IPB, headerIndex, 'UU')
1096 sigmap_vvT = col_getElem(column, IPT, headerIndex, 'VV')
1097 sigmap_vvB = col_getElem(column, IPB, headerIndex, 'VV')
1098
1099 fge_fam = sqrt((sigmap_uuT*ZWT*sin(azimuth))**2 + (sigmap_vvT*ZWT*cos(azimuth))**2 + &
1100 (sigmap_uuB*ZWB*sin(azimuth))**2 + (sigmap_vvB*ZWB*cos(azimuth))**2)
1101
1102 else
1103
1104 write(*,*)"ERROR: The family", cdfam, " is not supported by setfgefamz"
1105 call utl_abort('setfgefamz')
1106
1107 end if
1108
1109 ! Store fge_fam in OBS_HPHT
1110 call obs_bodySet_r(obsSpaceData, OBS_HPHT, bodyIndex, fge_fam)
1111
1112 end if
1113
1114 end do BODY
1115
1116 end do HEADER
1117
1118 end subroutine setfgefamz
1119
1120 !--------------------------------------------------------------------------
1121 ! setfgett
1122 !--------------------------------------------------------------------------
1123 subroutine setfgett(column,columnTrlOnAnlIncLev,lobsSpaceData)
1124 !
1125 !:Purpose: To interpolate vertically the contents of "column" to the
1126 ! pressure levels of the observations. Then to compute THE FIRST
1127 ! GUESS ERROR VARIANCES. A linear interpolation in ln(p) is
1128 ! performed.
1129 !
1130 implicit none
1131
1132 ! Arguments:
1133 type(struct_columnData), intent(in) :: column
1134 type(struct_columnData), intent(in) :: columnTrlOnAnlIncLev
1135 type(struct_obs), intent(inout) :: lobsSpaceData
1136
1137 ! Locals:
1138 INTEGER IPB,IPT
1139 INTEGER INDEX_HEADER,ITYP,IK
1140 INTEGER INDEX_BODY
1141 REAL*8 ZWB,ZWT
1142 REAL*8 ZLEV,ZPB,ZPT
1143 character(len=4) :: varLevel
1144
1145 ! loop over all body rows
1146 BODY: do index_body=1,obs_numbody(lobsSpaceData)
1147
1148 ! 1. Computation of sigmap
1149 ! ---------------------
1150
1151 IF ( (obs_bodyElem_i(lobsSpaceData,OBS_ASS,index_body) == obs_assimilated) .and. &
1152 (obs_bodyElem_i(lobsSpaceData,OBS_VNM,index_body).EQ. BUFR_NETT) ) THEN
1153
1154 IF ( (obs_bodyElem_i(lobsSpaceData,OBS_XTR,index_body) .NE. 0) .and. &
1155 (obs_bodyElem_i(lobsSpaceData,OBS_VCO,index_body) .EQ. 2) ) THEN
1156 ITYP = obs_bodyElem_i(lobsSpaceData,OBS_VNM,index_body)
1157 varLevel = vnl_varLevelFromVarnum(ityp)
1158 IK=col_getNumLev(columnTrlOnAnlIncLev,varLevel)-1
1159 INDEX_HEADER = obs_bodyElem_i(lobsSpaceData,OBS_HIND,index_body)
1160 IPT = IK + col_getOffsetFromVarno(columnTrlOnAnlIncLev,ityp)
1161 IPB = IPT +1
1162 call obs_bodySet_r(lobsSpaceData,OBS_HPHT,index_body,col_getElem(column,IPB,INDEX_HEADER))
1163 ELSE
1164 INDEX_HEADER = obs_bodyElem_i(lobsSpaceData,OBS_HIND,index_body)
1165 ZLEV = obs_bodyElem_r(lobsSpaceData,OBS_PPP,index_body)
1166 IK = obs_bodyElem_i(lobsSpaceData,OBS_LYR,index_body)
1167 IPT = IK
1168 IPB = IPT+1
1169 ITYP = obs_bodyElem_i(lobsSpaceData,OBS_VNM,index_body)
1170 varLevel = vnl_varLevelFromVarnum(ityp)
1171 ZPT = col_getPressure(columnTrlOnAnlIncLev,IK,INDEX_HEADER,varLevel)
1172 ZPB = col_getPressure(columnTrlOnAnlIncLev,IK+1,INDEX_HEADER,varLevel)
1173 ZWB = LOG(ZLEV/ZPT)/LOG(ZPB/ZPT)
1174 ZWT = 1.0D0 - ZWB
1175
1176 ! FIRST GUESS ERROR VARIANCE
1177
1178 call obs_bodySet_r(lobsSpaceData,OBS_HPHT,index_body, &
1179 (ZWB*col_getElem(column,IPB,INDEX_HEADER,'TT') + ZWT*col_getElem(column,IPT,INDEX_HEADER,'TT')))
1180 ENDIF
1181
1182 ENDIF
1183
1184 END DO BODY
1185
1186 end subroutine setfgett
1187
1188 !--------------------------------------------------------------------------
1189 ! setfgeSurf
1190 !--------------------------------------------------------------------------
1191 subroutine setfgeSurf(column, columnTrlOnAnlIncLev, lobsSpaceData)
1192 !
1193 !:Purpose: To interpolate vertically the contents of "column" to the
1194 ! pressure levels of the observations. A linear interpolation in
1195 ! ln(p) is performed.
1196 !
1197 implicit none
1198
1199 ! Arguments:
1200 type(struct_columnData), intent(in) :: column
1201 type(struct_columnData), intent(in) :: columnTrlOnAnlIncLev
1202 type(struct_obs) , intent(inout) :: lobsSpaceData
1203
1204 ! Locals:
1205 integer :: ipb, ipt, idim, headerIndex, ik, bodyIndex, ityp, bodyElem_i
1206 real(8) :: zwb, zwt, zlev, zpt, zpb, zhhh, bodyElem_r, colElem1, colElem2
1207 character(len=2) :: cfam
1208 character(len=4) :: varLevel
1209 character(len=12) :: stnid
1210 logical :: ok
1211
1212 ! loop over all body rows
1213 BODY: do bodyIndex = 1, obs_numbody( lobsSpaceData )
1214
1215 cfam = obs_getFamily( lobsSpaceData, bodyIndex_opt = bodyIndex )
1216 if( cfam == 'SF'.or. cfam == 'TM' .or. cfam == 'UA' .or. cfam == 'SC' .or. cfam == 'GP' .or. cfam == 'GL' ) then
1217
1218 ! Process all data within the domain of the model (excluding GB-GPS ZTD data)
1219 ok = .false.
1220
1221 if ( obs_bodyElem_i( lobsSpaceData, OBS_VCO, bodyIndex ) == 1 ) then
1222
1223 ityp = obs_bodyElem_i( lobsSpaceData, OBS_VNM, bodyIndex )
1224 if ( ityp == BUFR_NETS .or. ityp == BUFR_NEPS .or. ityp == BUFR_NEPN .or. ityp == BUFR_NESS .or. &
1225 ityp == BUFR_NEUS .or. ityp == BUFR_NEVS .or. ityp == BUFR_NEFS .or. ityp == BUFR_NEDS .or. &
1226 ityp == bufr_sst .or. ityp == BUFR_ICEC .or. ityp == bufr_logVis .or. ityp == bufr_gust .or. &
1227 ityp == bufr_riverFlow) then
1228
1229 ok = ( obs_bodyElem_i( lobsSpaceData, OBS_ASS, bodyIndex ) == obs_assimilated )
1230
1231 else if ( ityp == BUFR_NEZD ) then
1232
1233 ! make sure total zenith delay (from ground-based GPS) not treated
1234 ok=.false.
1235
1236 else
1237
1238 ok=(obs_bodyElem_i( lobsSpaceData, OBS_ASS, bodyIndex ) == obs_assimilated .and. &
1239 obs_bodyElem_i( lobsSpaceData, OBS_XTR, bodyIndex ) >= 0)
1240 if ( ok ) write(*,*) 'setfgesurf: WARNING!!! unknown obs seen'
1241 if ( ok ) write(*,*) 'setfgesurf: ityp=',ityp,', cfam=',cfam
1242
1243 end if
1244
1245 if ( ok ) then
1246
1247 headerIndex = obs_bodyElem_i( lobsSpaceData, OBS_HIND, bodyIndex )
1248 ityp = obs_bodyElem_i( lobsSpaceData, OBS_VNM , bodyIndex )
1249 varLevel = vnl_varLevelFromVarnum( ityp )
1250 idim = 1
1251 if ( varLevel == 'SF') idim = 0
1252 ik = obs_bodyElem_i( lobsSpaceData, OBS_LYR, bodyIndex )
1253 zlev = obs_bodyElem_r( lobsSpaceData, OBS_PPP, bodyIndex )
1254 zhhh = zlev
1255
1256 if ( ityp == BUFR_NETS .or. ityp == BUFR_NEPS .or. ityp == BUFR_NEPN .or. &
1257 ityp == BUFR_NESS .or. ityp == BUFR_NEUS .or. ityp == BUFR_NEVS .or. &
1258 ityp == bufr_logVis .or. ityp == bufr_gust) then
1259
1260 ipt = ik + col_getOffsetFromVarno(columnTrlOnAnlIncLev,ityp)
1261 ipb = ipt+1
1262 call obs_bodySet_r( lobsSpaceData, OBS_HPHT, bodyIndex, col_getElem( column, ipb, headerIndex ) )
1263
1264 else
1265
1266 ipt = ik + col_getOffsetFromVarno(columnTrlOnAnlIncLev,ityp)
1267 ipb = ipt+1
1268 zpt = col_getHeight(columnTrlOnAnlIncLev,ik,headerIndex,varLevel)
1269 zpb = col_getHeight(columnTrlOnAnlIncLev,ik+1,headerIndex,varLevel)
1270 zwb = idim*(zpt-zhhh)/(zpt-zpb)
1271 zwt = 1.d0 - zwb
1272
1273 if ( obs_bodyElem_i( lobsSpaceData, OBS_XTR, bodyIndex ) == 0 ) then
1274
1275 call obs_bodySet_r( lobsSpaceData, OBS_HPHT, bodyIndex, &
1276 zwb * col_getElem( column, ipb, headerIndex ) + zwt * col_getElem( column, ipt, headerIndex ))
1277
1278 else
1279
1280 call obs_bodySet_r( lobsSpaceData, OBS_HPHT, bodyIndex, &
1281 col_getElem( column, ik + col_getOffsetFromVarno( columnTrlOnAnlIncLev, ityp ), headerIndex ))
1282
1283 end if
1284
1285 stnid = obs_elem_c( lobsSpaceData, 'STID', headerIndex )
1286 if(stnid == '99999999' ) then
1287
1288 bodyElem_i = obs_bodyElem_i( lobsSpaceData, OBS_XTR, bodyIndex )
1289 write(*,*) 'setfgesurf: stn, ityp, xtr, ipt, ipb, zwt, zwb', &
1290 stnid, ityp, &
1291 bodyElem_i, ipt, ipb, zwt, zwb
1292 bodyElem_r = obs_bodyElem_i( lobsSpaceData, OBS_HPHT, bodyIndex )
1293 colElem1 = col_getElem( column, ipb, headerIndex )
1294 colElem2 = col_getElem( column, ipt, headerIndex )
1295 write(*,*) 'setfgesurf: gobs(ipb), gobs(ipt), fge', &
1296 colElem1, colElem2, bodyElem_r
1297
1298 endif
1299
1300 end if
1301 end if
1302 end if
1303
1304 end if
1305
1306 end do BODY
1307
1308 end subroutine setfgeSurf
1309
1310 !--------------------------------------------------------------------------
1311 ! setfgedif
1312 !--------------------------------------------------------------------------
1313 subroutine setfgedif(cdfam,columnTrlOnAnlIncLev,lobsSpaceData)
1314 !
1315 !:Purpose: To construct the FIRST GUESS ERROR VARIANCES from the
1316 ! diff-calculated dependencies and the primary errors.
1317 !
1318 implicit none
1319
1320 ! Arguments:
1321 character(len=2), intent(in) :: cdfam
1322 type(struct_columnData), intent(in) :: columnTrlOnAnlIncLev
1323 type(struct_obs), intent(inout) :: lobsSpaceData
1324
1325 ! Locals:
1326 INTEGER INDEX_HEADER, IDATYP, INDEX_BODY, iProfile, varNum
1327 REAL*8 zLat, Lat, sLat
1328 REAL*8 zLon, Lon
1329 REAL*8 zAzm !, Azm
1330 INTEGER ISAT
1331 REAL*8 Rad, Geo
1332 REAL*8, allocatable :: zPP(:)
1333 REAL*8, allocatable :: zDP(:)
1334 REAL*8, allocatable :: zTT(:)
1335 REAL*8, allocatable :: zHU(:)
1336 REAL*8, allocatable :: zHT(:)
1337 REAL*8, allocatable :: zUU(:)
1338 REAL*8, allocatable :: zVV(:)
1339 INTEGER JL
1340 REAL*8 ZP0, ZMT
1341 REAL*8 ZFGE, ZERR
1342 INTEGER JV, NGPSLEV, NWNDLEV
1343 LOGICAL ASSIM, LFIRST, FIRSTHEADER
1344 INTEGER NH, NH1
1345 REAL*8 DV (gps_ncvmx)
1346 TYPE(GPS_PROFILE) :: PRF
1347 REAL*8 , allocatable :: H (:),AZMV(:)
1348 TYPE(GPS_DIFF), allocatable :: RSTV(:)
1349 type(struct_vco), pointer :: vco_anl
1350 real*8, dimension(:), pointer :: dPdPs
1351
1352 WRITE(*,*)'ENTER SETFGEDIFF'
1353
1354 ! Initializations
1355
1356 nullify(dPdPs)
1357
1358 NGPSLEV=col_getNumLev(columnTrlOnAnlIncLev,'TH')
1359 NWNDLEV=col_getNumLev(columnTrlOnAnlIncLev,'MM')
1360 LFIRST=.FALSE.
1361 if ( .NOT.allocated(ose_vRO_Jacobian) ) then
1362 LFIRST = .TRUE.
1363 allocate(zPP (NGPSLEV))
1364 allocate(zDP (NGPSLEV))
1365 allocate(zTT (NGPSLEV))
1366 allocate(zHU (NGPSLEV))
1367 allocate(zHT (NGPSLEV))
1368 allocate(zUU (NGPSLEV))
1369 allocate(zVV (NGPSLEV))
1370
1371 allocate(ose_vRO_Jacobian(gps_numROProfiles,gps_RO_MAXPRFSIZE,2*NGPSLEV+1))
1372 allocate(ose_vRO_lJac (gps_numROProfiles))
1373 ose_vRO_Jacobian = 0.d0
1374 ose_vRO_lJac = .False.
1375
1376 allocate( H (gps_RO_MAXPRFSIZE) )
1377 allocate( AZMV (gps_RO_MAXPRFSIZE) )
1378 allocate( RSTV (gps_RO_MAXPRFSIZE) )
1379 endif
1380
1381 vco_anl => col_getVco(columnTrlOnAnlIncLev)
1382
1383 ! Loop over all header indices of the 'RO' family:
1384
1385 call obs_set_current_header_list(lobsSpaceData,CDFAM)
1386 FIRSTHEADER=.TRUE.
1387 HEADER: do
1388 index_header = obs_getHeaderIndex(lobsSpaceData)
1389 if (index_header < 0) exit HEADER
1390
1391 ! Process only refractivity data (codtyp 169)
1392
1393 IDATYP = obs_headElem_i(lobsSpaceData,OBS_ITY,INDEX_HEADER)
1394 IF ( IDATYP .EQ. 169 ) THEN
1395 iProfile = gps_iprofile_from_index(index_header)
1396 varNum = gps_vRO_IndexPrf(iProfile, 2)
1397
1398 ! Scan for requested data values of the profile, and count them
1399
1400 ASSIM = .FALSE.
1401 NH = 0
1402 call obs_set_current_body_list(lobsSpaceData, INDEX_HEADER)
1403 BODY: do
1404 INDEX_BODY = obs_getBodyIndex(lobsSpaceData)
1405 if (INDEX_BODY < 0) exit BODY
1406 IF ( obs_bodyElem_i(lobsSpaceData,OBS_ASS,INDEX_BODY) == obs_assimilated ) THEN
1407 ASSIM = .TRUE.
1408 NH = NH + 1
1409 ENDIF
1410 ENDDO BODY
1411
1412 ! If assimilations are requested, prepare and apply the observation operator
1413
1414 IF (ASSIM) THEN
1415 iProfile=gps_iprofile_from_index(INDEX_HEADER)
1416
1417 ! Profile at the observation location:
1418
1419 if (.not.ose_vRO_lJac(iProfile)) then
1420
1421 ! Basic geometric variables of the profile:
1422
1423 zLat = obs_headElem_r(lobsSpaceData,OBS_LAT,INDEX_HEADER)
1424 zLon = obs_headElem_r(lobsSpaceData,OBS_LON,INDEX_HEADER)
1425 ISAT = obs_headElem_i(lobsSpaceData,OBS_SAT,INDEX_HEADER)
1426 Rad = obs_headElem_r(lobsSpaceData,OBS_TRAD,INDEX_HEADER)
1427 Geo = obs_headElem_r(lobsSpaceData,OBS_GEOI,INDEX_HEADER)
1428 zAzm = obs_headElem_r(lobsSpaceData,OBS_AZA,INDEX_HEADER) / MPC_DEGREES_PER_RADIAN_R8
1429 zMT = col_getHeight(columnTrlOnAnlIncLev,NGPSLEV,INDEX_HEADER,'TH')
1430 Lat = zLat * MPC_DEGREES_PER_RADIAN_R8
1431 Lon = zLon * MPC_DEGREES_PER_RADIAN_R8
1432 !Azm = zAzm * MPC_DEGREES_PER_RADIAN_R8
1433 sLat = sin(zLat)
1434 zMT = zMT * ec_rg / gps_gravitysrf(sLat)
1435 zP0 = col_getElem(columnTrlOnAnlIncLev,1,INDEX_HEADER,'P0')
1436
1437 ! approximation for dPdPs
1438 if (associated(dPdPs)) then
1439 deallocate(dPdPs)
1440 end if
1441 call czp_fetch1DdPdPs(vco_anl, zP0, profT_opt=dPdPs)
1442 zDP(1:NGPSLEV) = dPdPs(1:NGPSLEV)
1443
1444 DO JL = 1, NGPSLEV
1445
1446 ! Profile x
1447
1448 zPP(JL) = col_getPressure(columnTrlOnAnlIncLev,JL,INDEX_HEADER,'TH')
1449 zTT(JL) = col_getElem(columnTrlOnAnlIncLev,JL,INDEX_HEADER,'TT') - MPC_K_C_DEGREE_OFFSET_R8
1450 zHU(JL) = col_getElem(columnTrlOnAnlIncLev,JL,INDEX_HEADER,'HU')
1451 zHT(JL) = col_getHeight(columnTrlOnAnlIncLev,JL,INDEX_HEADER,'TH')
1452 zUU(JL) = 0.d0
1453 zVV(JL) = 0.d0
1454 ENDDO
1455 DO JL = 1, NWNDLEV
1456 zUU(JL) = col_getElem(columnTrlOnAnlIncLev,JL,INDEX_HEADER,'UU')
1457 zVV(JL) = col_getElem(columnTrlOnAnlIncLev,JL,INDEX_HEADER,'VV')
1458 ENDDO
1459 zUU(NGPSLEV) = zUU(NWNDLEV)
1460 zVV(NGPSLEV) = zUU(NWNDLEV)
1461
1462 ! GPS profile structure:
1463
1464 call gps_struct1sw(ngpslev,zLat,zLon,zAzm,zMT,Rad,geo,zP0,zPP,zDP,zTT,zHU,zUU,zVV,prf)
1465 !call gps_struct1sw_v2(ngpslev,zLat,zLon,zAzm,zMT,Rad,geo,zP0,zPP,zDP,zTT,zHU,zUU,zVV,zHT,prf)
1466
1467 ! Prepare the vector of all the observations:
1468
1469 NH1 = 0
1470 call obs_set_current_body_list(lobsSpaceData, INDEX_HEADER)
1471 BODY_2: do
1472 INDEX_BODY = obs_getBodyIndex(lobsSpaceData)
1473 if (INDEX_BODY < 0) exit BODY_2
1474 IF ( obs_bodyElem_i(lobsSpaceData,OBS_ASS,INDEX_BODY) == obs_assimilated ) THEN
1475 NH1 = NH1 + 1
1476 H(NH1) = obs_bodyElem_r(lobsSpaceData,OBS_PPP,INDEX_BODY)
1477 AZMV(NH1)= zAzm
1478 ENDIF
1479 ENDDO BODY_2
1480
1481 ! Apply the observation operator:
1482
1483 IF (varNum == bufr_nebd) THEN
1484 CALL GPS_BNDOPV1(H, AZMV, NH, PRF, RSTV)
1485 ELSE
1486 CALL GPS_REFOPV (H, NH, PRF, RSTV)
1487 ENDIF
1488 DO NH1=1,NH
1489 ose_vRO_Jacobian(iProfile,NH1,:)= RSTV(NH1)%DVAR(1:2*NGPSLEV+1)
1490 ENDDO
1491 ose_vRO_lJac(iProfile) = .True.
1492 endif
1493
1494 ! Local error
1495
1496 DO JL = 1, NGPSLEV
1497 DV ( JL) = 1.d0
1498 DV (NGPSLEV+JL) = 1.d0
1499 ENDDO
1500 DV (2*NGPSLEV+1) = 2.d0
1501
1502 ! Perform the H(xb)DV operation:
1503
1504 NH1 = 0
1505 call obs_set_current_body_list(lobsSpaceData, INDEX_HEADER)
1506 BODY_3: do
1507 INDEX_BODY = obs_getBodyIndex(lobsSpaceData)
1508 if (INDEX_BODY < 0) exit BODY_3
1509 IF ( obs_bodyElem_i(lobsSpaceData,OBS_ASS,INDEX_BODY) == obs_assimilated ) THEN
1510 NH1 = NH1 + 1
1511
1512 ! Observation jacobian
1513
1514 ! JAC = RSTV(NH1)%DVAR
1515
1516 ! Evaluate sqrt( H(xb)DV **2 )
1517
1518 ZFGE = 0.d0
1519 DO JV = 1, 2*PRF%NGPSLEV+1
1520 ZFGE = ZFGE + (ose_vRO_Jacobian(iProfile,NH1,JV) * DV(JV))**2
1521 ENDDO
1522 ZFGE = SQRT(ZFGE)
1523 ZERR = obs_bodyElem_r(lobsSpaceData,OBS_OER,INDEX_BODY)
1524
1525 ! FIRST GUESS ERROR VARIANCE
1526
1527 call obs_bodySet_r(lobsSpaceData,OBS_HPHT,INDEX_BODY,ZFGE)
1528 IF (FIRSTHEADER) THEN
152911 FORMAT(A12,2I5,F12.2,3F16.8)
1530 WRITE(*,11)'SETFGEDIFFGE',NH1,NH,H(NH1),RSTV(NH1)%VAR,ZFGE,ZERR
1531 ENDIF
1532 ENDIF
1533 ENDDO BODY_3
1534 ENDIF
1535 ENDIF
1536 FIRSTHEADER = .FALSE.
1537 ENDDO HEADER
1538
1539 IF (LFIRST) THEN
1540 deallocate( RSTV )
1541 deallocate( AZMV )
1542 deallocate( H )
1543
1544 deallocate(zVV)
1545 deallocate(zUU)
1546 deallocate(zHT)
1547 deallocate(zHU)
1548 deallocate(zTT)
1549 deallocate(zDP)
1550 deallocate(zPP)
1551 ENDIF
1552
1553 WRITE(*,*)'EXIT SETFGEDIFF'
1554 end subroutine setfgedif
1555
1556 !--------------------------------------------------------------------------
1557 ! setfgegps
1558 !--------------------------------------------------------------------------
1559 subroutine setfgegps(column,columnTrlOnAnlIncLev,lobsSpaceData)
1560 !
1561 !:Purpose: To set FGE for all GPS ZTD observations using Jacobians from ZTD
1562 ! observation operator
1563 !
1564 !:Option: Test ZTD operators (compares H(x+dx)-H(x) with (dH/dx)*dx
1565 ! when gps_gb_LTESTOP = .true.)
1566 !
1567 !:Note:
1568 ! _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
1569 ! 9 October 2015
1570 !
1571 ! :NOTE: Effective Rev644M, this routine is no longer used!
1572 ! FGE for ZTD is no longer needed for background check.
1573 ! Routine is called only when gps_gb_LTESTOP=.true., in which
1574 ! case the operator test only is done.
1575 !
1576 ! _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
1577 !
1578 implicit none
1579
1580 ! Arguments:
1581 type(struct_columnData), intent(in) :: column
1582 type(struct_columnData), intent(in) :: columnTrlOnAnlIncLev
1583 type(struct_obs), intent(inout) :: lobsSpaceData
1584
1585 ! Locals:
1586 ! column contains background errors for control variables on model levels
1587 ! columnTrlOnAnlIncLev contains lo-res first guess profiles at obs locations
1588 type(struct_vco), pointer :: vco_anl
1589 REAL*8 ZLAT, Lat
1590 REAL*8 ZLON, Lon
1591 REAL*8, allocatable :: ZPP(:)
1592 REAL*8, allocatable :: ZDP(:)
1593 REAL*8, allocatable :: ZTT(:)
1594 REAL*8, allocatable :: ZHU(:)
1595 REAL*8, allocatable :: zHeight(:)
1596 REAL*8, allocatable :: zHeight2(:)
1597 REAL*8, allocatable :: ZTTB(:)
1598 REAL*8, allocatable :: ZHUB(:)
1599 REAL*8, allocatable :: ZQQB(:)
1600 REAL*8, allocatable :: ZQQ(:)
1601 REAL*8, allocatable :: ZTTB_P(:)
1602 REAL*8, allocatable :: ZQQB_P(:)
1603 REAL*8, allocatable :: zHeight_P(:)
1604 REAL*8, allocatable :: ZPP_P(:)
1605 REAL*8 ZP0
1606 REAL*8 ZP0B, ZP0B_P
1607 REAL*8 ZMT, ZTOP, ZBOT
1608 REAL*8 JAC(gps_ncvmx)
1609 REAL*8 DX (gps_ncvmx)
1610 REAL*8 ZLEV, ZTDOBS, ZPSMOD
1611 REAL*8 ZLSUM
1612 REAL*8 DELTAH_NL, DELTAH_TL
1613 REAL*8 PERTFAC, ZTDM
1614 REAL*8 ZDZMIN, ZSUMTEST
1615 INTEGER INDEX_HEADER, FIRST_HEADER
1616 INTEGER IDATYP, ITYP
1617 INTEGER IDATA, IDATEND, INDEX_BODY
1618 INTEGER JL, NFLEV_T, ILYR, IOBS
1619 INTEGER INOBS_OPT, INOBS_JAC, icount, iversion
1620 LOGICAL ASSIM, OK, LSTAG
1621 CHARACTER*9 STN_JAC
1622 character(len=12) :: stnid
1623 CHARACTER(len=4) :: varLevel
1624 TYPE(GPS_PROFILEZD) :: PRF, PRFP
1625 TYPE(GPS_DIFF) :: ZTDopv, ZTDopvP
1626 real*8, dimension(:), pointer :: dPdPs
1627
1628 IF (gps_gb_numZTD .EQ. 0) RETURN
1629
1630 ! Initializations
1631
1632 nullify(dPdPs)
1633
1634 NFLEV_T = col_getNumLev(columnTrlOnAnlIncLev,'TH')
1635 allocate(ZPP(NFLEV_T))
1636 allocate(ZDP(NFLEV_T))
1637 allocate(ZTT(NFLEV_T))
1638 allocate(ZHU(NFLEV_T))
1639 allocate(zHeight(NFLEV_T))
1640 allocate(ZTTB(NFLEV_T))
1641 allocate(ZHUB(NFLEV_T))
1642 allocate(ZQQB(NFLEV_T))
1643 allocate(ZQQ(NFLEV_T))
1644
1645 ! Number of locations/sites for observation operator test
1646 INOBS_OPT = 50
1647 ! Number of locations/sites for Jacobian printout
1648 INOBS_JAC = 5
1649 ! Factor to multiply background errors for perturbation vector
1650 PERTFAC = 0.75d0
1651
1652 STN_JAC = 'FSL_BRFT '
1653
1654 ZDZMIN = gps_gb_DZMIN
1655
1656 vco_anl => col_getVco(columnTrlOnAnlIncLev)
1657 iversion = vco_anl%Vcode
1658 if (iversion .eq. 5002) then
1659 LSTAG = .TRUE.
1660 WRITE(*,*)'VERTICAL COORD OF ANALYSIS FIELDS IS STAGGERED'
1661 WRITE(*,*)'VCODE= ',iversion,' LSTAG= ',LSTAG
1662 else
1663 LSTAG = .FALSE.
1664 WRITE(*,*)'VERTICAL COORD OF ANALYSIS FIELDS IS NOT STAGGERED'
1665 WRITE(*,*)'VCODE= ',iversion,' LSTAG= ',LSTAG
1666 endif
1667
1668 IF ( .NOT.gps_gb_LTESTOP ) THEN
1669
1670 first_header=-1
1671 icount = 0
1672
1673 ! loop over all header indices of the 'GP' family
1674 call obs_set_current_header_list(lobsSpaceData,'GP')
1675 HEADER: do
1676 index_header = obs_getHeaderIndex(lobsSpaceData)
1677 if (index_header < 0) exit HEADER
1678 if (first_header .eq. -1) first_header = index_header
1679
1680 ! Process only zenith delay data (codtyp 189 and BUFR_NEZD)
1681
1682 IDATYP = obs_headElem_i(lobsSpaceData,OBS_ITY,INDEX_HEADER)
1683 IF ( IDATYP .EQ. 189 ) THEN
1684
1685 ! Loop over data in the observations
1686
1687 IDATA = obs_headElem_i(lobsSpaceData,OBS_RLN,INDEX_HEADER)
1688 IDATEND = obs_headElem_i(lobsSpaceData,OBS_NLV,INDEX_HEADER) + IDATA - 1
1689 ASSIM = .FALSE.
1690
1691 ! Scan for requested assimilations, and count them.
1692
1693 DO INDEX_BODY= IDATA, IDATEND
1694 ITYP = obs_bodyElem_i(lobsSpaceData,OBS_VNM,INDEX_BODY)
1695 OK = ( (ITYP .EQ. BUFR_NEZD) .AND. (obs_bodyElem_i(lobsSpaceData,OBS_ASS,INDEX_BODY) == obs_assimilated) )
1696 IF ( OK ) THEN
1697 ASSIM = .TRUE.
1698 ZLEV = obs_bodyElem_r(lobsSpaceData,OBS_PPP,INDEX_BODY)
1699 icount = icount + 1
1700 ENDIF
1701 ENDDO
1702
1703 ! If assimilations are requested, apply the AD observation operator
1704
1705 IF (ASSIM) THEN
1706
1707 ! LR background profile and background errors at the observation location x :
1708
1709 Lat = obs_headElem_r(lobsSpaceData,OBS_LAT,INDEX_HEADER)
1710 Lon = obs_headElem_r(lobsSpaceData,OBS_LON,INDEX_HEADER)
1711 ZLAT = Lat * MPC_DEGREES_PER_RADIAN_R8
1712 ZLON = Lon * MPC_DEGREES_PER_RADIAN_R8
1713 ZP0B = col_getElem(columnTrlOnAnlIncLev,1,INDEX_HEADER,'P0')
1714 DO JL = 1, NFLEV_T
1715 ZPP(JL) = col_getPressure(columnTrlOnAnlIncLev,JL,INDEX_HEADER,'TH')
1716 ZTTB(JL) = col_getElem(columnTrlOnAnlIncLev,JL,INDEX_HEADER,'TT')- 273.15d0
1717 ZTT(JL) = col_getElem(column,JL,INDEX_HEADER,'TT')
1718 DX(JL) = ZTT(JL)
1719 ZHUB(JL) = col_getElem(columnTrlOnAnlIncLev,JL,INDEX_HEADER,'HU')
1720 ZQQB(JL) = ZHUB(JL)
1721 ZHU(JL) = col_getElem(column,JL,INDEX_HEADER,'HU')
1722 DX(NFLEV_T+JL) = ZHU(JL)
1723 zHeight(JL) = col_getHeight(columnTrlOnAnlIncLev,JL,INDEX_HEADER,'TH')
1724 DX(2*NFLEV_T+JL) = col_getHeight(column,JL,INDEX_HEADER,'TH')
1725 ENDDO
1726 ZP0 = col_getElem(column,1,INDEX_HEADER,'P0')
1727 DX(3*NFLEV_T+1) = ZP0
1728 ZMT = zHeight(NFLEV_T)
1729 CALL gps_structztd_v2(NFLEV_T,Lat,Lon,ZMT,ZP0B,ZPP,ZTTB,ZHUB,zHeight,gps_gb_LBEVIS,gps_gb_IREFOPT,PRF)
1730 CALL gps_ztdopv(ZLEV,PRF,gps_gb_LBEVIS,ZDZMIN,ZTDopv,ZPSMOD,gps_gb_IZTDOP)
1731 JAC = ZTDopv%DVar
1732
1733 DO INDEX_BODY= IDATA, IDATEND
1734 ITYP = obs_bodyElem_i(lobsSpaceData,OBS_VNM,INDEX_BODY)
1735 IF ( obs_bodyElem_i(lobsSpaceData,OBS_ASS,INDEX_BODY) == obs_assimilated .AND. ITYP.EQ.BUFR_NEZD ) THEN
1736
1737 ! Observation error SDERR
1738 ! ZOER = obs_bodyElem_r(lobsSpaceData,OBS_PPP,INDEX_BODY)
1739
1740 ! Observation height (m)
1741 ZLEV = obs_bodyElem_r(lobsSpaceData,OBS_PPP,INDEX_BODY)
1742
1743 ZLSUM = 0.0d0
1744
1745 DO JL = 1, 3*NFLEV_T+1
1746 ZLSUM = ZLSUM + (JAC(JL)*DX(JL))**2
1747 ENDDO
1748 call obs_bodySet_r(lobsSpaceData,OBS_HPHT,index_body,SQRT(ZLSUM))
1749
1750 IF (icount .LE. INOBS_JAC) THEN
1751 ! IF ( obs_elem_c(lobsSpaceData,'STID',INDEX_HEADER) .EQ. STN_JAC ) THEN
1752 stnid = obs_elem_c(lobsSpaceData,'STID',INDEX_HEADER)
1753 WRITE(*,'(A11,A9)') 'SETFGEGPS: ', stnid
1754 WRITE(*,*) ' ZTD, ZTD FGE = ', ZTDopv%Var, SQRT(ZLSUM)
1755 WRITE(*,'(A11,A9,3(1x,f7.2))') &
1756 'SETFGEGPS: ',stnid,ZLAT,ZLON,ZLEV
1757 WRITE(*,*) 'JL JACT JACQ FGE_T FGE_LQ QQ'
1758 DO JL = 1, NFLEV_T
1759 WRITE(*,'(1X,I2,5(1x,E13.6))') JL,JAC(JL),JAC(JL+NFLEV_T)/ZQQB(JL),ZTT(JL),ZHU(JL),ZQQB(JL)
1760 ENDDO
1761 WRITE(*,*) 'JACPS FGE_PS'
1762 WRITE(*,'(2(1x,E13.6))') JAC(3*NFLEV_T+1), ZP0
1763 ENDIF
1764
1765 ENDIF
1766 ENDDO
1767 ENDIF
1768 ENDIF
1769
1770 ENDDO HEADER
1771
1772 ENDIF
1773
1774 !-------------------------------------------------------------------------
1775
1776 IF ( gps_gb_LTESTOP ) THEN
1777
1778 allocate(ZTTB_P(NFLEV_T))
1779 allocate(ZQQB_P(NFLEV_T))
1780 allocate(zHeight2(NFLEV_T))
1781 allocate(zHeight_P(NFLEV_T))
1782 allocate(ZPP_P(NFLEV_T))
1783
1784 icount = 0
1785 ZSUMTEST = 0
1786
1787 ! loop over all header indices of the 'GP' family
1788 call obs_set_current_header_list(lobsSpaceData,'GP')
1789 HEADER2: DO
1790 index_header = obs_getHeaderIndex(lobsSpaceData)
1791 if (index_header < 0) exit HEADER2
1792 if (icount > INOBS_OPT ) exit HEADER2
1793
1794 ! Loop over data in the observations
1795
1796 IDATA = obs_headElem_i(lobsSpaceData,OBS_RLN,INDEX_HEADER)
1797 IDATEND = obs_headElem_i(lobsSpaceData,OBS_NLV,INDEX_HEADER) + IDATA - 1
1798
1799 ! LR background profile and background errors at the observation location x :
1800
1801 Lat = obs_headElem_r(lobsSpaceData,OBS_LAT,INDEX_HEADER)
1802 Lon = obs_headElem_r(lobsSpaceData,OBS_LON,INDEX_HEADER)
1803 ZLAT = Lat * MPC_DEGREES_PER_RADIAN_R8
1804 ZLON = Lon * MPC_DEGREES_PER_RADIAN_R8
1805 ZP0B = col_getElem(columnTrlOnAnlIncLev,1,INDEX_HEADER,'P0')
1806
1807 ! approximation for dPdPs
1808 if (associated(dPdPs)) then
1809 deallocate(dPdPs)
1810 end if
1811 call czp_fetch1DdPdPs(vco_anl, ZP0B, profT_opt=dPdPs)
1812 zDP(1:NFLEV_T) = dPdPs(1:NFLEV_T)
1813
1814 DO JL = 1, NFLEV_T
1815 ZPP(JL) = col_getPressure(columnTrlOnAnlIncLev,JL,INDEX_HEADER,'TH')
1816 ZTTB(JL) = col_getElem(columnTrlOnAnlIncLev,JL,INDEX_HEADER,'TT')- 273.15d0
1817 ZTT(JL) = col_getElem(column,JL,INDEX_HEADER,'TT') * PERTFAC
1818 ZQQB(JL) = col_getElem(columnTrlOnAnlIncLev,JL,INDEX_HEADER,'HU')
1819 ZQQ(JL) = col_getElem(column,JL,INDEX_HEADER,'HU') * PERTFAC
1820 zHeight(JL) = col_getHeight(columnTrlOnAnlIncLev,JL,INDEX_HEADER,'TH')
1821 zHeight2(JL) = col_getHeight(column,JL,INDEX_HEADER,'TH') * PERTFAC
1822 ENDDO
1823 ZP0 = col_getElem(column,1,INDEX_HEADER,'P0') * PERTFAC
1824 ZMT = zHeight(NFLEV_T)
1825
1826 DO JL = 1, NFLEV_T
1827 DX ( JL) = ZTT(JL)
1828 DX (NFLEV_T+JL) = ZQQ(JL)
1829 DX (2*NFLEV_T+JL) = zHeight2(JL)
1830 ENDDO
1831 DX (3*NFLEV_T+1) = ZP0
1832
1833 ZTDOBS = -1.0d0
1834 DO INDEX_BODY = IDATA, IDATEND
1835 ITYP = obs_bodyElem_i(lobsSpaceData,OBS_VNM,INDEX_BODY)
1836 IOBS = obs_bodyElem_i(lobsSpaceData,OBS_HIND,INDEX_BODY)
1837 IF ( obs_bodyElem_i(lobsSpaceData,OBS_ASS,INDEX_BODY) == obs_assimilated .AND. ITYP .EQ. BUFR_NEZD ) THEN
1838 varLevel = vnl_varLevelFromVarnum(ITYP)
1839 ZTDOBS = obs_bodyElem_r(lobsSpaceData,OBS_VAR,INDEX_BODY)
1840 ZLEV = obs_bodyElem_r(lobsSpaceData,OBS_PPP,INDEX_BODY)
1841 ILYR = obs_bodyElem_i(lobsSpaceData,OBS_LYR,INDEX_BODY)
1842 ZTOP = col_getHeight(columnTrlOnAnlIncLev,ILYR,IOBS,varLevel)
1843 if ( ILYR .LT. NFLEV_T ) then
1844 ZBOT = col_getHeight(columnTrlOnAnlIncLev,ILYR+1,IOBS,varLevel)
1845 else
1846 ZBOT = ZTOP
1847 endif
1848 icount = icount + 1
1849 ENDIF
1850 ENDDO
1851
1852 IF ( ZTDOBS .GT. 0.d0 ) THEN
1853 ! Create the pertubation control vector
1854 DO JL = 1, NFLEV_T
1855 ZPP_P(JL) = ZPP(JL) + ZDP(JL)*ZP0
1856 ZTTB_P(JL) = ZTTB(JL) + ZTT(JL)
1857 ZQQB_P(JL) = ZQQB(JL) + ZQQ(JL)
1858 zHeight_P(JL) = zHeight(JL) + zHeight2(JL)
1859 ENDDO
1860 ZP0B_P = ZP0B + ZP0
1861
1862 ! Non-linear observation operator --> delta_H = H(x+delta_x) - H(x)
1863
1864 CALL gps_structztd_v2(NFLEV_T,Lat,Lon,ZMT,ZP0B,ZPP,ZTTB,ZQQB,zHeight,gps_gb_LBEVIS,gps_gb_IREFOPT,PRF)
1865 CALL gps_structztd_v2(NFLEV_T,Lat,Lon,ZMT,ZP0B_P,ZPP_P,ZTTB_P,ZQQB_P,zHeight_P,gps_gb_LBEVIS,gps_gb_IREFOPT,PRFP)
1866 CALL gps_ztdopv(ZLEV,PRF,gps_gb_LBEVIS,ZDZMIN,ZTDopv,ZPSMOD,gps_gb_IZTDOP)
1867 JAC = ZTDopv%DVar
1868 ZTDM = ZTDopv%Var
1869 CALL gps_ztdopv(ZLEV,PRFP,gps_gb_LBEVIS,ZDZMIN,ZTDopvP,ZPSMOD,gps_gb_IZTDOP)
1870 DELTAH_NL = ZTDopvP%Var - ZTDopv%Var
1871
1872 ! Linear --> delta_H = dH/dx * delta_x
1873
1874 DELTAH_TL = 0.0d0
1875 DO JL = 1, 3*NFLEV_T+1
1876 DELTAH_TL = DELTAH_TL + JAC(JL)*DX(JL)
1877 ENDDO
1878
1879 stnid = obs_elem_c(lobsSpaceData,'STID',INDEX_HEADER)
1880 WRITE(*,*) 'SETFGEGPS: GPS ZTD OBSOP TEST FOR SITE ', stnid
1881 WRITE(*,*) ' '
1882 WRITE(*,*) ' DZ (M), MODEL LEVEL ABOVE = ', ZLEV-ZMT, ILYR
1883 WRITE(*,*) ' ZLEV (M), ZTOP (M), ZBOT (M) = ', ZLEV, ZTOP, ZBOT
1884 WRITE(*,*) ' ZTD OBS (MM) = ', ZTDOBS*1000.d0
1885 WRITE(*,*) ' ZTD_MOD = ', ZTDM*1000.d0
1886 WRITE(*,*) ' DELTAH_NL, DELTAH_TL = ', DELTAH_NL*1000.d0, DELTAH_TL*1000.d0
1887 WRITE(*,*) ' '
1888 WRITE(*,*) ' DELTAH_TL/DELTAH_NL = ', DELTAH_TL/DELTAH_NL
1889 WRITE(*,*) ' '
1890
1891 ZSUMTEST = ZSUMTEST + (DELTAH_TL/DELTAH_NL)
1892
1893 ENDIF
1894
1895 ENDDO HEADER2
1896
1897 WRITE(*,*) ' '
1898 WRITE(*,*) 'SETFGEGPS: ----- GPS ZTD OBSOP TEST SUMMARY -----'
1899 WRITE(*,*) ' NUMBER OF TESTS (sites) = ', icount
1900 WRITE(*,*) ' AVG DELTAH_TL/DELTAH_NL = ', ZSUMTEST/FLOAT(icount)
1901 WRITE(*,*) ' '
1902
1903 deallocate(ZTTB_P)
1904 deallocate(ZQQB_P)
1905 deallocate(zHeight2)
1906 deallocate(zHeight_P)
1907 deallocate(ZPP_P)
1908
1909 ENDIF
1910 !-------------------------------------------------------------------------
1911
1912 deallocate(ZPP)
1913 deallocate(ZDP)
1914 deallocate(ZTT)
1915 deallocate(ZHU)
1916 deallocate(zHeight)
1917 deallocate(ZTTB)
1918 deallocate(ZHUB)
1919 deallocate(ZQQB)
1920 deallocate(ZQQ)
1921
1922 end subroutine setfgegps
1923
1924 !------------------ CH obs family OmP error std dev routines --------------
1925
1926 !--------------------------------------------------------------------------
1927 ! ose_setOmPstddevCH
1928 !--------------------------------------------------------------------------
1929 character(len=4) function ose_setOmPstddevCH(obsSpaceData) result(availableOMPE)
1930 !
1931 !:Purpose: To read OmP error std dev from auxiliary file or calculate from OmP.
1932 !
1933 implicit none
1934
1935 ! Arguments:
1936 type(struct_obs), intent(inout) :: obsSpaceData ! observation-space data; output saved in OBS_OMPE column
1937
1938 ! Locals:
1939 integer, parameter :: ndim=1
1940
1941 ! Check for the presence of CH observations
1942 availableOMPE = ' '
1943 if ( .not.obs_famExist(obsSpaceData,'CH',localMPI_opt=.true.) ) return
1944
1945 ! read the OmP error std. dev. information from the auxiliary file
1946 call ose_readOmPstddev_auxfileCH
1947
1948 availableOMPE='None'
1949 if ( OmPstdCH%n_stnid == 0 ) return ! All CH family OBS_OMPE to be estimated elsewhere via use of OBS_HPHT and OBS_OER
1950
1951 ! Calc from the OmP dataset if requested (and there is enough data)
1952 if ( any(OmPstdCH%source(1:OmPstdCH%n_stnid) == 1) ) call ose_calcOmPstddevCH(obsSpaceData)
1953
1954 ! Assign OmP error std dev values to OBS_OMPE for CH family
1955 if ( any(OmPstdCH%source(1:OmPstdCH%n_stnid) <= 1) ) call ose_fillOmPstddevCH(obsSpaceData)
1956
1957 ! Deallocate OmPstdCH space
1958 call ose_deallocOmPstddevCH
1959
1960 ! Check if ALL CH family obs have been assigned usable values in OBS_OMPE
1961 if ( .not. ose_OmPstddevExistsForAllCH(ObsSpaceData) ) then
1962 ! For some obs, need to calc OBS_HPHT to get OBS_OMPE
1963 availableOMPE='Some'
1964 else
1965 ! All OBS_OMPE are available
1966 availableOMPE='All '
1967 end if
1968
1969 end function ose_setOmPstddevCH
1970
1971 !--------------------------------------------------------------------------
1972 ! ose_readOmPstddev_auxfileCH
1973 !--------------------------------------------------------------------------
1974 subroutine ose_readOmPstddev_auxfileCH
1975 !
1976 !:Purpose: To read and store OmP error std. dev. as needed for CH
1977 ! family obs - if/when available.
1978 !
1979 implicit none
1980
1981 ! Locals:
1982 integer, external :: fnom, fclos
1983 integer :: ierr, nulstat
1984 logical :: LnewExists
1985 character (len=128) :: ligne
1986 character(len=11) :: AuxObsDataFileCH = 'obsinfo_chm'
1987 integer :: ipos, stnidIndex, monthIndex, levIndex, ios, isize, icount
1988 character(len=20) :: abortText
1989
1990 ! Initialization
1991
1992 OmPstdCH%n_stnid=0
1993
1994 ! Check the existence of the text file with statistics
1995
1996 INQUIRE(FILE=trim(AuxObsDataFileCH),EXIST=LnewExists)
1997 if (.not.LnewExists) then
1998 WRITE(*,*) '-----------------------------------------------------------------------------'
1999 WRITE(*,*) 'WARNING! ose_readOmPstddev_auxfileCH: auxiliary file ' // trim(AuxObsDataFileCH)
2000 WRITE(*,*) 'WARNING! not available. Default CH family OmP stddev to be applied if needed.'
2001 WRITE(*,*) '-----------------------------------------------------------------------------'
2002 return
2003 end if
2004
2005 ! Read error std dev. from file auxiliary file for constituent data
2006
2007 nulstat=0
2008 ierr=fnom(nulstat,trim(AuxObsDataFileCH),'SEQ',0)
2009 if ( ierr == 0 ) then
2010 open(unit=nulstat, file=trim(AuxObsDataFileCH), status='OLD')
2011 else
2012 call utl_abort('ose_readOmPstddev_auxfileCH: COULD NOT OPEN AUXILIARY FILE ' // trim(AuxObsDataFileCH) )
2013 end if
2014
2015 ! Read OmP error standard deviations for constituents or related directives if available.
2016
2017 ios=0
2018 read(nulstat,'(A)',iostat=ios,err=10,end=10) ligne
2019 do while (trim(adjustl(ligne(1:12))) /= 'SECTION V:')
2020 read(nulstat,'(A)',iostat=ios,err=10,end=15) ligne
2021 end do
2022
2023 ! Read number of observation set sub-families (STNIDs and ...) and allocate space
2024
2025 read(nulstat,*,iostat=ios,err=10,end=10) OmPstdCH%n_stnid
2026 read(nulstat,*,iostat=ios,err=10,end=10) isize
2027
2028 allocate(OmPstdCH%stnids(OmPstdCH%n_stnid),OmPstdCH%std_type(OmPstdCH%n_stnid))
2029 allocate(OmPstdCH%n_month(OmPstdCH%n_stnid),OmPstdCH%n_lat(OmPstdCH%n_stnid))
2030 allocate(OmPstdCH%source(OmPstdCH%n_stnid),OmPstdCH%ibegin(OmPstdCH%n_stnid))
2031 allocate(OmPstdCH%element(OmPstdCH%n_stnid),OmPstdCH%n_lvl(OmPstdCH%n_stnid))
2032 allocate(OmPstdCH%std(isize))
2033 allocate(OmPstdCH%levels(isize),OmPstdCH%lat(isize),OmPstdCH%month(isize))
2034
2035 OmPstdCH%element(:)=0
2036 OmPstdCH%source(:)=0
2037 OmPstdCH%std_type(:)=0
2038 OmPstdCH%n_lvl(:)=1
2039 OmPstdCH%n_lat(:)=1
2040 OmPstdCH%n_month(:)=1
2041
2042 ! Begin reading for each sub-family
2043 ! Important: Combination of STNID, BUFR element and number of vertical levels
2044 ! to determine association to the observations.
2045
2046 icount=0
2047 STNIDLOOP: do stnidIndex=1,OmPstdCH%n_stnid
2048
2049 ! disregard line of dashes
2050 read(nulstat,'(A)',iostat=ios,err=10,end=10) ligne
2051
2052 ! Read STNID (* as wildcard)
2053 read(nulstat,'(2X,A9)',iostat=ios,err=10,end=10) OmPstdCH%stnids(stnidIndex)
2054
2055 ! Read (1) BUFR element
2056 ! (2) Flag indication if OmP error std dev provided from this auxiliary file or
2057 ! to be calculated via OmP differences or HPHT
2058 ! (3) Type of input/set std dev
2059 ! (4) Number of vertical levels
2060 ! (5) Number of latitudes
2061 ! (6) Number of months
2062 !
2063 ! Important: Combination of STNID and BUFR element
2064 ! to determine association to the observations.
2065
2066 read(nulstat,*,iostat=ios,err=10,end=10) &
2067 OmPstdCH%element(stnidIndex),OmPstdCH%source(stnidIndex), &
2068 OmPstdCH%std_type(stnidIndex),OmPstdCH%n_lvl(stnidIndex), &
2069 OmPstdCH%n_lat(stnidIndex),OmPstdCH%n_month(stnidIndex)
2070
2071 if ( OmPstdCH%n_lvl(stnidIndex) < 1 ) OmPstdCH%n_lvl(stnidIndex)=1
2072 if ( OmPstdCH%n_lat(stnidIndex) < 1 ) OmPstdCH%n_lat(stnidIndex)=1
2073 if ( OmPstdCH%n_month(stnidIndex) < 1 ) OmPstdCH%n_month(stnidIndex)=1
2074
2075 if ( icount+OmPstdCH%n_lvl(stnidIndex)*OmPstdCH%n_lat(stnidIndex)*OmPstdCH%n_month(stnidIndex) > isize ) then
2076 write(*,'(10X,"Max array size exceeded: ",I6)') isize
2077 CALL utl_abort('ose_readOmPstddev_auxfileHCHin: PROBLEM READING OBSERR STD DEV.')
2078 else if ( OmPstdCH%n_lat(stnidIndex) == 1 .and. OmPstdCH%n_month(stnidIndex) > 1 ) then
2079 write(*,'(10X,"Fails for stnid number: ",I6)') stnidIndex
2080 CALL utl_abort('ose_readOmPstddev_auxfileHCHin: Cannot depend on month if not dependent on latitude')
2081 else if ( OmPstdCH%n_month(stnidIndex) /= 1 .and. OmPstdCH%n_month(stnidIndex) /= 12 ) then
2082 write(*,'(10X,"Fails for stnid number: ",I6)') stnidIndex
2083 CALL utl_abort('ose_readOmPstddev_auxfileHCHin: Number of months must be 1 or 12')
2084 end if
2085
2086 ! disregard line of dashes
2087 read(nulstat,'(A)',iostat=ios,err=10,end=10) ligne
2088
2089 if ( OmPstdCH%source(stnidIndex) > 1 ) then
2090 ! Disregard data section
2091 OmPstdCH%ibegin(stnidIndex)=icount
2092 cycle STNIDLOOP
2093 else if ( OmPstdCH%source(stnidIndex) == 1 ) then
2094
2095 OmPstdCH%ibegin(stnidIndex)=icount+1
2096
2097 ! Only reference vertical levels and latitudes to be determined
2098 ! For use in determining error std dev from OmPs of current processing window
2099
2100 OmPstdCH%n_month(stnidIndex) = 1
2101 if ( OmPstdCH%n_lvl(stnidIndex) == 1 .and. OmPstdCH%n_lat(stnidIndex) == 1 ) then
2102
2103 icount=icount+1
2104
2105 else if ( OmPstdCH%n_lvl(stnidIndex) == 1 .and. OmPstdCH%n_lat(stnidIndex) > 1 ) then
2106
2107 ! Read reference latitudes (must be in order of increasing size)
2108
2109 read(nulstat,*,iostat=ios,err=10,end=10) &
2110 OmPstdCH%lat(icount+1:icount+OmPstdCH%n_lat(stnidIndex))
2111 icount=icount+OmPstdCH%n_lat(stnidIndex)
2112
2113 else if ( OmPstdCH%n_lvl(stnidIndex) > 1 .and. OmPstdCH%n_lat(stnidIndex) == 1 ) then
2114
2115 ! Read reference vertical levels (must be in order of increasing size)
2116
2117 read(nulstat,*,iostat=ios,err=10,end=10) &
2118 OmPstdCH%levels(icount+1:icount+OmPstdCH%n_lvl(stnidIndex))
2119 icount=icount+OmPstdCH%n_lvl(stnidIndex)
2120
2121 else
2122
2123 ! Read reference latitudes (must be in order of increasing size)
2124 read(nulstat,*,iostat=ios,err=10,end=10) &
2125 OmPstdCH%lat(icount+1:icount+OmPstdCH%n_lat(stnidIndex))
2126
2127 ! Read reference vertical levels (must be in order of increasing size)
2128 read(nulstat,*,iostat=ios,err=10,end=10) &
2129 OmPstdCH%levels(icount+1:icount+OmPstdCH%n_lvl(stnidIndex))
2130
2131 icount=icount+OmPstdCH%n_lvl(stnidIndex)*OmPstdCH%n_lat(stnidIndex)
2132
2133 end if
2134
2135 cycle STNIDLOOP
2136
2137 end if
2138
2139 ! For OmPstdCH%source(stnidIndex) == 0
2140
2141 OmPstdCH%ibegin(stnidIndex)=icount+1
2142 if ( OmPstdCH%n_lvl(stnidIndex) == 1 .and. OmPstdCH%n_lat(stnidIndex) == 1 ) then
2143
2144 ! Read one value only (independent of level and latitude)
2145 ! Assumes one month only.
2146
2147 read(nulstat,*,iostat=ios,err=10,end=10) OmPstdCH%std(icount+1)
2148 icount=icount+1
2149
2150 else if ( OmPstdCH%n_lvl(stnidIndex) == 1 .and. OmPstdCH%n_lat(stnidIndex) > 1 ) then
2151
2152 ! Value dependent on latitude
2153
2154 ! Read reference latitudes (must be in order of increasing size)
2155
2156 read(nulstat,*,iostat=ios,err=10,end=10) &
2157 OmPstdCH%lat(icount+1:icount+OmPstdCH%n_lat(stnidIndex))
2158
2159 ! Read OMP error std dev related values
2160
2161 if ( OmPstdCH%n_month(stnidIndex) == 1 ) then
2162
2163 read(nulstat,*,iostat=ios,err=10,end=10) &
2164 OmPstdCH%std(icount+1:icount+OmPstdCH%n_lat(stnidIndex))
2165
2166 else
2167
2168 do monthIndex=1,OmPstdCH%n_month(stnidIndex)
2169
2170 ! Read reference month (must be in order of increasing size)
2171 read(nulstat,*,iostat=ios,err=10,end=10) OmPstdCH%month(icount+monthIndex)
2172
2173 ipos=icount+(monthIndex-1)*OmPstdCH%n_lat(stnidIndex)
2174
2175 read(nulstat,*,iostat=ios,err=10,end=10) &
2176 OmPstdCH%std(ipos+1:ipos+OmPstdCH%n_lat(stnidIndex))
2177 end do
2178
2179 end if
2180
2181 icount = icount + OmPstdCH%n_lat(stnidIndex)*OmPstdCH%n_month(stnidIndex)
2182
2183 else if ( OmPstdCH%n_lvl(stnidIndex) > 1 .and. OmPstdCH%n_lat(stnidIndex) == 1 ) then
2184
2185 ! Value dependent on vertical level and not latitude
2186
2187 if ( OmPstdCH%n_month(stnidIndex) == 1 ) then
2188
2189 do levIndex=1,OmPstdCH%n_lvl(stnidIndex)
2190 icount=icount+1
2191
2192 ! Read vertical level and OMP error std dev related value.
2193
2194 read(nulstat,*,iostat=ios,err=10,end=10) &
2195 OmPstdCH%levels(icount),OmPstdCH%std(icount)
2196
2197 end do
2198
2199 else
2200
2201 do monthIndex=1,OmPstdCH%n_month(stnidIndex)
2202
2203 ! Read reference month (must be in order of increasing size)
2204 read(nulstat,*,iostat=ios,err=10,end=10) OmPstdCH%month(icount+monthIndex)
2205
2206 ipos=icount+(monthIndex-1)*OmPstdCH%n_lvl(stnidIndex)
2207
2208 read(nulstat,*,iostat=ios,err=10,end=10) &
2209 OmPstdCH%std(ipos+1:ipos+OmPstdCH%n_lvl(stnidIndex))
2210 end do
2211
2212 end if
2213
2214 icount = icount + OmPstdCH%n_lvl(stnidIndex)*OmPstdCH%n_month(stnidIndex)
2215
2216 else if ( OmPstdCH%n_lvl(stnidIndex) > 1 .and. OmPstdCH%n_lat(stnidIndex) > 1 ) then
2217
2218 ! Value dependent on vertical level and latitude
2219
2220 ! Read reference latitudes (must be in order of increasing size)
2221 read(nulstat,*,iostat=ios,err=10,end=10) &
2222 OmPstdCH%lat(icount+1:icount+OmPstdCH%n_lat(stnidIndex))
2223
2224 if ( OmPstdCH%n_month(stnidIndex) == 1 ) then
2225
2226 do levIndex=1,OmPstdCH%n_lvl(stnidIndex)
2227
2228 ! Read vertical level and OMP error std dev related lat-dependent values.
2229
2230 read(nulstat,*,iostat=ios,err=10,end=10) &
2231 OmPstdCH%levels(icount+levIndex), &
2232 OmPstdCH%std(icount+(levIndex-1)* &
2233 OmPstdCH%n_lat(stnidIndex)+1:icount+levIndex*OmPstdCH%n_lat(stnidIndex))
2234
2235 end do
2236
2237 else
2238
2239 do monthIndex=1,OmPstdCH%n_month(stnidIndex)
2240
2241 ! Read reference month (must be in order of increasing size)
2242 read(nulstat,*,iostat=ios,err=10,end=10) OmPstdCH%month(icount+monthIndex)
2243
2244 ipos=icount+(monthIndex-1)*OmPstdCH%n_lat(stnidIndex)*OmPstdCH%n_lvl(stnidIndex)
2245
2246 do levIndex=1,OmPstdCH%n_lvl(stnidIndex)
2247
2248 ! Read vertical level and OMP error std dev related lat-dependent values.
2249
2250 read(nulstat,*,iostat=ios,err=10,end=10) &
2251 OmPstdCH%levels(icount+levIndex), &
2252 OmPstdCH%std(ipos+(levIndex-1)* &
2253 OmPstdCH%n_lat(stnidIndex)+1:ipos+levIndex*OmPstdCH%n_lat(stnidIndex))
2254
2255 end do
2256
2257 end do
2258
2259 end if
2260
2261 icount=icount+OmPstdCH%n_lat(stnidIndex)*OmPstdCH%n_lvl(stnidIndex)*OmPstdCH%n_month(stnidIndex)
2262 end if
2263 end do STNIDLOOP
2264
2265 10 if (ios.gt.0) then
2266 write(abortText,*) ios
2267 call utl_abort('ose_readOmPstddev_auxfileCHin: PROBLEM READING OMP ERR STD DEV. - ' // &
2268 'File read error message number: ' // trim(abortText) )
2269 end if
2270
2271 return
2272
2273 ! Reached end of file and no related section found.
2274
2275 15 OmPstdCH%n_stnid = 0
2276
2277 close(unit=nulstat)
2278 ierr=fclos(nulstat)
2279
2280 end subroutine ose_readOmPstddev_auxfileCH
2281
2282 !--------------------------------------------------------------------------
2283 ! ose_calcOmPstddevCH
2284 !--------------------------------------------------------------------------
2285 subroutine ose_calcOmPstddevCH(obsSpaceData)
2286 !
2287 !:Purpose: To calc OmP error std dev for some obs sets of the CH family
2288 !
2289 implicit none
2290
2291 ! Arguments:
2292 type(struct_obs), intent(inout) :: obsSpaceData ! observation-space data; output saved in OBS_OMPE column
2293
2294 ! Locals:
2295 logical :: availableOmP
2296 integer :: stnidIndex, headerIndex, bodyIndex, bodyIndex_start, bodyIndex_end, icodtyp, ierr
2297 integer :: idate, itime, iass, latIndex, levIndex, monthIndex, ibegin, loopIndex, posIndex
2298 real(8) :: zlat, zval, zlev, lat, sumOmP, sumSqrOmP, varOmP, maxOmP,meanOmP,medianOmP
2299 character(len=12) :: stnid
2300 real(8), allocatable :: series(:,:,:),sumOmP2d(:,:),sumSqrOmP2d(:,:)
2301 real(8), allocatable :: sumOmP2dt(:,:),sumSqrOmP2dt(:,:)
2302 integer, allocatable :: nSeries(:,:),nSeriest(:,:)
2303 integer, parameter :: maxCount = 10000
2304 integer, parameter :: minCount = 5
2305 real(8), parameter :: stdScale = 2.0
2306 real(8), parameter :: minVal = 1.0d-20
2307 real(4) :: rseries(maxCount)
2308 integer :: ip(maxCount)
2309
2310 ! Loop over all obs types
2311
2312 do stnidIndex=1,OmPstdCH%n_stnid
2313 ! Check if OBS_OMPE is to be estimated elsewhere via use of OBS_HPHT and OBS_OER
2314 ! instead of via ose_fillOmPstddevCH
2315 if ( OmPstdCH%source(stnidIndex) /= 1 ) cycle
2316
2317 write(*,*)
2318 write(*,*) 'ose_calcOmPstddevCH: Online calculation of OmP error std dev of CH family stnid ',OmPstdCH%stnids(stnidIndex)
2319 write(*,*)
2320
2321 ! Identify start position index (-1) in OmPstdCH
2322 ibegin=OmPstdCH%ibegin(stnidIndex)-1
2323
2324 allocate(series(OmPstdCH%n_lvl(stnidIndex),OmPstdCH%n_lat(stnidIndex),maxCount))
2325 allocate(nSeries(OmPstdCH%n_lvl(stnidIndex),OmPstdCH%n_lat(stnidIndex)))
2326 allocate(sumOmP2d(OmPstdCH%n_lvl(stnidIndex),OmPstdCH%n_lat(stnidIndex)))
2327 allocate(sumSqrOmP2d(OmPstdCH%n_lvl(stnidIndex),OmPstdCH%n_lat(stnidIndex)))
2328 nSeries(:,:)=0
2329 sumOmP2d(:,:)=0.0d0
2330 sumSqrOmP2d(:,:)=0.0d0
2331
2332 allocate(nSeriest(OmPstdCH%n_lvl(stnidIndex),OmPstdCH%n_lat(stnidIndex)))
2333 allocate(sumOmP2dt(OmPstdCH%n_lvl(stnidIndex),OmPstdCH%n_lat(stnidIndex)))
2334 allocate(sumSqrOmP2dt(OmPstdCH%n_lvl(stnidIndex),OmPstdCH%n_lat(stnidIndex)))
2335 nSeriest(:,:)=0
2336
2337 ! Loop over all header indices of the 'CH' family:
2338
2339 call obs_set_current_header_list(obsSpaceData,'CH')
2340 HEADER: do
2341
2342 headerIndex = obs_getHeaderIndex(obsSpaceData)
2343 if (headerIndex < 0) exit HEADER
2344
2345 icodtyp = obs_headElem_i(obsSpaceData,OBS_ITY,headerIndex)
2346 if (icodtyp.ne.codtyp_get_codtyp('CHEMREMOTE').and.icodtyp.ne.codtyp_get_codtyp('CHEMINSITU')) cycle HEADER
2347
2348 stnid = obs_elem_c(obsSpaceData,'STID',headerIndex)
2349 if ( .not. utl_stnid_equal(OmPstdCH%stnids(stnidIndex),stnid) ) cycle HEADER
2350
2351 bodyIndex_start = obs_headElem_i(obsSpaceData,OBS_RLN,headerIndex)
2352 bodyIndex_end = bodyIndex_start+obs_headElem_i(obsSpaceData,OBS_NLV,headerIndex)-1
2353
2354 ! Check OBS_VNM value.
2355 do bodyIndex=bodyIndex_start,bodyIndex_end
2356 if (obs_bodyElem_i(obsSpaceData,OBS_VNM,bodyIndex) /= BUFR_SCALE_EXPONENT) then
2357 if ( obs_bodyElem_i(obsSpaceData,OBS_VNM,bodyIndex) /= OmPstdCH%element(stnidIndex) ) cycle HEADER
2358 end if
2359 end do
2360
2361 zlat = obs_headElem_r( obsSpaceData, OBS_LAT, headerIndex )
2362 idate = obs_headElem_i( obsSpaceData, OBS_DAT, headerIndex )
2363 itime = obs_headElem_i( obsSpaceData, OBS_ETM, headerIndex )
2364
2365 ! Identify lat and month index
2366 if (OmPstdCH%n_lat(stnidIndex) == 1) then
2367 latIndex = 1
2368 else
2369
2370 ! Find latitude index for specifying the latitude bin
2371 ! Assuming increasing latitudes in OmPstdCH%lat
2372
2373 lat = zlat / MPC_RADIANS_PER_DEGREE_R8 ! radians to degrees
2374
2375 if (lat >= 0.5*(OmPstdCH%lat(ibegin+OmPstdCH%n_lat(stnidIndex)) &
2376 +OmPstdCH%lat(ibegin+OmPstdCH%n_lat(stnidIndex)-1)) ) then
2377 latIndex = OmPstdCH%n_lat(stnidIndex)
2378 else
2379 do latIndex=1,OmPstdCH%n_lat(stnidIndex)-1
2380 if (lat <= 0.5*(OmPstdCH%lat(ibegin+latIndex)+OmPstdCH%lat(ibegin+latIndex+1)) ) exit
2381 end do
2382 end if
2383 end if
2384
2385 if (OmPstdCH%n_month(stnidIndex) == 1) then
2386 monthIndex = 1
2387 else
2388 ! Find month index
2389 monthIndex=(idate-(idate/10000)*10000)/100
2390 end if
2391
2392 do bodyIndex=bodyIndex_start,bodyIndex_end
2393 if (obs_bodyElem_i(obsSpaceData,OBS_VNM,bodyIndex) == BUFR_SCALE_EXPONENT) cycle
2394
2395 iass = obs_bodyElem_i( obsSpaceData, OBS_ASS, bodyIndex )
2396 if ( iass /= obs_assimilated ) cycle
2397
2398 ! Identify vertical level
2399 zlev = obs_bodyElem_r( obsSpaceData, OBS_PPP, bodyIndex )
2400 if ( OmPstdCH%n_lvl(stnidIndex) == 1 ) then
2401 levIndex = 1
2402 else if ( OmPstdCH%levels(ibegin+1) < OmPstdCH%levels(ibegin+2) ) then
2403 if (zlev <= 0.5*(OmPstdCH%levels(ibegin+1)+OmPstdCH%levels(ibegin+2)) ) then
2404 levIndex = 1
2405 else
2406 do levIndex=OmPstdCH%n_lvl(stnidIndex),2,-1
2407 if ( zlev >= 0.5*(OmPstdCH%levels(ibegin+levIndex)+OmPstdCH%levels(ibegin+levIndex-1)) ) exit
2408 end do
2409 end if
2410 else
2411 if (zlev <= 0.5*(OmPstdCH%levels(ibegin+OmPstdCH%n_lvl(stnidIndex)) &
2412 +OmPstdCH%levels(ibegin+OmPstdCH%n_lvl(stnidIndex)-1)) ) then
2413 levIndex = OmPstdCH%n_lvl(stnidIndex)
2414 else
2415 do levIndex=1,OmPstdCH%n_lvl(stnidIndex)-1
2416 if ( zlev >= 0.5*(OmPstdCH%levels(ibegin+levIndex)+OmPstdCH%levels(ibegin+levIndex+1)) ) exit
2417 end do
2418 end if
2419 end if
2420
2421 ! Store OmP in work array
2422
2423 if ( OmPstdCH%std_type(stnidIndex) == 1 ) then
2424 zval = obs_bodyElem_r( obsSpaceData, OBS_VAR, bodyIndex )
2425 if ( zval > minVal ) then
2426 nSeries(levIndex,latIndex) = nSeries(levIndex,latIndex) + 1
2427 series(levIndex,latIndex,nSeries(levIndex,latIndex)) = obs_bodyElem_r( obsSpaceData, OBS_OMP, bodyIndex )/zval
2428 end if
2429 else
2430 nSeries(levIndex,latIndex) = nSeries(levIndex,latIndex) + 1
2431 series(levIndex,latIndex,nSeries(levIndex,latIndex)) = obs_bodyElem_r( obsSpaceData, OBS_OMP, bodyIndex )
2432 end if
2433 ! Check if enough data
2434 if ( nSeries(levIndex,latIndex) == maxCount ) exit
2435
2436 end do
2437
2438 end do HEADER
2439
2440 if ( any(nSeries > 0) ) then
2441
2442 ! Calc OmP error std dev
2443
2444 !write(*,*) 'latbin levbin Npts AvgOmP OmPStddev'
2445 do levIndex=1,OmPstdCH%n_lvl(stnidIndex)
2446 do latIndex=1,OmPstdCH%n_lat(stnidIndex)
2447 availableOmP=.true.
2448 if (nSeries(levIndex,latIndex) > minCount ) then
2449 rseries(1:nSeries(levIndex,latIndex))=series(levIndex,latIndex,1:nSeries(levIndex,latIndex))
2450 call ipsort(ip,rseries(1:nSeries(levIndex,latIndex)),nSeries(levIndex,latIndex))
2451 medianOmP=series(levIndex,latIndex,ip(nSeries(levIndex,latIndex)/2))
2452
2453 sumOmP = sum(series(levIndex,latIndex,1:nSeries(levIndex,latIndex)))
2454 meanOmP=sumOmP/nSeries(levIndex,latIndex)
2455 sumSqrOmP = sum(series(levIndex,latIndex,1:nSeries(levIndex,latIndex))*series(levIndex,latIndex,1:nSeries(levIndex,latIndex)))
2456 varOmP = sumSqrOmP/nSeries(levIndex,latIndex) - (sumOmP/nSeries(levIndex,latIndex))**2
2457 if (varOmP > minVal*minVal ) then
2458 do loopIndex=1,nSeries(levIndex,latIndex)
2459 maxOmP = stdScale*sqrt(varOmP)
2460 ! if ( abs(series(levIndex,latIndex,loopIndex)-meanOmP) > maxOmP ) then
2461 if ( abs(series(levIndex,latIndex,loopIndex)-medianOmP) > maxOmP ) then
2462 sumOmP = sumOmP - series(levIndex,latIndex,loopIndex)
2463 sumSqrOmP = sumSqrOmP - series(levIndex,latIndex,loopIndex)*series(levIndex,latIndex,loopIndex)
2464 nSeries(levIndex,latIndex) = nSeries(levIndex,latIndex) - 1
2465 end if
2466 end do
2467 varOmP = sumSqrOmP/nSeries(levIndex,latIndex) - (sumOmP/nSeries(levIndex,latIndex))**2
2468 !write(*,110) latIndex,levIndex,nSeries(levIndex,latIndex),sumOmP/nSeries(levIndex,latIndex),sqrt(varOmP)
2469 sumOmP2d(levIndex,latIndex)=sumOmP
2470 sumSqrOmP2d(levIndex,latIndex)=sumSqrOmP
2471 if (varOmP < minVal*minVal ) availableOmP = .false.
2472 else
2473 availableOmP = .false.
2474 end if
2475 else
2476 availableOmP = .false.
2477 end if
2478 if (.not.availableOmP) nSeries(levIndex,latIndex) = 0
2479 end do
2480 end do
2481 end if
2482
2483 ! Combine from all processors
2484
2485 call rpn_comm_allreduce(nSeries,nSeriest,OmPstdCH%n_lvl(stnidIndex)*OmPstdCH%n_lat(stnidIndex),"MPI_INTEGER","MPI_SUM","GRID",ierr)
2486 call rpn_comm_allreduce(sumOmP2d,sumOmP2dt,OmPstdCH%n_lvl(stnidIndex)*OmPstdCH%n_lat(stnidIndex),"MPI_DOUBLE_PRECISION","MPI_SUM","GRID",ierr)
2487 call rpn_comm_allreduce(sumSqrOmP2d,sumSqrOmP2dt,OmPstdCH%n_lvl(stnidIndex)*OmPstdCH%n_lat(stnidIndex),"MPI_DOUBLE_PRECISION","MPI_SUM","GRID",ierr)
2488
2489 if (any(nSeriest > 5*minCount)) then
2490
2491 where ( nSeriest > 5*minCount ) sumSqrOmP2dt = sumSqrOmP2dt/nSeriest - (sumOmP2dt/nSeriest)**2
2492
2493 if (mmpi_myid == 0) then
2494 write(*,*) 'Calculated OmP error std dev'
2495 write(*,*) 'latbin levbin Npts AvgOmP OmPStddev'
2496 end if
2497 do levIndex=1,OmPstdCH%n_lvl(stnidIndex)
2498 do latIndex=1,OmPstdCH%n_lat(stnidIndex)
2499 availableOmP=.true.
2500 if (nSeriest(levIndex,latIndex) > 5*minCount ) then
2501 varOmP = sumSqrOmP2dt(levIndex,latIndex)
2502 if (varOmP < minVal*minVal ) then
2503 availableOmP = .false.
2504 else
2505 if (mmpi_myid == 0 ) write(*,110) latIndex,levIndex,nSeriest(levIndex,latIndex),sumOmP2dt(levIndex,latIndex)/nSeriest(levIndex,latIndex),sqrt(varOmP)
2506 end if
2507 else
2508 availableOmP = .false.
2509 end if
2510
2511 ! Store in structure
2512
2513 ! Indentify position in structure
2514 if (OmPstdCH%n_lvl(stnidIndex) > 1) then
2515 posIndex=ibegin+(levIndex-1)*OmPstdCH%n_lat(stnidIndex)
2516 else
2517 posIndex=ibegin
2518 end if
2519
2520 if ( OmPstdCH%n_month(stnidIndex) == 1 ) then
2521 posIndex = posIndex + latIndex
2522 else
2523 posIndex = posIndex + (monthIndex-1)*OmPstdCH%n_lvl(stnidIndex)*OmPstdCH%n_lat(stnidIndex) + latIndex
2524 end if
2525
2526 if (availableOmP) then
2527 OmPstdCH%std(posIndex) = sqrt(varOmP)
2528 else
2529 OmPstdCH%std(posIndex) = MPC_missingValue_R8
2530 end if
2531
2532 end do
2533 end do
2534 end if
2535110 format(I5,I7,I7,3x,G11.3,G11.3)
2536
2537 deallocate(series,nSeries,sumOmP2d,sumSqrOmP2d)
2538 deallocate(nSeriest,sumOmP2dt,sumSqrOmP2dt)
2539 end do
2540
2541 end subroutine ose_calcOmPstddevCH
2542
2543 !--------------------------------------------------------------------------
2544 ! ose_fillOmPstddevCH
2545 !--------------------------------------------------------------------------
2546 subroutine ose_fillOmPstddevCH(obsSpaceData)
2547 !
2548 !:Purpose: To assign the Omp error std dev where possible for the obs
2549 ! of the CH obs family.
2550 !
2551 implicit none
2552
2553 ! Arguments:
2554 type(struct_obs), intent(inout) :: obsSpaceData ! observation-space data; output saved in OBS_OMPE column
2555
2556 ! Locals:
2557 integer :: stnidIndex, headerIndex, bodyIndex, bodyIndex_start, bodyIndex_end, icodtyp
2558 integer :: idate, itime, iass, latIndex, monthIndex, ibegin
2559 real(8) :: zlat, zlev, OmP_err_stddev, lat
2560 character(len=12) :: stnid
2561
2562 ! Loop over all obs types
2563
2564 do stnidIndex=1,OmPstdCH%n_stnid
2565 ! Check if OBS_OMPE is to be estimated elsewhere via use of OBS_HPHT and OBS_OER
2566 ! instead of via ose_fillOmPstddevCH
2567 if ( OmPstdCH%source(stnidIndex) > 1 ) cycle
2568
2569 ! Loop over all header indices of the 'CH' family:
2570
2571 call obs_set_current_header_list(obsSpaceData,'CH')
2572 HEADER: do
2573
2574 headerIndex = obs_getHeaderIndex(obsSpaceData)
2575 if (headerIndex < 0) exit HEADER
2576
2577 icodtyp = obs_headElem_i(obsSpaceData,OBS_ITY,headerIndex)
2578 if (icodtyp.ne.codtyp_get_codtyp('CHEMREMOTE').and.icodtyp.ne.codtyp_get_codtyp('CHEMINSITU')) cycle HEADER
2579
2580 stnid = obs_elem_c(obsSpaceData,'STID',headerIndex)
2581 if ( .not. utl_stnid_equal(OmPstdCH%stnids(stnidIndex),stnid) ) cycle HEADER
2582
2583 bodyIndex_start = obs_headElem_i(obsSpaceData,OBS_RLN,headerIndex)
2584 bodyIndex_end = bodyIndex_start+obs_headElem_i(obsSpaceData,OBS_NLV,headerIndex)-1
2585
2586 ! Check OBS_VNM value.
2587 do bodyIndex=bodyIndex_start,bodyIndex_end
2588 if (obs_bodyElem_i(obsSpaceData,OBS_VNM,bodyIndex) /= BUFR_SCALE_EXPONENT) then
2589 if ( obs_bodyElem_i(obsSpaceData,OBS_VNM,bodyIndex) /= OmPstdCH%element(stnidIndex) ) cycle HEADER
2590 end if
2591 end do
2592
2593 zlat = obs_headElem_r( obsSpaceData, OBS_LAT, headerIndex )
2594 idate = obs_headElem_i( obsSpaceData, OBS_DAT, headerIndex )
2595 itime = obs_headElem_i( obsSpaceData, OBS_ETM, headerIndex )
2596
2597 ! Identify lat and month index
2598 if (OmPstdCH%n_lat(stnidIndex) == 1) then
2599 latIndex = 0 ! no interpolation
2600 else
2601
2602 ! Find latitude index for interpolation.
2603 ! Assuming increasing latitudes in OmPstdCH%lat
2604 ! Interpolation to between latIndex and latIndex-1
2605
2606 lat = zlat / MPC_RADIANS_PER_DEGREE_R8 ! radians to degrees
2607
2608 ibegin=OmPstdCH%ibegin(stnidIndex)-1
2609 if ( lat <= OmPstdCH%lat(ibegin+1) ) then
2610 latIndex=2
2611 else if ( lat >= OmPstdCH%lat(ibegin+OmPstdCH%n_lat(stnidIndex)) ) then
2612 latIndex=OmPstdCH%n_lat(stnidIndex)
2613 else
2614 do latIndex=2,OmPstdCH%n_lat(stnidIndex)
2615 if (lat >= OmPstdCH%lat(ibegin+latIndex-1) .and. &
2616 lat <= OmPstdCH%lat(ibegin+latIndex)) exit
2617 end do
2618 end if
2619 end if
2620
2621 if (OmPstdCH%n_month(stnidIndex) == 1) then
2622 monthIndex = 1
2623 else
2624 ! Find month index
2625 monthIndex=(idate-(idate/10000)*10000)/100
2626 end if
2627
2628 do bodyIndex=bodyIndex_start,bodyIndex_end
2629 if (obs_bodyElem_i(obsSpaceData,OBS_VNM,bodyIndex) == BUFR_SCALE_EXPONENT) cycle
2630
2631 zlev = obs_bodyElem_r( obsSpaceData, OBS_PPP, bodyIndex )
2632
2633 ! Get OmP error std dev
2634 OmP_err_stddev = ose_getOmPstddevCH( lat, zlev, stnidIndex, latIndex, monthIndex )
2635 if ( OmPstdCH%std_type(stnidIndex) == 1 ) then
2636 iass = obs_bodyElem_i( obsSpaceData, OBS_ASS, bodyIndex )
2637 if ( iass == obs_assimilated ) then
2638 OmP_err_stddev = obs_bodyElem_r( obsSpaceData, OBS_VAR, bodyIndex )*OmP_err_stddev
2639 call obs_bodySet_r( obsSpaceData, OBS_OMPE, bodyIndex, OmP_err_stddev )
2640 end if
2641 else
2642 call obs_bodySet_r( obsSpaceData, OBS_OMPE, bodyIndex, OmP_err_stddev )
2643 end if
2644
2645 end do
2646 end do HEADER
2647 end do
2648
2649 end subroutine ose_fillOmPstddevCH
2650
2651 !--------------------------------------------------------------------------
2652 ! ose_getOmPstddevCH
2653 !--------------------------------------------------------------------------
2654 real(8) function ose_getOmPstddevCH(zlat,zlev,stnidIndex,latIndex,monthIndex) result(OmP_err_stddev)
2655 !
2656 !:Purpose: To return the OmP error std dev for a CH family measurement
2657 !
2658 implicit none
2659
2660 ! Arguments:
2661 real(8), intent(in) :: zlat ! latitude (radians)
2662 real(8), intent(in) :: zlev ! vertical coordinate value
2663 integer, intent(in) :: stnidIndex ! station and obs type index
2664 integer, intent(in) :: latIndex ! reference lat for interpolation
2665 integer, intent(in) :: monthIndex ! month index
2666
2667 ! Locals:
2668 real(8) :: levDiff
2669 integer :: ibegin,levIndex,loopIndex,posIndex
2670 real(8), parameter :: minDiff = 0.01*abs(MPC_missingValue_R8)
2671
2672 OmP_err_stddev = MPC_missingValue_R8
2673
2674 ! Get OmP error std. dev.
2675
2676 ibegin=OmPstdCH%ibegin(stnidIndex)-1
2677
2678 if (OmPstdCH%n_lvl(stnidIndex) > 1) then
2679
2680 ! Find nearest vertical level (no vertical interpolation in this version)
2681
2682 levDiff=1.0d10
2683 do loopIndex=1,OmPstdCH%n_lvl(stnidIndex)
2684 if ( levDiff > abs(zlev-OmPstdCH%levels(ibegin+loopIndex)) ) THEN
2685 levIndex=loopIndex
2686 levDiff=abs(zlev-OmPstdCH%levels(ibegin+loopIndex))
2687 END IF
2688 END DO
2689 posIndex=ibegin+(levIndex-1)*OmPstdCH%n_lat(stnidIndex)
2690 else
2691 posIndex=ibegin
2692 end if
2693
2694 if ( OmPstdCH%n_month(stnidIndex) == 1 ) then
2695 posIndex = posIndex + latIndex
2696 else
2697 posIndex = posIndex + (monthIndex-1)*OmPstdCH%n_lat(stnidIndex)*OmPstdCH%n_lvl(stnidIndex) + latIndex
2698 end if
2699
2700 if ( OmPstdCH%n_lat(stnidIndex) > 1 ) then
2701 ! Apply interpolation in latitude
2702
2703 if ( latIndex == 1 .or. latIndex > OmPstdCH%n_lat(stnidIndex)) then
2704 if ( abs(OmPstdCH%std(posIndex) - MPC_missingValue_R8) > minDiff ) then
2705 OmP_err_stddev = MPC_missingValue_R8
2706 else
2707 OmP_err_stddev = OmPstdCH%std(posIndex)
2708 end if
2709 else
2710 if ( abs(OmPstdCH%std(posIndex-1) - MPC_missingValue_R8) < minDiff .and. &
2711 abs(OmPstdCH%std(posIndex) - MPC_missingValue_R8) < minDiff ) then
2712 OmP_err_stddev = MPC_missingValue_R8
2713 else if ( abs(OmPstdCH%std(posIndex-1) - MPC_missingValue_R8) < minDiff ) then
2714 OmP_err_stddev = OmPstdCH%std(posIndex)
2715 else if ( abs(OmPstdCH%std(posIndex) - MPC_missingValue_R8) < minDiff ) then
2716 OmP_err_stddev = OmPstdCH%std(posIndex-1)
2717 else
2718 OmP_err_stddev = (OmPstdCH%std(posIndex-1)*(OmPstdCH%lat(ibegin+latIndex)-zlat)+ &
2719 OmPstdCH%std(posIndex)*(zlat-OmPstdCH%lat(ibegin+latIndex-1)))/ &
2720 (OmPstdCH%lat(ibegin+latIndex)-OmPstdCH%lat(ibegin+latIndex-1))
2721 end if
2722 end if
2723 else
2724 if ( abs(OmPstdCH%std(posIndex) - MPC_missingValue_R8) > minDiff ) then
2725 OmP_err_stddev = MPC_missingValue_R8
2726 else
2727 OmP_err_stddev = OmPstdCH%std(posIndex)
2728 end if
2729 end if
2730
2731 end function ose_getOmPstddevCH
2732
2733 !--------------------------------------------------------------------------
2734 ! ose_OmPstddevExistsForAllCH
2735 !--------------------------------------------------------------------------
2736 logical function ose_OmPstddevExistsForAllCH(obsSpaceData) result(allOMPE)
2737 !
2738 !:Purpose: To determine if all obs to be processed have usable OBS_OMPE values
2739 ! for the CH obs family.
2740 !
2741 implicit none
2742
2743 ! Arguments:
2744 type(struct_obs), intent(inout) :: obsSpaceData ! observation-space data; output saved in OBS_OMPE column
2745
2746 ! Local:
2747 integer :: headerIndex, bodyIndex, bodyIndex_start, bodyIndex_end, icodtyp
2748
2749 ! Loop over all header indices of the 'CH' family:
2750
2751 allOMPE = .true.
2752
2753 call obs_set_current_header_list(obsSpaceData,'CH')
2754 HEADER: do
2755
2756 headerIndex = obs_getHeaderIndex(obsSpaceData)
2757 if (headerIndex < 0) exit HEADER
2758
2759 icodtyp = obs_headElem_i(obsSpaceData,OBS_ITY,headerIndex)
2760 if (icodtyp.ne.codtyp_get_codtyp('CHEMREMOTE').and.icodtyp.ne.codtyp_get_codtyp('CHEMINSITU')) cycle HEADER
2761
2762 bodyIndex_start = obs_headElem_i(obsSpaceData,OBS_RLN,headerIndex)
2763 bodyIndex_end = bodyIndex_start+obs_headElem_i(obsSpaceData,OBS_NLV,headerIndex)-1
2764
2765 ! Check for cases were OmP error std dev is not available
2766
2767 do bodyIndex=bodyIndex_start,bodyIndex_end
2768 if ( obs_bodyElem_r(obsSpaceData,OBS_OMPE,bodyIndex) <= 0.0d0 .and. &
2769 obs_bodyElem_i(obsSpaceData,OBS_ASS,bodyIndex) == obs_assimilated ) then
2770 allOMPE = .false.
2771 write(*,*)
2772 write(*,*) 'ose_OmPstddevExistsForAllCH: Not all CH obs to be processed have available OmP error std dev.'
2773 write(*,*) 'HPHT will be calculated for the obs that do not have OmP error std dev available.'
2774 write(*,*)
2775 return
2776 end if
2777 end do
2778 end do HEADER
2779
2780 end function ose_OmPstddevExistsForAllCH
2781
2782 !--------------------------------------------------------------------------
2783 ! ose_deallocOmPstddevCH
2784 !--------------------------------------------------------------------------
2785 subroutine ose_deallocOmPstddevCH
2786 !
2787 !:Purpose: To deallocate temporary storage space used for OmP error std dev
2788 ! for the CH family.
2789 !
2790 implicit none
2791
2792 if (OmPstdCH%n_stnid.eq.0) return
2793
2794 if (allocated(OmPstdCH%stnids)) deallocate(OmPstdCH%stnids)
2795 if (allocated(OmPstdCH%n_lvl)) deallocate(OmPstdCH%n_lvl)
2796 if (allocated(OmPstdCH%ibegin)) deallocate(OmPstdCH%ibegin)
2797 if (allocated(OmPstdCH%element)) deallocate(OmPstdCH%element)
2798 if (allocated(OmPstdCH%source)) deallocate(OmPstdCH%source)
2799 if (allocated(OmPstdCH%std_type)) deallocate(OmPstdCH%std_type)
2800 if (allocated(OmPstdCH%n_lat)) deallocate(OmPstdCH%n_lat)
2801 if (allocated(OmPstdCH%std)) deallocate(OmPstdCH%std)
2802 if (allocated(OmPstdCH%levels)) deallocate(OmPstdCH%levels)
2803 if (allocated(OmPstdCH%lat)) deallocate(OmPstdCH%lat)
2804 if (allocated(OmPstdCH%n_month)) deallocate(OmPstdCH%n_month)
2805 if (allocated(OmPstdCH%month)) deallocate(OmPstdCH%month)
2806
2807 end subroutine ose_deallocOmPstddevCH
2808
2809end module obsSpaceErrorStdDev_mod