NCEPLIBS-bufr 11.7.1
ufbseq.f
Go to the documentation of this file.
1C> @file
2C> @brief Read/write an entire sequence of data values from/to
3C> a data subset.
4
5C> This subroutine reads or writes an entire sequence of data values
6C> from or to the BUFR data subset that is currently open within the
7C> BUFRLIB internal arrays. The direction of the data transfer is
8C> determined by the context of ABS(LUNIN):
9C> - If ABS(LUNIN) points to a file that was previously opened for
10C> input using subroutine openbf(), then data values are read from
11C> the current data subset.
12C> - If ABS(LUNIN) points to a file that was previously opened for
13C> output using subroutine openbf(), then data values are written to
14C> the current data subset.
15C>
16C> <p>This subroutine is specifically designed for use with a single
17C> Table A or Table D mnemonic. In the latter case, the mnemonic
18C> may be replicated within the overall subset definition, and in
19C> which case the subroutine will return all data values within all
20C> replications of the sequence defined by the mnemonic. But in
21C> either case, the mnemonic itself may contain, within its own
22C> sequence definition, any number of data values defined by Table B
23C> mnemonics and/or subsequences of data values defined by other
24C> Table D mnemonics, and any such subsequences may themselves be
25C> replicated using any manner of fixed or delayed replication.
26C> See [DX BUFR Tables](@ref ufbsubs) for more details including
27C> an example use case, and see also subroutines ufbint(), ufbrep()
28C> and ufbstp() which are also used to read/write one or more data
29C> values from/to a data subset but cannot themselves be directly
30C> used with Table A or Table D mnemonics.
31C>
32C> @authors J. Woollen
33C> @authors J. Ator
34C> @date 2000-09-19
35C>
36C> @param[in] LUNIN -- integer: Absolute value is Fortran logical
37C> unit number for BUFR file
38C> @param[in,out] USR -- real*8(*,*): Data values
39C> - If ABS(LUNIN) was opened for input, then
40C> USR is output from this subroutine and
41C> contains data values that were read
42C> from the current data subset.
43C> - If ABS(LUNIN) was opened for output, then
44C> USR is input to this subroutine and
45C> contains data values that are to be
46C> written to the current data subset.
47C> @param[in] I1 -- integer: Actual first dimension of USR as allocated
48C> within the calling program
49C> @param[in] I2 -- integer:
50C> - If ABS(LUNIN) was opened for input, then I2
51C> must be set equal to the actual second dimension
52C> of USR as allocated within the calling program
53C> - If ABS(LUNIN) was opened for output, then I2
54C> must be set equal to the number of replications
55C> of STR that are to be written to the data subset
56C> @param[out] IRET -- integer: Number of replications of STR that were
57C> actually read/written from/to the data subset
58C> @param[in] STR -- character*(*): String consisting of a single Table A
59C> or Table D mnemonic whose sequence definition is
60C> in one-to-one correspondence with the number of data
61C> values that will be read/written from/to the data
62C> subset within the first dimension of USR
63C> (see [DX BUFR Tables](@ref dfbftab) for further
64C> information about Table A and Table D mnemonics)
65C>
66C> <p>It is the user's responsibility to ensure that USR is dimensioned
67C> sufficiently large enough to accommodate the number of data values
68C> that are to be read from or written to the data subset. Note also
69C> that USR is an array of real*8 values; therefore, any data that are
70C> to be written out as character (i.e. CCITT IA5) values in
71C> BUFR must be converted from character into real*8 format within the
72C> application program before calling this subroutine. Conversely,
73C> when this subroutine is being used to read character values from a
74C> data subset, the value that is returned will be in real*8 format
75C> and must be converted back into character format by the application
76C> program before it can be used as such. Alternatively, there are
77C> different subroutines such as readlc() and writlc() which can be
78C> used to read/write character data directly from/to a data subset
79C> without the need to convert from/to real*8 format as an intermediate
80C> step.
81C>
82C> <p>Numeric (i.e. non-character) data values within USR are always in
83C> the exact units specified for the corresponding mnemonic within the
84C> relevant DX or master BUFR table, without any scale or reference
85C> values applied. Specifically, this means that, when writing
86C> data values into an output subset, the user only needs to store each
87C> respective value into USR using the units specified within the table,
88C> and the BUFRLIB software will take care of any necessary scaling or
89C> referencing of the value before it is actually encoded into BUFR.
90C> Conversely, when reading data values from an input subset, the
91C> values returned in USR are already de-scaled and de-referenced and,
92C> thus, are already in the exact units that were defined for the
93C> corresponding mnemonics within the table.
94C>
95C> <p>"Missing" values in USR are always denoted by a unique
96C> placeholder value. This placeholder value is initially set
97C> to a default value of 10E10_8, but it can be reset to
98C> any substitute value of the user's choice via a separate
99C> call to subroutine setbmiss(). In any case, and whenever this
100C> subroutine is used to read data values from an input subset, any
101C> returned value in USR can be easily checked for equivalence to the
102C> current placeholder value via a call to function ibfms(), and a
103C> positive result means that the value for the corresponding mnemonic
104C> was encoded as "missing" in BUFR (i.e. all bits set to 1) within the
105C> original data subset. Conversely, whenever this subroutine
106C> is used to write data values to an output subset, the current
107C> placeholder value can be obtained via a separate call to function
108C> getbmiss(), and the resulting value can then be stored into the
109C> USR array whereever the user desires a BUFR "missing" value (i.e.
110C> all bits set to 1) to be encoded for the corresponding mnemonic
111C> within the output subset.
112C>
113C> @remarks
114C> - If LUNIN < 0, and if ABS(LUNIN) points to a file that is open
115C> for output (writing BUFR), then the subroutine will treat the file
116C> pointed to by ABS(LUNIN) as though it was open for input (reading
117C> BUFR). This is a special capability for use by some applications
118C> that need to read certain values back out from a BUFR file during
119C> the same time that it is in the process of being written to.
120C> - If ABS(LUNIN) points to a file that is open for output
121C> (writing BUFR), and if the data values to be written are part of
122C> a sequence replicated using delayed replication, then a call to
123C> subroutine drfini() must be made prior to calling this subroutine,
124C> in order to pre-allocate the necessary internal array space for
125C> the number of replications of the sequence.
126C>
127C> <b>Program history log:</b>
128C> | Date | Programmer | Comments |
129C> | -----|------------|----------|
130C> | 2000-09-19 | J. Woollen | Original author |
131C> | 2002-05-14 | J. Woollen | Improved generality; previously ufbseq would not recognize compressed delayed replication as a legitimate data structure |
132C> | 2003-05-19 | J. Woollen | Corrected the logic array of exit conditions for the subroutine; previously, in some cases, proper exits were missed, generating bogus error messages |
133C> | 2003-11-04 | S. Bender | Added remarks and routine interdependencies |
134C> | 2003-11-04 | D. Keyser | Unified/portable for WRF; added documentation; outputs more complete diagnostic info when routine terminates abnormally |
135C> | 2004-08-18 | J. Ator | Added SAVE for IFIRST1 and IFIRST2 flags |
136C> | 2007-01-19 | J. Ator | Replaced call to parseq with call to parstr() |
137C> | 2009-04-21 | J. Ator | Use errwrt() |
138C> | 2014-09-10 | J. Ator | Fix bug involving nested delayed replication where first replication of outer sequence does not contain a replication of the inner sequence |
139C> | 2014-12-10 | J. Ator | Use modules instead of COMMON blocks |
140C> | 2020-03-06 | J. Ator | No longer abort when reading data and number of available levels is greater than I2; instead just return first I2 levels and print a diagnostic message |
141C>
142 SUBROUTINE ufbseq(LUNIN,USR,I1,I2,IRET,STR)
143
144 USE modv_bmiss
145 USE moda_usrint
146 USE moda_msgcwd
147 USE moda_tables
148
149 parameter(mtag=10)
150
151 COMMON /quiet / iprt
152
153 CHARACTER*(*) STR
154 CHARACTER*156 BORT_STR
155 CHARACTER*128 ERRSTR
156 CHARACTER*10 TAGS(MTAG)
157 real*8 usr(i1,i2)
158
159 DATA ifirst1/0/,ifirst2/0/
160
161 SAVE ifirst1, ifirst2
162
163C----------------------------------------------------------------------
164C----------------------------------------------------------------------
165
166 iret = 0
167
168C CHECK THE FILE STATUS AND I-NODE
169C --------------------------------
170
171 lunit = abs(lunin)
172 CALL status(lunit,lun,il,im)
173 IF(il.EQ.0) GOTO 900
174 IF(im.EQ.0) GOTO 901
175
176 io = min(max(0,il),1)
177 IF(lunit.NE.lunin) io = 0
178
179 IF(i1.LE.0) THEN
180 IF(iprt.GE.0) THEN
181 CALL errwrt('+++++++++++++++++++++WARNING+++++++++++++++++++++++')
182 errstr = .LE.'BUFRLIB: UFBSEQ - 3rd ARG. (INPUT) IS 0, ' //
183 . 'SO RETURN WITH 5th ARG. (IRET) = 0; 6th ARG. (STR) ='
184 CALL errwrt(errstr)
185 CALL errwrt(str)
186 CALL errwrt('+++++++++++++++++++++WARNING+++++++++++++++++++++++')
187 CALL errwrt(' ')
188 ENDIF
189 GOTO 100
190 ELSEIF(i2.LE.0) THEN
191 IF(iprt.EQ.-1) ifirst1 = 1
192 IF(io.EQ.0 .OR. ifirst1.EQ.0 .OR. iprt.GE.1) THEN
193 CALL errwrt('+++++++++++++++++++++WARNING+++++++++++++++++++++++')
194 errstr = .LE.'BUFRLIB: UFBSEQ - 4th ARG. (INPUT) IS 0, ' //
195 . 'SO RETURN WITH 5th ARG. (IRET) = 0; 6th ARG. (STR) ='
196 CALL errwrt(errstr)
197 CALL errwrt(str)
198 IF(iprt.EQ.0 .AND. io.EQ.1) THEN
199 errstr = 'Note: Only the first occurrence of this WARNING ' //
200 . 'message is printed, there may be more. To output all ' //
201 . 'such messages,'
202 CALL errwrt(errstr)
203 errstr = 'modify your application program to add ' //
204 . '"CALL OPENBF(0,''QUIET'',1)" prior to the first call ' //
205 . 'to a BUFRLIB routine.'
206 CALL errwrt(errstr)
207 ENDIF
208 CALL errwrt('+++++++++++++++++++++WARNING+++++++++++++++++++++++')
209 CALL errwrt(' ')
210 ifirst1 = 1
211 ENDIF
212 GOTO 100
213 ENDIF
214
215C CHECK FOR VALID SEQUENCE AND SEQUENCE LENGTH ARGUMENTS
216C ------------------------------------------------------
217
218 CALL parstr(str,tags,mtag,ntag,' ',.true.)
219 IF(ntag.LT.1) GOTO 902
220 IF(ntag.GT.1) GOTO 903
221 IF(i1.LE.0) GOTO 904
222 IF(i2.LE.0) GOTO 905
223 IF(inode(lun).NE.inv(1,lun)) GOTO 906
224
225
226C INITIALIZE USR ARRAY PRECEEDING AN INPUT OPERATION
227C --------------------------------------------------
228
229 IF(io.EQ.0) THEN
230 DO j=1,i2
231 DO i=1,i1
232 usr(i,j) = bmiss
233 ENDDO
234 ENDDO
235 ENDIF
236
237
238C FIND THE PARAMETERS OF THE SPECIFIED SEQUENCE
239C ---------------------------------------------
240
241 DO node=inode(lun),isc(inode(lun))
242 IF(str.EQ.tag(node)) THEN
243 IF(typ(node).EQ.'SEQ'.OR.typ(node).EQ.'RPC') THEN
244 ins1 = 1
2455 ins1 = invtag(node,lun,ins1,nval(lun))
246 IF(ins1.EQ.0) GOTO 200
247 IF(typ(node).EQ.'RPC'.AND.val(ins1,lun).EQ.0.) THEN
248 ins1 = ins1+1
249 GOTO 5
250 ENDIF
251 ins2 = invtag(node,lun,ins1+1,nval(lun))
252 IF(ins2.EQ.0) ins2 = 10e5
253 nods = node
254 DO WHILE(link(nods).EQ.0.AND.jmpb(nods).GT.0)
255 nods = jmpb(nods)
256 ENDDO
257 IF(link(nods).EQ.0) THEN
258 insx = nval(lun)
259 ELSEIF(link(nods).GT.0) THEN
260 insx = invwin(link(nods),lun,ins1+1,nval(lun))-1
261 ENDIF
262 ins2 = min(ins2,insx)
263 ELSEIF(typ(node).EQ.'SUB') THEN
264 ins1 = 1
265 ins2 = nval(lun)
266 ELSE
267 GOTO 907
268 ENDIF
269 nseq = 0
270 DO isq=ins1,ins2
271 ityp = itp(inv(isq,lun))
272 IF(ityp.GT.1) nseq = nseq+1
273 ENDDO
274 IF(nseq.GT.i1) GOTO 908
275 GOTO 1
276 ENDIF
277 ENDDO
278
279 GOTO 200
280
281C FRAME A SECTION OF THE BUFFER - RETURN WHEN NO FRAME
282C ----------------------------------------------------
283
2841 ins1 = invtag(node,lun,ins1,nval(lun))
285 IF(ins1.GT.nval(lun)) GOTO 200
286 IF(ins1.GT.0) THEN
287 IF(typ(node).EQ.'RPC'.AND.val(ins1,lun).EQ.0.) THEN
288 ins1 = ins1+1
289 GOTO 1
290 ELSEIF(io.EQ.0.AND.iret+1.GT.i2) THEN
291 IF(iprt.GE.0) THEN
292 CALL errwrt('++++++++++++BUFR ARCHIVE LIBRARY+++++++++++++++')
293 WRITE ( unit=errstr, fmt='(A,I5,A,A,A)' )
294 . 'BUFRLIB: UFBSEQ - INCOMPLETE READ; ONLY THE FIRST ', i2,
295 . ' (=4TH INPUT ARG.) ''LEVELS'' OF INPUT MNEMONIC ', tags(1),
296 . ' WERE READ'
297 CALL errwrt(errstr)
298 CALL errwrt('++++++++++++BUFR ARCHIVE LIBRARY+++++++++++++++')
299 CALL errwrt(' ')
300 ENDIF
301 GOTO 200
302 ENDIF
303 ELSEIF(ins1.EQ.0) THEN
304 IF(io.EQ.1.AND.iret.LT.i2) GOTO 910
305 ELSE
306 GOTO 911
307 ENDIF
308
309 IF(ins1.EQ. 0) GOTO 200
310 IF(iret.EQ.i2) GOTO 200
311
312 iret = iret+1
313 ins1 = ins1+1
314
315C READ/WRITE USER VALUES
316C ----------------------
317
318 j = ins1
319 DO i=1,nseq
320 DO WHILE(itp(inv(j,lun)).LT.2)
321 j = j+1
322 ENDDO
323 IF(io.EQ.0) usr(i,iret) = val(j,lun )
324 IF(io.EQ.1) val(j,lun ) = usr(i,iret)
325 j = j+1
326 ENDDO
327
328C CHECK FOR NEXT FRAME
329C --------------------
330
331 GOTO 1
332
333200 CONTINUE
334
335 IF(iret.EQ.0) THEN
336 IF(io.EQ.0) THEN
337 IF(iprt.GE.1) THEN
338 CALL errwrt('+++++++++++++++++++++WARNING+++++++++++++++++++++++')
339 errstr = 'BUFRLIB: UFBSEQ - NO SPECIFIED VALUES READ IN, ' //
340 . 'SO RETURN WITH 5th ARG. (IRET) = 0; 6th ARG. (STR) ='
341 CALL errwrt(errstr)
342 CALL errwrt(str)
343 CALL errwrt('+++++++++++++++++++++WARNING+++++++++++++++++++++++')
344 CALL errwrt(' ')
345 ENDIF
346 ELSE
347 IF(iprt.EQ.-1) ifirst2 = 1
348 IF(ifirst2.EQ.0 .OR. iprt.GE.1) THEN
349 CALL errwrt('+++++++++++++++++++++WARNING+++++++++++++++++++++++')
350 errstr = 'BUFRLIB: UFBSEQ - NO SPECIFIED VALUES WRITTEN OUT, ' //
351 . 'SO RETURN WITH 5th ARG. (IRET) = 0; 6th ARG. (STR) ='
352 CALL errwrt(errstr)
353 CALL errwrt(str)
354 CALL errwrt('MAY NOT BE IN THE BUFR TABLE(?)')
355 IF(iprt.EQ.0) THEN
356 errstr = 'Note: Only the first occurrence of this WARNING ' //
357 . 'message is printed, there may be more. To output all ' //
358 . 'such messages,'
359 CALL errwrt(errstr)
360 errstr = 'modify your application program to add ' //
361 . '"CALL OPENBF(0,''QUIET'',1)" prior to the first call ' //
362 . 'to a BUFRLIB routine.'
363 CALL errwrt(errstr)
364 ENDIF
365 CALL errwrt('+++++++++++++++++++++WARNING+++++++++++++++++++++++')
366 CALL errwrt(' ')
367 ifirst2 = 1
368 ENDIF
369 ENDIF
370 ENDIF
371
372C EXITS
373C -----
374
375100 RETURN
376900 CALL bort('BUFRLIB: UFBSEQ - BUFR FILE IS CLOSED, IT MUST BE'//
377 . ' OPEN')
378901 CALL bort('BUFRLIB: UFBSEQ - A MESSAGE MUST BE OPEN IN BUFR '//
379 . 'FILE, NONE ARE')
380902 WRITE(bort_str,'("BUFRLIB: UFBSEQ - THE INPUT STRING (",A,") '//
381 . 'DOES NOT CONTAIN ANY MNEMONICS!!")') str
382 CALL bort(bort_str)
383903 WRITE(bort_str,'("BUFRLIB: UFBSEQ - THERE CANNOT BE MORE THAN '//
384 . 'ONE MNEMONIC IN THE INPUT STRING (",A,") (HERE THERE ARE ",I3'//
385 . ',")")') str,ntag
386 CALL bort(bort_str)
387904 WRITE(bort_str,'("BUFRLIB: UFBSEQ - THIRD ARGUMENT (INPUT) MUST'//
388 . .GT.' BE ZERO (HERE IT IS",I4,") - INPUT MNEMONIC IS ",A)')
389 . i1,tags(1)
390 CALL bort(bort_str)
391905 WRITE(bort_str,'("BUFRLIB: UFBSEQ - FOURTH ARGUMENT (INPUT) '//
392 . .GT.'MUST BE ZERO (HERE IT IS",I4,") - INPUT MNEMONIC IS ",A)')
393 . i2,tags(1)
394 CALL bort(bort_str)
395906 CALL bort('BUFRLIB: UFBSEQ - LOCATION OF INTERNAL TABLE FOR '//
396 . 'BUFR FILE DOES NOT AGREE WITH EXPECTED LOCATION IN INTERNAL '//
397 . 'SUBSET ARRAY')
398907 WRITE(bort_str,'("BUFRLIB: UFBSEQ - INPUT MNEMONIC ",A," MUST '//
399 . 'BE A SEQUENCE (HERE IT IS TYPE """,A,""")")') tags(1),typ(node)
400 CALL bort(bort_str)
401908 WRITE(bort_str,'("BUFRLIB: UFBSEQ - INPUT SEQ. MNEM. ",A,'//
402 . .GT.'" CONSISTS OF",I4," TABLE B MNEM., THE MAX. SPECIFIED IN'//
403 . ' (INPUT) ARGUMENT 3 (",I3,")")') tags(1),nseq,i1
404 CALL bort(bort_str)
405910 WRITE(bort_str,'("BUFRLIB: UFBSEQ - NO. OF ''LEVELS'' WRITTEN '//
406 . .LT.'(",I5,") NO. REQUESTED (",I5,") - INCOMPLETE WRITE '//
407 . '(INPUT MNEMONIC IS ",A,")")') iret,i2,tags(1)
408 CALL bort(bort_str)
409911 WRITE(bort_str,.GE.'("BUFRLIB: UFBSEQ - VARIABLE INS1 MUST BE '//
410 . 'ZERO, HERE IT IS",I4," - INPUT MNEMONIC IS ",A)') ins1,tags(1)
411 CALL bort(bort_str)
412 END
subroutine bort(STR)
This subroutine calls subroutine errwrt() to log an error message, then calls subroutine bort_exit() ...
Definition: bort.f:23
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 invtag(NODE, LUN, INV1, INV2)
THIS FUNCTION LOOKS FOR A SPECIFIED MNEMONIC WITHIN THE PORTION OF THE CURRENT SUBSET BUFFER BOUNDED ...
Definition: invtag.f:50
function invwin(NODE, LUN, INV1, INV2)
THIS FUNCTION LOOKS FOR A SPECIFIED NODE WITHIN THE PORTION OF THE CURRENT SUBSET BUFFER BOUNDED BY T...
Definition: invwin.f:49
This module contains array and variable declarations used to store the internal jump/link table.
Definition: moda_tables.F:13
integer, dimension(:), allocatable link
Link indices corresponding to tag, typ and jmpb:
Definition: moda_tables.F:136
integer, dimension(:), allocatable itp
Integer type values corresponding to typ:
Definition: moda_tables.F:141
integer, dimension(:), allocatable isc
Scale factors corresponding to tag and typ:
Definition: moda_tables.F:140
character *3, dimension(:), allocatable typ
Type indicators corresponding to tag:
Definition: moda_tables.F:133
character *10, dimension(:), allocatable tag
Mnemonics in the jump/link table.
Definition: moda_tables.F:132
integer, dimension(:), allocatable jmpb
Jump backward indices corresponding to tag and typ:
Definition: moda_tables.F:137
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
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 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 ufbseq(LUNIN, USR, I1, I2, IRET, STR)
This subroutine reads or writes an entire sequence of data values from or to the BUFR data subset tha...
Definition: ufbseq.f:143