1module burpFiles_mod
2 ! MODULE burpFiles_mod (prefix='brpf' category='3. Observation input/output')
3 !
4 !:Purpose: To store the filenames of the burp observation files and call
5 ! subroutines in readBurp_mod to read and update burp files.
6 !
7 use codePrecision_mod
8 use mathPhysConstants_mod
9 use utilities_mod
10 use obsSpaceData_mod
11 use burpread_mod
12 use bufr_mod
13 use utilities_mod
14 use obsSubSpaceData_mod
15 use burp_module
16 use obsUtil_mod
17 use obsVariableTransforms_mod
18
19 implicit none
20 save
21 private
22
23 ! public procedures
24 public :: brpf_getDateStamp, brpf_readfile, brpf_updatefile
25 public :: brpf_obsSub_read, brpf_obsSub_update
26
27contains
28
29 !--------------------------------------------------------------------------
30 ! brpf_getDataStamp
31 !--------------------------------------------------------------------------
32 subroutine brpf_getDateStamp(datestamp, burpFileName)
33 implicit none
34
35 ! Arguments:
36 integer, intent(out) :: dateStamp
37 character(len=*), intent(in) :: burpFileName
38
39 ! Locals:
40 integer :: ier, inblks, nulburp, fnom, fclos, numblks
41 logical :: isExist_L
42 integer :: ktime, kdate, kdate_recv, ktime_recv, ihandl, ilong
43 integer :: itime, iflgs, idburp, ilat, ilon, idx, idy
44 integer :: ialt, idelay, idate, irs, irunn, inblk, isup, ixaux
45 integer :: insup, inxaux
46 integer, allocatable :: ibuf(:)
47 integer :: inrecs, mrfcls, mrfopn, mrfopc, mrbhdr, mrfloc, mrfget, mrfmxl
48 integer :: istampobs, inewhh, newdate, nresume, ivals
49 real(8) :: delhh
50 character(len=9) :: clstnid
51
52 !
53 !- Get the date from the burp files
54 !
55
56 ier = mrfopc('MSGLVL','FATAL')
57
58 ivals = 8
59 kdate = -9999
60 ktime = -9999
61 nresume = 0
62 nulburp = 0
63 inquire(file=trim(burpFileName),exist=isExist_L)
64 if ( isExist_L ) then
65 ier = fnom(nulburp,trim(burpFileName),'RND+OLD',0)
66 write(*,*)' Open File : ',trim(burpFileName)
67 if ( ier == 0 ) then
68 inblks = -1
69 inblks = numblks(nulburp)
70 if ( inblks > 0 ) then
71 inrecs= mrfopn(nulburp,'READ')
72 ilong = mrfmxl(nulburp)
73 allocate(ibuf(ilong + 20))
74 ibuf(1) = ilong + 20
75 ihandl = mrfloc(nulburp,0,'>>*******',-1,-1,-1,-1,-1,-1,0)
76 if ( ihandl < 0 ) then
77 ihandl=mrfloc(nulburp,0,'*********',-1,-1,-1,-1,-1,-1,0)
78 else
79 nresume=nresume+1
80 end if
81 if ( ihandl < 0 ) then
82 write(*,*) 'AUCUN ENREGISTREMENT VALIDE DANS LE FICHIER BURP'
83 else
84 if ((kdate < 0.and.ktime < 0).or.nresume == 1) then
85 insup=0
86 inxaux=0
87 ier=mrfget(ihandl,ibuf)
88 ier=mrbhdr(ibuf,itime,iflgs,clstnid,idburp,ilat, &
89 ilon,idx,idy, ialt,idelay,idate,irs,irunn,inblk, &
90 isup,insup,ixaux,inxaux)
91 ktime=itime
92 kdate=idate
93 if (nresume == 1) nresume=2
94 end if
95 end if
96 deallocate(ibuf)
97 ier=mrfcls(nulburp)
98 end if
99 end if
100 ier= fclos(nulburp)
101 end if
102
103 !
104 !- Set reference datestamp
105 !
106 ! Make sure all mpi tasks have a valid date (important for split burp files)
107 call rpn_comm_allreduce(kdate,kdate_recv,1,"MPI_INTEGER","MPI_MAX","GRID",ier)
108 call rpn_comm_allreduce(ktime,ktime_recv,1,"MPI_INTEGER","MPI_MAX","GRID",ier)
109 kdate = kdate_recv
110 ktime = ktime_recv
111 if (nresume >= 1 ) then
112 ier = newdate(datestamp,kdate,ktime*10000,3)
113 else
114 ! Assumes 6-hour windows with reference times being synoptic times.
115 ! Does not require kdate and ktime to be from a resume record.
116 ier = newdate(istampobs,kdate,ktime*10000,3)
117 delhh = 3.0d0
118 call incdatr (datestamp, istampobs, delhh)
119 ier = newdate(datestamp,kdate,inewhh,-3)
120 ktime = ktime/100
121 if (ktime >= 21 .or. ktime < 3) then
122 ktime = 0
123 else if(ktime >= 3 .and. ktime < 9) then
124 ktime = 6
125 else if(ktime >= 9 .and. ktime < 15) then
126 ktime = 12
127 else
128 ktime = 18
129 end if
130 ier = newdate(datestamp,kdate,ktime*1000000,3)
131 ktime = ktime*100
132 end if
133
134 write(*,*)' BURP FILES VALID DATE (YYYYMMDD) : ', kdate
135 write(*,*)' BURP FILES VALID TIME (HHMM) : ', ktime
136 write(*,*)' BURP FILES DATESTAMP : ', datestamp
137
138 end subroutine brpf_getDateStamp
139
140 !--------------------------------------------------------------------------
141 ! brpf_readFile
142 !--------------------------------------------------------------------------
143 subroutine brpf_readFile(obsdat,fileName,familyType,fileIndex)
144 implicit none
145
146 ! Arguments:
147 type (struct_obs), intent(inout) :: obsdat
148 character(len=*), intent(in) :: fileName
149 character(len=*), intent(in) :: familyType
150 integer, intent(in) :: fileIndex
151
152 ! Locals:
153 integer :: bodyIndex, bodyIndexBegin, bodyIndexEnd, headerIndexBegin, headerIndexEnd, headerIndex
154 integer :: numBody, numHeader
155 logical :: burp_chem
156 real(pre_obsReal) :: missingValue
157
158 write(*,*) ' '
159 write(*,*) 'brpf_readFile: Starting'
160 write(*,*) ' '
161 missingValue = real(MPC_missingValue_R8,pre_obsReal)
162
163 bodyIndexBegin = obs_numbody(obsdat) + 1
164 headerIndexBegin = obs_numheader(obsdat) + 1
165 call brpr_readBurp(obsdat, & ! INOUT
166 familyType, fileName, fileIndex) ! IN
167 bodyIndexEnd = obs_numbody(obsdat)
168 headerIndexEnd = obs_numheader(obsdat)
169
170 burp_chem = trim(familyType) == 'CH'
171
172 if ( trim(familyType) /= 'TO' .and. .not.burp_chem ) then
173
174 call ovt_transformObsValues (obsdat, headerIndexBegin, headerIndexEnd )
175 call ovt_adjustHumGZ (obsdat, headerIndexBegin, headerIndexEnd )
176 call obsu_computeVertCoordSurfObs(obsdat, headerIndexBegin, headerIndexEnd )
177
178 end if
179
180 do headerIndex = headerIndexBegin, headerIndexEnd
181
182 call obs_headSet_i(obsdat, OBS_IDF, headerIndex, fileIndex)
183 call obs_setFamily(obsdat, trim(familyType), headerIndex)
184
185 ! For CH family, apply scaling from the element BUFR_SCALE_EXPONENT when present.
186 if (burp_chem) call brpf_setScaleCH(obsdat, headerIndex, forward=.true.)
187
188 end do
189
190 ! initializations
191 do bodyIndex = bodyIndexBegin, bodyIndexEnd
192
193 if ( obs_columnActive_RB(obsdat, OBS_OMA) ) call obs_bodySet_r(obsdat, OBS_OMA , bodyIndex, missingValue )
194 if ( obs_columnActive_RB(obsdat, OBS_OMA0)) call obs_bodySet_r(obsdat, OBS_OMA0, bodyIndex, missingValue )
195 if ( obs_columnActive_RB(obsdat, OBS_OMP) ) call obs_bodySet_r(obsdat, OBS_OMP , bodyIndex, missingValue )
196 if ( obs_columnActive_RB(obsdat, OBS_OMP6)) call obs_bodySet_r(obsdat, OBS_OMP6, bodyIndex, missingValue )
197 if ( obs_columnActive_RB(obsdat, OBS_OER) ) call obs_bodySet_r(obsdat, OBS_OER , bodyIndex, missingValue )
198 if ( obs_columnActive_RB(obsdat, OBS_HPHT)) call obs_bodySet_r(obsdat, OBS_HPHT, bodyIndex, missingValue )
199 if ( obs_columnActive_RB(obsdat, OBS_HAHT)) call obs_bodySet_r(obsdat, OBS_HAHT, bodyIndex, missingValue )
200 if ( obs_columnActive_RB(obsdat, OBS_WORK)) call obs_bodySet_r(obsdat, OBS_WORK, bodyIndex, missingValue )
201 if ( obs_columnActive_RB(obsdat, OBS_SIGI)) call obs_bodySet_r(obsdat, OBS_SIGI, bodyIndex, missingValue )
202 if ( obs_columnActive_RB(obsdat, OBS_SIGO)) call obs_bodySet_r(obsdat, OBS_SIGO, bodyIndex, missingValue )
203 if ( obs_columnActive_RB(obsdat, OBS_ZHA )) call obs_bodySet_r(obsdat, OBS_ZHA , bodyIndex, missingValue )
204
205 end do
206
207 ! For GP family, initialize OBS_OER to element 15032 (ZTD formal error)
208 ! for all ZTD data (element 15031)
209 if ( trim(familyType) == 'GP') then
210 write(*,*)' Initializing OBS_OER for GB-GPS ZTD to formal error (ele 15032)'
211 call obsu_setGbgpsError(obsdat, headerIndexBegin, headerIndexEnd )
212 end if
213
214 numHeader = obs_numHeader(obsdat)
215 numBody = obs_numBody(obsdat)
216 write(*,*) 'brpf_readFile: obs_numheader', numHeader
217 write(*,*) 'brpf_readFile: obs_numbody ', numBody
218
219 end subroutine brpf_readFile
220
221 !--------------------------------------------------------------------------
222 ! brpf_updateFile
223 !--------------------------------------------------------------------------
224 subroutine brpf_updateFile(obsSpaceData,fileName,familyType,fileIndex)
225 implicit none
226
227 ! Arguments:
228 type (struct_obs), intent(inout) :: obsSpaceData
229 character(len=*), intent(in) :: fileName
230 character(len=*), intent(in) :: familyType
231 integer, intent(in) :: fileIndex
232
233 ! Locals:
234 integer :: headerIndex
235
236 call utl_tmg_start(12,'----UpdateBurpFile')
237
238 write(*,*)
239 write(*,*) 'brpf_updateFile: Starting'
240
241 ! CH family: Scaling of the obs related values to be stored in the BURP files
242 if (familytype == 'CH') then
243 call obs_set_current_header_list(obsSpaceData,'CH')
244 HEADER: do
245 headerIndex = obs_getHeaderIndex(obsSpaceData)
246 if (headerIndex < 0) exit HEADER
247 call brpf_setScaleCH(obsSpaceData,headerIndex,forward=.false.)
248 end do HEADER
249 end if
250
251 call brpr_updateBurp(obsSpaceData,familyType,fileName,fileIndex)
252
253 write(*,*) 'brpf_updateFile: Done'
254 write(*,*)
255
256 call utl_tmg_stop(12)
257
258 end subroutine brpf_updateFile
259
260 !--------------------------------------------------------------------------
261 ! brpf_setScaleCH
262 !--------------------------------------------------------------------------
263 subroutine brpf_setScaleCH(obsdat,headerIndex,forward)
264 !
265 !:Purpose: Apply or unapply scaling to CH observations by multiplying
266 ! (or dividing) with 10^{exponent} where the exponent is from
267 ! element BUFR_SCALE_EXPONENT if provided.
268 !
269 !
270 implicit none
271
272 ! Arguments:
273 type(struct_obs), intent(inout) :: obsdat ! struct_obs instance
274 integer, intent(in) :: headerIndex ! header index in obsdat
275 logical, intent(in) :: forward ! applies scaling if .true., unapplies scaling if .false.
276
277 ! Locals:
278 integer :: bodyIndex,rln,nlv
279 real(pre_obsReal) :: obsv
280 real(pre_obsReal) :: vomp, voma, voer, vhpht, scale
281 integer :: nexp,iobs,iexp
282 real(pre_obsReal), allocatable :: expnt(:)
283
284 rln = obs_headElem_i(obsdat,OBS_RLN,headerIndex)
285 nlv = obs_headElem_i(obsdat,OBS_NLV,headerIndex)
286
287 allocate(expnt(nlv))
288
289 ! Count number of power of 10 exponents
290 nexp = 0
291 do bodyIndex = rln, nlv + rln -1
292 if (obs_bodyElem_i(obsdat,OBS_VNM,bodyIndex) == bufr_scale_exponent) then
293 nexp = nexp + 1
294 expnt(nexp) = obs_bodyElem_r(obsdat,OBS_VAR,bodyIndex)
295 end if
296 end do
297
298 if (nexp == 0) then
299 deallocate(expnt)
300 return
301 end if
302
303 if (nexp*2 /= nlv) then
304 ! Skip over obs assuming mantissa was filtered out in brpr_readBurp
305 ! (not inserted in obsSpaceData) due to quality flags.
306 ! Set exponent quality flag to that of a 'Suspicious element'
307
308 do bodyIndex = RLN, NLV + RLN -1
309 call obs_bodySet_r(obsdat,OBS_VAR,bodyIndex, 0.0D0 )
310 call obs_bodySet_i(obsdat,OBS_FLG,bodyIndex, ibset(obs_bodyElem_i(obsdat,OBS_FLG,bodyIndex),02) )
311 call obs_bodySet_i(obsdat,OBS_FLG,bodyIndex, ibset(obs_bodyElem_i(obsdat,OBS_FLG,bodyIndex),04) )
312 call obs_bodySet_i(obsdat,OBS_FLG,bodyIndex, ibset(obs_bodyElem_i(obsdat,OBS_FLG,bodyIndex),09) )
313 end do
314
315 ! write(*,*) 'NLV =',nlv,' Nexp=',nexp
316 ! call utl_abort('brpf_setScaleCH: Inconsistent number of exponents')
317 deallocate(expnt)
318 return
319 end if
320
321 if (forward) then
322
323 ! Apply power of 10 exponents if present
324 iobs = 0
325 do bodyIndex = RLN, NLV + RLN -1
326 if (obs_bodyElem_i(obsdat,OBS_VNM,bodyIndex) /= bufr_scale_exponent) then
327 iobs = iobs + 1
328 obsv = obs_bodyElem_r(obsdat,OBS_VAR,bodyIndex)
329 call obs_bodySet_r(obsdat,OBS_VAR,bodyIndex,obsv*10**(expnt(iobs)) )
330 end if
331 end do
332
333 else
334
335 ! Unapply power of 10 exponents if present
336 iobs=0
337 iexp=0
338 do bodyIndex = RLN, NLV + RLN -1
339 if (obs_bodyElem_i(obsdat,OBS_VNM,bodyIndex) == bufr_scale_exponent) then
340 ! Store scaling exponents
341 iexp = iexp + 1
342 call obs_bodySet_r(obsdat,OBS_OMP,bodyIndex,expnt(iexp))
343 call obs_bodySet_r(obsdat,OBS_OMA,bodyIndex,expnt(iexp))
344 call obs_bodySet_r(obsdat,OBS_OER,bodyIndex,expnt(iexp))
345 call obs_bodySet_r(obsdat,OBS_HPHT,bodyIndex,expnt(iexp))
346 else
347 iobs=iobs+1
348 obsv=obs_bodyElem_r(obsdat,OBS_VAR,bodyIndex)
349 vomp=obs_bodyElem_r(obsdat,OBS_OMP,bodyIndex)
350 voma=obs_bodyElem_r(obsdat,OBS_OMA,bodyIndex)
351 voer=obs_bodyElem_r(obsdat,OBS_OER,bodyIndex)
352 vhpht=obs_bodyElem_r(obsdat,OBS_HPHT,bodyIndex)
353 scale=10**(-expnt(iobs))
354 call obs_bodySet_r(obsdat,OBS_VAR,bodyIndex,obsv*scale )
355 call obs_bodySet_r(obsdat,OBS_OMP,bodyIndex,vomp*scale )
356 call obs_bodySet_r(obsdat,OBS_OMA,bodyIndex,voma*scale )
357 call obs_bodySet_r(obsdat,OBS_OER,bodyIndex,voer*scale )
358 call obs_bodySet_r(obsdat,OBS_HPHT,bodyIndex,vhpht*scale )
359 end if
360 end do
361
362 end if
363
364 end subroutine brpf_setScaleCH
365
366 !--------------------------------------------------------------------------
367 ! brpf_obsSub_read
368 !--------------------------------------------------------------------------
369 function brpf_obsSub_read(filename,stnid,varno,nlev,ndim,block_type,bkstp_opt, &
370 match_nlev_opt,codtyp_opt,numColumns_opt) result(burp_out)
371 !
372 !:Purpose: To retrieve information from observation BURP file. Returns the
373 ! data in a struct_oss_obsdata object. Can retrieve either 1D or 2D
374 ! data from a report.
375 !
376 !:Comments:
377 !
378 ! - BUFR power 10 exponent element (i.e. data with BUFR number
379 ! BUFR_SCALE_EXPONENT) will be applied only to 1D data if present.
380 ! - As burp_out is for a specific input stnid, burp_out%code contains
381 ! only the (lat/long and time coord.) with 22 characters.
382 ! - Exponent BUFR data (i.e. data with BUFR number BUFR_SCALE_EXPONENT)
383 ! will be applied only to 1D data.
384 !
385 !:Arguments:
386 ! :filename: observation family name
387 ! :stnid: station ID of observation
388 ! :varno: BUFR code (if <=0, search through all codes to obtain first
389 ! between 10000 and 16000)
390 ! :nlev: number of levels in the observation (number of rows)
391 ! :ndim: number of dimensions for the retrieved data in each report
392 ! (e.g. ndim=1 for std, ndim=2 for averaging kernels)
393 ! :numColumns_opt: Number of columns (if different from nlev and for ndim=2)
394 ! :block_type: block type indicated by the two rightmost bits of bknat.
395 ! Valid values are 'DATA', 'INFO', '3-D', and 'MRQR'.
396 ! :match_nlev_opt: =.true. (default) causes filtering out of report if
397 ! the report number of levels is different from the input
398 ! argument nlev
399 !
400 implicit none
401
402 ! Arguments:
403 character(len=*), intent(in) :: filename ! BURP file name
404 character(len=9), intent(in) :: stnid ! station ID of observation
405 integer, intent(in) :: varno
406 integer, intent(in) :: nlev ! number of levels in the observation
407 integer, intent(in) :: ndim
408 character(len=4), intent(in) :: block_type
409 integer, optional, intent(in) :: numColumns_opt ! Number of columns (if different from nlev and for ndim=2)
410 integer, optional, intent(in) :: bkstp_opt ! bkstp number of requested block
411 logical, optional, intent(in) :: match_nlev_opt
412 integer, optional, intent(in) :: codtyp_opt(:) ! optional CODTYP list for search
413 ! Result:
414 type(struct_oss_obsdata) :: burp_out ! struct_oss_obsdata object
415
416 ! Locals:
417 character(len=9) :: rep_stnid
418 type(burp_file) :: brp
419 type(burp_rpt) :: rep
420 type(burp_block) :: blk
421 integer :: error,ref_rpt,nrep,ref_blk,varno_ivar
422 integer :: ref_bkstp,nval,ivar,ilev,icount,icodtyp
423 integer :: date,time,ilat,ilon,iele,nele,icol,ivar_previous
424 logical :: match_nlev
425 real(8) :: exponent
426
427 if (present(match_nlev_opt)) then
428 match_nlev = match_nlev_opt
429 else
430 match_nlev = .true.
431 end if
432
433 ! initialize burp file, report, and block
434 call BURP_Init(brp, iostat=error)
435 call BURP_Init(rep, iostat=error)
436 call BURP_Init(blk, iostat=error)
437
438 ! open the burp file
439 call BURP_New(brp, FILENAME=filename, MODE=FILE_ACC_READ, IOSTAT=error)
440 if (error /= 0) call utl_abort('brpf_obsSub_read: Could not find/open BURP file: ' // trim(filename))
441
442 write(*,*) "brpf_obsSub_read: Reading file " // trim(filename)
443 write(*,*) "brpf_obsSub_read: Selecting STNID = ",stnid," BUFR = ",varno," block type = ",block_type
444 write(*,*) "brpf_obsSub_read: nlev = ",nlev," match_nlev = ",match_nlev
445 if (present(bkstp_opt)) write(*,*) "brpf_obsSub_read: bkstp = ",bkstp_opt
446 if (present(codtyp_opt)) write(*,*) "brpf_obsSub_read: codtyp = ",codtyp_opt(:)
447
448 ! get number of reports in file
449 call BURP_Get_Property(brp, NRPTS=nrep)
450
451 ! allocate memory
452 if (ndim == 1) then
453 call oss_obsdata_alloc(burp_out,nrep,dim1=nlev)
454 else
455 if (present(numColumns_opt)) then
456 call oss_obsdata_alloc(burp_out,nrep,dim1=nlev,dim2_opt=numColumns_opt)
457 else
458 call oss_obsdata_alloc(burp_out,nrep,dim1=nlev,dim2_opt=nlev)
459 end if
460 end if
461
462 icount = 0 ! counter of reports with same stnid, number of levels, and varno as input
463 ref_rpt = 0
464
465 ! loop through reports
466 REPORTS: do
467
468 ref_rpt = BURP_Find_Report(brp, REPORT=rep, SEARCH_FROM=ref_rpt, IOSTAT=error)
469
470 if (ref_rpt<0) exit REPORTS
471
472 call BURP_Get_Property(rep, STNID=rep_stnid, DATE=date, TEMPS=time, LATI=ilat, LONG=ilon, IDTYP=icodtyp)
473
474 if (present(codtyp_opt)) then
475 if (.not.any(codtyp_opt(:) == icodtyp)) cycle REPORTS
476 end if
477
478 if (.not.utl_stnid_equal(stnid,rep_stnid)) cycle REPORTS
479
480 ! loop through blocks
481 ref_blk = 0
482 BLOCKS: do
483
484 ref_blk = BURP_Find_Block(rep, BLOCK=blk, SEARCH_FROM=ref_blk, IOSTAT=error)
485 if (ref_blk<0) exit BLOCKS
486
487 call BURP_Get_Property(blk, NELE=nele, NVAL=nval, BKSTP=ref_bkstp, IOSTAT=error)
488
489 if (.not.IS_Burp_Btyp(trim(block_type),BLOCK=blk)) cycle BLOCKS
490 if (match_nlev .and. nval /= nlev) cycle BLOCKS
491 if (present(bkstp_opt)) then
492 if (bkstp_opt /= ref_bkstp) cycle BLOCKS
493 end if
494
495 if (varno > 0) then
496 ivar = BURP_Find_Element(blk, ELEMENT=varno, IOSTAT=error)
497 if (ivar < 0) cycle BLOCKS
498 else
499 ! Search for first data element within elements 10000 and 16000.
500 varno_ivar=-1
501 do ivar=1,nele
502 varno_ivar=BURP_Get_Element(blk, INDEX=ivar, IOSTAT=error)
503 if (varno_ivar >= 10000.and.varno_ivar < 16000) exit
504 end do
505 if (varno_ivar < 10000.or.varno_ivar >= 16000) call utl_abort('brpf_obsSub_read: No valid element found for STNID ' // rep_stnid )
506 end if
507
508 ! required block found if code reaches this point, retrieve data and store in burp_out
509
510 if (nval > nlev) call utl_abort('brpf_obsSub_read: number of levels in the report (' // trim(utl_str(nval)) // &
511 ') exceeds the specified maximum number of levels (' // trim(utl_str(nlev)) // &
512 ') for STNID ' // rep_stnid )
513
514 icount=icount+1
515 burp_out%code(icount) = oss_obsdata_get_header_code(ilon,ilat,date,time,rep_stnid) ! this code is a unique identifier for this report
516
517 if (ndim == 1) then
518 ! retrieve 1D data
519
520 do ilev=1,nval
521 burp_out%data1d(ilev,icount) = BURP_Get_Rval(blk, NELE_IND=ivar, NVAL_IND=ilev, NT_IND=1, IOSTAT=error)
522 end do
523
524 if (ivar < nele) then
525 if (BURP_Get_Element(blk, INDEX=ivar+1, IOSTAT=error) == BUFR_SCALE_EXPONENT) then
526 ! Apply exponent
527 do ilev=1,nval
528 exponent = BURP_Get_Rval(blk, NELE_IND=ivar+1, NVAL_IND=ilev, NT_IND=1, IOSTAT=error)
529 burp_out%data1d(ilev,icount) = burp_out%data1d(ilev,icount) * 10**exponent
530 end do
531 end if
532 end if
533
534 else if (ndim == 2) then
535 ! retrieve 2D data
536
537 icol = 0
538 ivar_previous=0
539 do iele=1,nele
540 ivar = BURP_Get_Element(blk, INDEX=iele, IOSTAT=error)
541 if (ivar == varno) then
542 icol = icol+1
543 ivar_previous=ivar
544 do ilev=1,nval
545 burp_out%data2d(ilev,icol,icount) = BURP_Get_Rval(blk, NELE_IND=iele, NVAL_IND=ilev, NT_IND=1, IOSTAT=error)
546 end do
547 else if (ivar_previous == varno .and. ivar == BUFR_SCALE_EXPONENT) then
548 ivar_previous=0
549 do ilev=1,nval
550 exponent = BURP_Get_Rval(blk, NELE_IND=iele, NVAL_IND=ilev, NT_IND=1, IOSTAT=error)
551 burp_out%data2d(ilev,icol,icount) = burp_out%data2d(ilev,icol,icount) * 10**exponent
552 end do
553 else
554 ivar_previous=0
555 end if
556 end do
557 if (present(numColumns_opt)) then
558 if (icol /= numColumns_opt) call utl_abort('brpf_obsSub_read: number of columns (' // trim(utl_str(icol)) // &
559 ') is not equal to the required number (' // trim(utl_str(numColumns_opt)) // &
560 ') for STNID ' // rep_stnid )
561 else
562 if (icol > nlev ) call utl_abort('brpf_obsSub_read: number of columns (' // trim(utl_str(icol)) // &
563 ') exceeds the maximum number (' // trim(utl_str(nlev)) // &
564 ') for STNID ' // rep_stnid )
565 end if
566 end if
567
568 exit BLOCKS
569
570 end do BLOCKS
571
572 end do REPORTS
573
574 ! resize first dimension of data arrays from length of nrep to icount
575 call utl_resize(burp_out%code,icount)
576 if (ndim == 1) then
577 call utl_resize(burp_out%data1d,nlev,icount)
578 else if (ndim == 2) then
579 call utl_resize(burp_out%data2d,nlev,nlev,icount)
580 end if
581
582 burp_out%nrep = icount
583
584 write(*,*) "brpf_obsSub_read: Reading of file complete. Number of reports found: ",burp_out%nrep
585
586 ! deallocate
587 Call BURP_Free(brp,iostat=error)
588 Call BURP_Free(rep,iostat=error)
589 Call BURP_Free(blk,iostat=error)
590
591 end function brpf_obsSub_read
592
593 !--------------------------------------------------------------------------
594 ! brpf_obsSub_update
595 !--------------------------------------------------------------------------
596 function brpf_obsSub_update(obsdata,filename,varno,block_type,bkstp_opt, &
597 multi_opt) result(nrep_modified)
598 !
599 !:Purpose: To add or modify data in BURP files from data stored in a
600 ! struct_oss_obsdata object. Provided data can be either 1D or 2D.
601 !
602 !:Comments:
603 ! - Currently assumes that all elements of varno(:) are distinct from
604 ! each other.
605 ! - Blocks with new data will overwrite any existing data of the same
606 ! varno. Otherwise the new data will be appended to the block.
607 !
608 !:Arguments:
609 ! :varno: BUFR descriptors. Number of elements must be
610 ! max(1,obsdata%dim2)
611 ! :block_type: block type indicated by the two rightmost bits of bknat.
612 ! Valid values are 'DATA', 'INFO', '3-D', and 'MRQR'.
613 ! :multi_opt: Indicates if intended report are for 'UNI' or 'MULTI'
614 ! level data (description is not accurate)
615 !
616 implicit none
617
618 ! Arguments:
619 type(struct_oss_obsdata), intent(inout) :: obsdata ! Input struct_oss_obsdata object for varno
620 character(len=*), intent(in) :: filename ! BURP file name
621 character(len=4), intent(in) :: block_type
622 integer, intent(in) :: varno(:)
623 integer, optional, intent(in) :: bkstp_opt ! bkstp number of requested block
624 character(len=*), optional, intent(in) :: multi_opt
625 ! Result:
626 integer :: nrep_modified ! Number of modified reports
627
628 ! Locals:
629 integer :: ncount
630 logical :: blk_found
631 integer, parameter :: LNMX=100000, code_len=90
632 character(len=9) :: stnid
633 character(len=code_len) :: code ! Must be at least as large as burp_code_len
634 type(burp_file) :: brp
635 type(burp_rpt) :: rep,rep_new
636 type(burp_block) :: blk
637 integer :: error,ref_rpt,nrep,ref_blk,ndim,dim1,dim2
638 integer :: ref_bkstp,nval,ivar,ilev,istat
639 integer :: date,time,ilat,ilon,iele,nele,k
640 integer, allocatable :: address(:)
641 real(4), allocatable :: new_vals(:,:,:)
642 logical, allocatable :: modify(:)
643
644 ! Check presence of data to update
645 if (obsdata%nrep <= 0) then
646 write(*,*) 'brpf_obsSub_update: Skipped due to absence of data to update.'
647 return
648 end if
649
650 ! Identify dimensions for the input data
651 ndim=obsdata%ndim
652 dim1=obsdata%dim1
653 if (ndim == 1) then
654 dim2=1
655 else
656 dim2=obsdata%dim2
657 end if
658
659 if (size(varno) < dim2) call utl_abort('brpf_obsSub_update: Number of BUFR elements not sufficient. ' // &
660 trim(utl_str(size(varno))) // ' vs ' // trim(utl_str(dim2)))
661
662 if (code_len < oss_obsdata_code_len()) call utl_abort('brpf_obsSub_update: Length of code string' // &
663 ' needs to be increased to ' // &
664 trim(utl_str(oss_obsdata_code_len())))
665
666 ! initialize burp file, report, and block system resources
667 call BURP_Init(brp, iostat=error)
668 call BURP_Init(rep, R2=rep_new, iostat=error)
669 call BURP_Init(blk, iostat=error)
670
671 ! open the burp file in append mode (to replace or add data in a block)
672 call BURP_New(brp, FILENAME=filename, MODE=FILE_ACC_APPEND, IOSTAT=error)
673 if (error /= 0) call utl_abort('brpf_obsSub_update: Could not open BURP file: ' // trim(filename))
674
675 ! get number of reports in file
676 call BURP_Get_Property(brp, NRPTS=nrep)
677
678 allocate(address(nrep),modify(nrep),new_vals(dim1,dim2,nrep))
679 address(:)=0
680 modify(:)=.false.
681 new_vals(:,:,:)=0.
682
683 ! First loop through reports to identify addresses of original file as well as identify if new
684 ! information should be included to that report.
685 ! NOTE: The addresses of all reports have to be saved in their original order to ensure the
686 ! order of the reports in the file is unchanged.
687 ref_rpt=0
688 ncount=0
689 obsdata%irep=1
690 REPORTS1: do
691
692 ref_rpt = BURP_Find_Report(brp, REPORT=rep, SEARCH_FROM=ref_rpt, IOSTAT=error)
693 if (ref_rpt<0) exit REPORTS1
694
695 ncount=ncount+1
696 address(ncount)=ref_rpt
697
698 call BURP_Get_Property(rep, STNID=stnid, DATE=date, TEMPS=time, LATI=ilat, LONG=ilon)
699
700 if (stnid(1:2) == '>>') cycle REPORTS1
701
702 ! Get unique identifier for search from input data
703 code = oss_obsdata_get_header_code(ilon,ilat,date,time,stnid)
704
705 ! Determine if replacement/additional data likely present for this report
706 if (dim1 == 1.and.dim2 == 1) then
707 new_vals(1,1,ncount)=real(oss_obsdata_get_element(obsdata,trim(code),1,stat_opt=istat))
708 else if (dim2 == 1) then
709 new_vals(:,1,ncount)=real(oss_obsdata_get_array1d(obsdata,trim(code),stat_opt=istat))
710 else
711 new_vals(:,:,ncount)=real(oss_obsdata_get_array2d(obsdata,trim(code),stat_opt=istat))
712 end if
713
714 if (istat == 0) then
715 if (present(multi_opt)) then
716 ! loop through blocks to find first data block
717 ref_blk = 0
718 BLOCKS1: do
719 ref_blk = BURP_Find_Block(rep, BLOCK=blk, SEARCH_FROM=ref_blk, IOSTAT=error)
720 if (ref_blk<0) exit BLOCKS1
721 if (IS_Burp_Btyp('DATA',BLOCK=blk)) then
722 if (IS_Burp_Btyp(trim(multi_opt),BLOCK=blk)) modify(ncount) = .true.
723 exit BLOCKS1
724 end if
725 end do BLOCKS1
726 else
727 modify(ncount) = .true.
728 end if
729 end if
730
731 end do REPORTS1
732
733 nrep_modified = count(modify) ! number of reports with same code and, possibly, same number of obs data levels
734
735 ! Generate new report
736 Call BURP_New(rep_new, ALLOC_SPACE=10*LNMX, IOSTAT=error)
737
738 ! second loop through reports to include the new information to the file
739 REPORTS2: do k=1,ncount
740
741 call BURP_Get_Report(brp, REPORT=rep, REF=address(k), IOSTAT=error)
742
743 ! Copy report header
744 Call BURP_Copy_Header(TO=rep_new,FROM=rep)
745 Call BURP_Init_Report_Write(brp,rep_new,IOSTAT=error)
746
747 ! Ignore resume records in BLOCKS do loop
748 call BURP_Get_Property(rep, STNID=stnid)
749
750 if (stnid(1:2) == '>>') then
751 write(*,*) 'brpf_obsSub_update: reading resume record, skip reading blocks'
752 else
753 ! loop through blocks
754 ref_blk = 0
755 BLOCKS: do
756
757 ref_blk = BURP_Find_Block(rep, BLOCK=blk, SEARCH_FROM=ref_blk, IOSTAT=error)
758 if (ref_blk<0) exit BLOCKS
759
760 if (modify(k)) then
761
762 call BURP_Get_Property(blk, NELE=nele, NVAL=nval, BKSTP=ref_bkstp, IOSTAT=error)
763
764 blk_found = IS_Burp_Btyp(trim(block_type),BLOCK=blk) .and. dim1 == nval
765 if (present(bkstp_opt)) blk_found = blk_found .and. bkstp_opt == ref_bkstp
766
767 if (blk_found) then
768 ! Block to be modified has been found, add new data to block.
769 ! If the varno is already in the block, the new data will overwrite the
770 ! existing data, otherwise will append the new data to the block.
771
772 do iele=1,dim2
773 ivar = BURP_Find_Element(blk, ELEMENT=varno(iele), IOSTAT=error)
774 if (ivar < 0) then
775 ivar=nele+1
776 call BURP_Resize_Block(blk,ADD_NELE=1,IOSTAT=error)
777 call BURP_Set_Element(blk,NELE_IND=ivar,ELEMENT=varno(iele),IOSTAT=error)
778 end if
779
780 do ilev=1,nval
781 call BURP_Set_Rval(blk,NELE_IND=ivar,NVAL_IND=ilev,NT_IND=1,RVAL=new_vals(ilev,iele,k),IOSTAT=error)
782 end do
783 end do
784
785 end if
786 end if
787
788 ! The call to BURP_Write_Block has ENCODE_BLOCK and CONVERT_BLOCK set
789 ! to .true. in all cases, including when the block has not been
790 ! modified, due to problems that can occur when writing blocks
791 ! containing negative integers with datyp=4.
792 call BURP_Write_Block(rep_new, BLOCK=blk, ENCODE_BLOCK=.true., CONVERT_BLOCK=.true., IOSTAT=error)
793
794 end do BLOCKS
795 end if
796 call BURP_Delete_Report(brp,rep,IOSTAT=error)
797 call BURP_Write_Report(brp,rep_new,IOSTAT=error)
798
799 end do REPORTS2
800
801 ! deallocate
802 deallocate(address,modify,new_vals)
803 Call BURP_Free(brp,iostat=error)
804 Call BURP_Free(rep,R2=rep_new,iostat=error)
805 Call BURP_Free(blk,iostat=error)
806
807 end function brpf_obsSub_update
808
809end module burpFiles_mod