NCEPLIBS-bufr 11.7.1
ufbtab.f
Go to the documentation of this file.
1C> @file
2C> @brief Read one or more data values from every data subset in a
3C> BUFR file
4
5C> This subroutine reads through every data subset in a BUFR file
6C> and returns one or more specified data values from each subset.
7C>
8C> <p>This provides a useful way to scan the ranges of one or more
9C> specified data values across an entire BUFR file.
10C>
11C> @author J. Woollen
12C> @date 1994-01-06
13C>
14C> @param[in] LUNIN -- integer: Absolute value is Fortran logical
15C> unit number for BUFR file
16C> @param[out] TAB -- real*8(*,*): Data values
17C> @param[in] I1 -- integer: Actual first dimension of TAB as allocated
18C> within the calling program
19C> @param[in] I2 -- integer: Actual second dimension of TAB as allocated
20C> within the calling program
21C> @param[out] IRET -- integer: Number of data subsets in BUFR file
22C> @param[in] STR -- character*(*): String of blank-separated
23C> Table B mnemonics, in one-to-one correspondence
24C> with the number of data values that will be read
25C> from each data subset within the first dimension of
26C> TAB (see [DX BUFR Tables](@ref dfbftab) for further
27C> information about Table B mnemonics)
28C>
29C> <p>It is the user's responsibility to ensure that TAB is dimensioned
30C> sufficiently large enough to accommodate the number of data values
31C> that are to be read from the BUFR file. Specifically, each row of
32C> TAB will contain the data values read from a different data subset,
33C> so the value I2 must be at least as large as the total number of data
34C> subsets in the BUFR file.
35C>
36C> <p>If logical unit ABS(LUNIN) has already been opened
37C> via a previous call to subroutine openbf(), then this subroutine
38C> will save the current file position, rewind the file to the
39C> beginning, read through the entire file, and then restore it to its
40C> previous file position. Otherwise, if logical unit ABS(LUNIN) has
41C> not already been opened via a previous call to subroutine openbf(),
42C> then this subroutine will open it via an internal call to
43C> subroutine openbf(), read through the entire file, and then close
44C> it via an internal call to subroutine closbf().
45C>
46C> @remarks
47C> - If LUNIN < 0, the number of data subsets in the BUFR file will
48C> still be returned in IRET; however, STR will be ignored,
49C> and all of the values returned in TAB will contain the current
50C> placeholder value for "missing" data.
51C> - If any of the Table B mnemonics in STR are replicated within the
52C> data subset definition for the BUFR file, then this subroutine will
53C> only return the value corresponding to the first occurrence of each
54C> such mnemonic (counting from the beginning of the data subset
55C> definition) within the corresponding row of TAB.
56C>
57C> <b>Program history log:</b>
58C> | Date | Programmer | Comments |
59C> | -----|------------|----------|
60C> | 1994-01-06 | J. Woollen | Original author |
61C> | 1998-07-08 | J. Woollen | Replaced call to Cray library routine "ABORT" with call to new internal routine bort() |
62C> | 1999-11-18 | J. Woollen | The number of BUFR files which can be opened at one time increased from 10 to 32 |
63C> | 2000-09-19 | J. Woollen | Maximum length increased from 10,000 to 20,000 bytes |
64C> | 2002-05-14 | J. Woollen | Removed old Cray compiler directives |
65C> | 2003-11-04 | D. Keyser | Modified to not abort when there are more than I2 data subsets, but instead just process first I2 subsets and print a diagnostic |
66C> | 2003-11-04 | D. Keyser | Increased MAXJL from 15000 to 16000; modified to use rewnbf(); upgraded to allow reading from a file that has already been opened via openbf() |
67C> | 2004-08-09 | J. Ator | Maximum message length increased from 20,000 to 50,000 bytes |
68C> | 2005-09-16 | J. Woollen | upgraded to work for compressed BUFR messages, and to allow for LUNIN < 0 option |
69C> | 2006-04-14 | J. Ator | Add declaration for CREF |
70C> | 2007-01-19 | J. Ator | Replaced call to parseq with call to parstr() |
71C> | 2009-04-21 | J. Ator | Use errwrt() |
72C> | 2009-12-01 | J. Ator | Fix bug for compressed character strings which are identical across all subsets in a single messagE |
73C> | 2010-05-07 | J. Ator | When calling ireadmg(), treat read error as EOF condition |
74C> | 2012-03-02 | J. Ator | Use function ups() |
75C> | 2012-09-15 | J. Woollen | Modified for C/I/O/BUFR interface; added IO type 'INX' to enable open and close for C file without closing FORTRAN file |
76C> | 2014-11-20 | J. Ator | Ensure openbf() has been called at least once before calling status() |
77C> | 2014-12-10 | J. Ator | Use modules instead of COMMON blocks |
78C> | 2016-12-19 | J. Woollen | Fix bug to prevent inventory overflow |
79C> | 2022-05-06 | J. Woollen | Use up8 and upb8 for 8byte integers, use nbmp for usrtpl, add msgunp=1 option |
80C>
81 SUBROUTINE ufbtab(LUNIN,TAB,I1,I2,IRET,STR)
82
83 USE modv_bmiss
84 USE moda_usrint
85 USE moda_msgcwd
86 USE moda_unptyp
87 USE moda_bitbuf
88 USE moda_tables
89
90 COMMON /usrstr/ nnod,ncon,nods(20),nodc(10),ivls(10),kons(10)
91 COMMON /acmode/ iac
92 COMMON /quiet / iprt
93
94 CHARACTER*(*) STR
95 CHARACTER*128 BORT_STR,ERRSTR
96 CHARACTER*40 CREF
97 CHARACTER*10 TGS(100)
98 CHARACTER*8 SUBSET,CVAL
99 equivalence(cval,rval)
100 integer*8 ival,lref,ninc,mps,lps
101 LOGICAL OPENIT,JUST_COUNT
102 real*8 tab(i1,i2),rval,ups
103
104 DATA maxtg /100/
105
106C-----------------------------------------------------------------------
107 mps(node) = 2_8**(ibt(node))-1
108 lps(lbit) = max(2_8**(lbit)-1,1)
109C-----------------------------------------------------------------------
110
111C SET COUNTERS TO ZERO
112C --------------------
113
114 iret = 0
115 irec = 0
116 isub = 0
117 iacc = iac
118
119C CHECK FOR COUNT SUBSET ONLY OPTION (RETURNING THE BUFRLIB'S GLOBAL
120C VALUE FOR MISSING IN OUTPUT ARRAY) INDICATED BY NEGATIVE UNIT
121C ------------------------------------------------------------------
122
123 lunit = abs(lunin)
124 just_count = lunin.LT.lunit
125
126C Make sure OPENBF has been called at least once before trying to
127C call STATUS; otherwise, STATUS might try to access array space
128C that hasn't yet been dynamically allocated.
129 CALL openbf(0,'FIRST',0)
130
131 CALL status(lunit,lun,il,im)
132 openit = il.EQ.0
133
134 IF(openit) THEN
135
136C OPEN BUFR FILE CONNECTED TO UNIT LUNIT IF IT IS NOT ALREADY OPEN
137C ----------------------------------------------------------------
138
139 CALL openbf(lunit,'INX',lunit)
140 ELSE
141
142C IF BUFR FILE ALREADY OPENED, SAVE POSITION & REWIND TO FIRST DATA MSG
143C ---------------------------------------------------------------------
144
145 CALL rewnbf(lunit,0)
146 ENDIF
147
148 iac = 1
149
150C SET THE OUTPUT ARRAY VALUES TO THE BUFRLIB'S GLOBAL VALUE FOR
151C MISSING (BMISS)
152C -------------------------------------------------------------
153
154 DO j=1,i2
155 DO i=1,i1
156 tab(i,j) = bmiss
157 ENDDO
158 ENDDO
159
160 IF(just_count) THEN
161
162C COME HERE FOR COUNT ONLY OPTION (OUTPUT ARRAY VALUES REMAIN MISSING)
163C --------------------------------------------------------------------
164
165 DO WHILE(ireadmg(-lunit,subset,idate).GE.0)
166 iret = iret+nmsub(lunit)
167 ENDDO
168 GOTO 25
169 ENDIF
170
171C OTHERWISE, CHECK FOR SPECIAL TAGS IN STRING
172C -------------------------------------------
173
174 CALL parstr(str,tgs,maxtg,ntg,' ',.true.)
175 DO i=1,ntg
176 IF(tgs(i).EQ.'IREC') irec = i
177 IF(tgs(i).EQ.'ISUB') isub = i
178 ENDDO
179
180C READ A MESSAGE AND PARSE A STRING
181C ---------------------------------
182
18310 IF(ireadmg(-lunit,subset,jdate).LT.0) GOTO 25
184 CALL string(str,lun,i1,0)
185 IF(irec.GT.0) nods(irec) = 0
186 IF(isub.GT.0) nods(isub) = 0
187
188C PARSE THE MESSAGE DEPENDING ON WHETHER COMPRESSED OR NOT
189C --------------------------------------------------------
190
191 if(msgunp(lun)==2) goto 115
192
193C ---------------------------------------------
194C THIS BRANCH IS FOR UNCOMPRESSED MESSAGES
195C ---------------------------------------------
196C SEE IF THERE IS ANOTHER SUBSET IN THE MESSAGE
197C ---------------------------------------------
198
19915 IF(nsub(lun).EQ.msub(lun)) GOTO 10
200 IF(iret+1.GT.i2) GOTO 99
201 iret = iret+1
202
203 DO i=1,nnod
204 nods(i) = abs(nods(i))
205 ENDDO
206
207C PARSE THE STRING NODES FROM A SUBSET
208C ------------------------------------
209
210 if(msgunp(lun)==0) mbit = mbyt(lun)*8 + 16
211 if(msgunp(lun)==1) mbit = mbyt(lun)
212
213 nbit = 0
214 n = 1
215 CALL usrtpl(lun,n,n)
21620 IF(n+1.LE.nval(lun)) THEN
217 n = n+1
218 node = inv(n,lun)
219 mbit = mbit+nbit
220 nbit = ibt(node)
221 IF(itp(node).EQ.1) THEN
222 CALL upb8(ival,nbit,mbit,mbay(1,lun))
223 nbmp=ival; CALL usrtpl(lun,n,nbmp)
224 ENDIF
225 DO i=1,nnod
226 IF(nods(i).EQ.node) THEN
227 IF(itp(node).EQ.1) THEN
228 CALL upb8(ival,nbit,mbit,mbay(1,lun))
229 tab(i,iret) = ival
230 ELSEIF(itp(node).EQ.2) THEN
231 CALL upb8(ival,nbit,mbit,mbay(1,lun))
232 IF(ival.LT.mps(node)) tab(i,iret) = ups(ival,node)
233 ELSEIF(itp(node).EQ.3) THEN
234 cval = ' '
235 kbit = mbit
236 CALL upc(cval,nbit/8,mbay(1,lun),kbit,.true.)
237 tab(i,iret) = rval
238 ENDIF
239 nods(i) = -nods(i)
240 GOTO 20
241 ENDIF
242 ENDDO
243 DO i=1,nnod
244 IF(nods(i).GT.0) GOTO 20
245 ENDDO
246 ENDIF
247
248C UPDATE THE SUBSET POINTERS BEFORE NEXT READ
249C -------------------------------------------
250
251 if(msgunp(lun)==0) then
252 ibit = mbyt(lun)*8
253 CALL upb(nbyt,16,mbay(1,lun),ibit)
254 mbyt(lun) = mbyt(lun) + nbyt
255 elseif(msgunp(lun)==1) then
256 mbyt(lun)=mbit
257 endif
258
259 nsub(lun) = nsub(lun) + 1
260 IF(irec.GT.0) tab(irec,iret) = nmsg(lun)
261 IF(isub.GT.0) tab(isub,iret) = nsub(lun)
262 GOTO 15
263
264C ---------------------------------------------
265C THIS BRANCH IS FOR COMPRESSED MESSAGES
266C ---------------------------------------------
267C STORE ANY MESSAGE AND/OR SUBSET COUNTERS
268C ---------------------------------------------
269
270C CHECK ARRAY BOUNDS
271C ------------------
272
273115 IF(iret+msub(lun).GT.i2) GOTO 99
274
275C STORE MESG/SUBS TOKENS
276C ----------------------
277
278 IF(irec.GT.0.OR.isub.GT.0) THEN
279 DO nsb=1,msub(lun)
280 IF(irec.GT.0) tab(irec,iret+nsb) = nmsg(lun)
281 IF(isub.GT.0) tab(isub,iret+nsb) = nsb
282 ENDDO
283 ENDIF
284
285C SETUP A NEW SUBSET TEMPLATE, PREPARE TO SUB-SURF
286C ------------------------------------------------
287
288 CALL usrtpl(lun,1,1)
289 ibit = mbyt(lun)
290 n = 0
291
292C UNCOMPRESS CHOSEN NODES INTO THE TAB ARRAY (FIRST OCCURANCES ONLY)
293C ------------------------------------------------------------------
294
295C READ ELEMENTS LOOP
296C ------------------
297
298120 DO n=n+1,nval(lun)
299 node = inv(n,lun)
300 nbit = ibt(node)
301 ityp = itp(node)
302
303C FIRST TIME IN RESET NODE INDEXES, OR CHECK FOR NODE(S) STILL NEEDED
304C -------------------------------------------------------------------
305
306 IF(n.EQ.1) THEN
307 DO i=1,nnod
308 nods(i) = abs(nods(i))
309 ENDDO
310 ELSE
311 DO i=1,nnod
312 IF(nods(i).GT.0) GOTO 125
313 ENDDO
314 GOTO 135
315 ENDIF
316
317C FIND THE EXTENT OF THE NEXT SUB-GROUP
318C -------------------------------------
319
320125 IF(ityp.EQ.1.OR.ityp.EQ.2) THEN
321 CALL up8(lref,nbit,mbay(1,lun),ibit)
322 CALL upb(linc, 6,mbay(1,lun),ibit)
323 nibit = ibit + linc*msub(lun)
324 ELSEIF(ityp.EQ.3) THEN
325 cref=' '
326 CALL upc(cref,nbit/8,mbay(1,lun),ibit,.true.)
327 CALL upb(linc, 6,mbay(1,lun),ibit)
328 nibit = ibit + 8*linc*msub(lun)
329 ELSE
330 GOTO 120
331 ENDIF
332
333C PROCESS A TYPE1 NODE INTO NVAL
334C ------------------------------
335
336 IF(ityp.EQ.1) THEN
337 jbit = ibit + linc
338 CALL up8(ninc,linc,mbay(1,lun),jbit)
339 ival = lref+ninc
340 CALL usrtpl(lun,n,int(ival))
341 GOTO 120
342 ENDIF
343
344C LOOP OVER STRING NODES
345C ----------------------
346
347 DO i=1,nnod
348
349C CHOSEN NODES LOOP - KEEP TRACK OF NODES NEEDED AND NODES FOUND
350C --------------------------------------------------------------
351
352 IF(node.NE.nods(i)) GOTO 130
353 nods(i) = -nods(i)
354 lret = iret
355
356C PROCESS A FOUND NODE INTO TAB
357C -----------------------------
358
359 IF(ityp.EQ.1.OR.ityp.EQ.2) THEN
360 DO nsb=1,msub(lun)
361 jbit = ibit + linc*(nsb-1)
362 CALL up8(ninc,linc,mbay(1,lun),jbit)
363 ival = lref+ninc
364 lret = lret+1
365 IF(ninc.LT.lps(linc)) tab(i,lret) = ups(ival,node)
366 ENDDO
367 ELSEIF(ityp.EQ.3) THEN
368 DO nsb=1,msub(lun)
369 IF(linc.EQ.0) THEN
370 cval = cref
371 ELSE
372 jbit = ibit + linc*(nsb-1)*8
373 cval = ' '
374 CALL upc(cval,linc,mbay(1,lun),jbit,.true.)
375 ENDIF
376 lret = lret+1
377 tab(i,lret) = rval
378 ENDDO
379 ELSE
380 CALL bort('UFBTAB - INVALID ELEMENT TYPE SPECIFIED')
381 ENDIF
382
383C END OF LOOPS FOR COMPRESSED MESSAGE PARSING
384C -------------------------------------------
385
386130 CONTINUE
387 ENDDO
388 ibit = nibit
389
390C END OF READ ELEMENTS LOOP
391C -------------------------
392
393 ENDDO
394135 iret = iret+msub(lun)
395
396C END OF MESSAGE PARSING - GO BACK FOR ANOTHER
397C --------------------------------------------
398
399 GOTO 10
400
401C -------------------------------------------
402C ERROR PROCESSING AND EXIT ROUTES BELOW
403C -------------------------------------------
404C EMERGENCY ROOM TREATMENT FOR ARRAY OVERFLOW
405C -------------------------------------------
406
40799 nrep = iret
408 DO WHILE(ireadsb(lunit).EQ.0)
409 nrep = nrep+1
410 ENDDO
411 DO WHILE(ireadmg(-lunit,subset,jdate).GE.0)
412 nrep = nrep+nmsub(lunit)
413 ENDDO
414 IF(iprt.GE.0) THEN
415 CALL errwrt('+++++++++++++++++++++WARNING+++++++++++++++++++++++')
416 WRITE ( unit=errstr, fmt='(A,A,I8,A,A)' )
417 . 'BUFRLIB: UFBTAB - THE NO. OF DATA SUBSETS IN THE BUFR FILE ',
418 . .GT.'IS LIMIT OF ', i2, ' IN THE 4TH ARG. (INPUT) - ',
419 . 'INCOMPLETE READ'
420 CALL errwrt(errstr)
421 WRITE ( unit=errstr, fmt='(A,I8,A,I8,A)' )
422 . '>>>UFBTAB STORED ', iret, ' REPORTS OUT OF ', nrep, '<<<'
423 CALL errwrt(errstr)
424 CALL errwrt('+++++++++++++++++++++WARNING+++++++++++++++++++++++')
425 CALL errwrt(' ')
426 ENDIF
427
428
42925 IF(openit) THEN
430
431C CLOSE BUFR FILE IF IT WAS OPENED HERE
432C -------------------------------------
433
434 CALL closbf(lunit)
435 ELSE
436
437C RESTORE BUFR FILE TO PREV. STATUS & POSITION IF NOT ORIG. OPENED HERE
438C ---------------------------------------------------------------------
439
440 CALL rewnbf(lunit,1)
441 ENDIF
442
443 iac = iacc
444
445C EXITS
446C -----
447
448 RETURN
449 END
subroutine bort(STR)
This subroutine calls subroutine errwrt() to log an error message, then calls subroutine bort_exit() ...
Definition: bort.f:23
subroutine closbf(LUNIT)
This subroutine closes the connection between logical unit LUNIT and the BUFRLIB software.
Definition: closbf.f:35
subroutine errwrt(STR)
This subroutine allows the user to specify a custom location for the logging of error and diagnostic ...
Definition: errwrt.f:42
function ireadmg(LUNIT, SUBSET, IDATE)
This function calls BUFRLIB subroutine readmg() and passes back its return code as the function value...
Definition: ireadmg.f:40
function ireadsb(LUNIT)
This function calls BUFRLIB subroutine readsb() and passes back its return code as the function value...
Definition: ireadsb.f:31
This module contains array and variable declarations used to store BUFR messages internally for multi...
Definition: moda_bitbuf.F:10
integer, dimension(:), allocatable mbyt
Length (in bytes) of current BUFR message for each internal I/O stream.
Definition: moda_bitbuf.F:25
integer, dimension(:,:), allocatable mbay
Current BUFR message for each internal I/O stream.
Definition: moda_bitbuf.F:26
This module contains array and variable declarations used to store the internal jump/link table.
Definition: moda_tables.F:13
integer, dimension(:), allocatable itp
Integer type values corresponding to typ:
Definition: moda_tables.F:141
integer, dimension(:), allocatable ibt
Bit widths corresponding to tag and typ:
Definition: moda_tables.F:138
This module declares and initializes the BMISS variable.
Definition: modv_BMISS.f90:9
real *8, public bmiss
Current placeholder value to represent "missing" data when reading from or writing to BUFR files; thi...
Definition: modv_BMISS.f90:15
function nmsub(LUNIT)
This function returns the total number of data subsets available within the BUFR message that was mos...
Definition: nmsub.f:30
subroutine openbf(LUNIT, IO, LUNDX)
This subroutine connects a new file to the BUFRLIB software for input or output operations.
Definition: openbf.f:139
subroutine parstr(STR, TAGS, MTAG, NTAG, SEP, LIMIT80)
THIS SUBROUTINE PARSES A STRING CONTAINING ONE OR MORE SUBSTRINGS INTO AN ARRAY OF SUBSTRINGS.
Definition: parstr.f:38
subroutine rewnbf(LUNIT, ISR)
THIS SUBROUTINE, DEPENDING ON THE VALUE OF ISR, WILL EITHER: 1) STORE THE CURRENT PARAMETERS ASSOCIAT...
Definition: rewnbf.f:65
subroutine status(LUNIT, LUN, IL, IM)
This subroutine checks whether a specified Fortran logical unit number is currently connected to the ...
Definition: status.f:56
subroutine string(STR, LUN, I1, IO)
THIS SUBROUTINE CHECKS TO SEE IF A USER-SPECIFIED CHARACTER STRING IS IN THE STRING CACHE (ARRAYS IN ...
Definition: string.f:59
subroutine ufbtab(LUNIN, TAB, I1, I2, IRET, STR)
This subroutine reads through every data subset in a BUFR file and returns one or more specified data...
Definition: ufbtab.f:82
subroutine up8(nval, nbits, ibay, ibit)
THIS SUBROUTINE UNPACKS AND RETURNS AN 8-BYTE INTEGER CONTAINED WITHIN NBITS BITS OF IBAY,...
Definition: up8.f:41
subroutine upb8(nval, nbits, ibit, ibay)
THIS SUBROUTINE UNPACKS AND RETURNS AN 8-BYTE INTEGER CONTAINED WITHIN NBITS BITS OF IBAY,...
Definition: upb8.f:36
subroutine upb(NVAL, NBITS, IBAY, IBIT)
THIS SUBROUTINE UNPACKS AND RETURNS A BINARY INTEGER CONTAINED WITHIN NBITS BITS OF IBAY,...
Definition: upb.f:50
subroutine upc(CHR, NCHR, IBAY, IBIT, CNVNULL)
THIS SUBROUTINE UNPACKS AND RETURNS A CHARACTER STRING OF LENGTH NCHR CONTAINED WITHIN NCHR BYTES OF ...
Definition: upc.f:50
real *8 function ups(IVAL, NODE)
THIS FUNCTION UNPACKS A REAL*8 USER VALUE FROM A PACKED BUFR INTEGER BY APPLYING THE PROPER SCALE AND...
Definition: ups.f:33
subroutine usrtpl(LUN, INVN, NBMP)
THIS SUBROUTINE STORES THE SUBSET TEMPLATE INTO INTERNAL SUBSET ARRAYS IN MODULE USRINT FOR CASES OF ...
Definition: usrtpl.f:52