NCEPLIBS-bufr  12.0.0
wrcmps.f
Go to the documentation of this file.
1 C> @file
2 C> @brief Write a compressed BUFR data subset.
3 C>
4 C> @author Woollen @date 2002-05-14
5 
6 C> This subroutine packs up the current subset within memory
7 C> (array ibay in module @ref moda_bitbuf), storing it for compression.
8 C> It then tries to add it to the compressed BUFR message that is
9 C> currently open within memory for abs(lunix) (array mgwa). If the
10 C> subset will not fit into the currently open message, then that
11 C> compressed message is flushed to lunix and a new one is created in
12 C> order to hold the current subset (still stored for compression).
13 C> This subroutine performs functions similar to NCEPLIBS-bufr
14 C> subroutine msgupd() except that it acts on compressed bufr messages.
15 C>
16 C> @param[in] lunix - integer: absolute value is fortran logical unit
17 C> number for bufr file (if lunix is less than zero, this is a "flush"
18 C> call and the buffer must be cleared out)
19 C>
20 C> @author Woollen @date 2002-05-14
21 
22  SUBROUTINE wrcmps(LUNIX)
23 
24  USE modv_mxcdv
25  USE modv_mxcsb
26 
27  USE moda_usrint
28  USE moda_msgcwd
29  USE moda_bitbuf
30  USE moda_mgwa
31  USE moda_tables
32  USE moda_comprx
33  USE moda_comprs
34  USE moda_s01cm
35 
36  COMMON /maxcmp/ maxcmb,maxrow,maxcol,ncmsgs,ncsubs,ncbyts
37 
38  CHARACTER*128 BORT_STR
39  CHARACTER*8 SUBSET
40  CHARACTER*1 CZERO
41 
42  LOGICAL MSGFULL
43 
44 C NOTE THE FOLLOWING LOGICAL FLAGS:
45 C FIRST - KEEPS TRACK OF WHETHER THE CURRENT SUBSET IS THE
46 C FIRST SUBSET OF A NEW MESSAGE
47 C FLUSH - KEEPS TRACK OF WHETHER THIS SUBROUTINE WAS CALLED
48 C WITH LUNIX < 0 IN ORDER TO FORCIBLY FLUSH ANY
49 C PARTIALLY-COMPLETED MESSAGE WITHIN MEMORY (PRESUMABLY
50 C IMMEDIATELY PRIOR TO EXITING THE CALLING PROGRAM!)
51 C WRIT1 - KEEPS TRACK OF WHETHER THE CURRENT MESSAGE NEEDS
52 C TO BE WRITTEN OUT
53 
54  LOGICAL FIRST,KMISS,EDGE4
55 
56  DATA first /.true./
57 
58  SAVE first,ibyt,jbit,subset,edge4
59 
60 C-----------------------------------------------------------------------
61  rln2 = 1./log(2.)
62 C-----------------------------------------------------------------------
63 
64 C GET THE UNIT AND SUBSET TAG
65 C ---------------------------
66 
67  lunit = abs(lunix)
68  CALL status(lunit,lun,il,im)
69 
70 C IF THIS IS A "FIRST" CALL, THEN INITIALIZE SOME VALUES IN
71 C ORDER TO PREPARE FOR THE CREATION OF A NEW COMPRESSED BUFR
72 C MESSAGE FOR OUTPUT.
73 
74  1 IF(first) THEN
75  kbyt = 0
76  ncol = 0
77  lunc = lun
78  nrow = nval(lun)
79  subset = tag(inode(lun))(1:8)
80  first = .false.
81  FLUSH = .false.
82  writ1 = .false.
83 
84 C THIS CALL TO CMSGINI IS DONE SOLELY IN ORDER TO DETERMINE
85 C HOW MANY BYTES (KBYT) WILL BE TAKEN UP IN A MESSAGE BY
86 C THE INFORMATION IN SECTIONS 0, 1, 2 AND 3. THIS WILL
87 C ALLOW US TO KNOW HOW MANY COMPRESSED DATA SUBSETS WILL
88 C FIT INTO SECTION 4 WITHOUT OVERFLOWING MAXCMB. LATER ON,
89 C A SEPARATE CALL TO CMSGINI WILL BE DONE TO ACTUALLY
90 C INITIALIZE SECTIONS 0, 1, 2 AND 3 OF THE FINAL COMPRESSED
91 C BUFR MESSAGE THAT WILL BE WRITTEN OUT.
92 
93  CALL cmsgini(lun,mbay(1,lun),subset,idate(lun),ncol,kbyt)
94 
95 C CHECK THE EDITION NUMBER OF THE BUFR MESSAGE TO BE CREATED
96 
97  edge4 = .false.
98  IF(ns01v.GT.0) THEN
99  ii = 1
100  DO WHILE ( (.NOT.edge4) .AND. (ii.LE.ns01v) )
101  IF( (cmnem(ii).EQ.'BEN') .AND. (ivmnem(ii).GE.4) ) THEN
102  edge4 = .true.
103  ELSE
104  ii = ii+1
105  ENDIF
106  ENDDO
107  ENDIF
108 
109  ENDIF
110 
111  IF(lun.NE.lunc) GOTO 900
112 
113 C IF THIS IS A "FLUSH" CALL, THEN CLEAR OUT THE BUFFER (NOTE THAT
114 C THERE IS NO CURRENT SUBSET TO BE STORED!) AND PREPARE TO WRITE
115 C THE FINAL COMPRESSED BUFR MESSAGE.
116 
117  IF(lunix.LT.0) THEN
118  IF(ncol.EQ.0) GOTO 100
119  IF(ncol.GT.0) THEN
120  FLUSH = .true.
121  writ1 = .true.
122  icol = 1
123  GOTO 20
124  ENDIF
125  ENDIF
126 
127 C CHECK ON SOME OTHER POSSIBLY PROBLEMATIC SITUATIONS
128 C ---------------------------------------------------
129 
130  IF(ncol+1.GT.mxcsb) THEN
131  GOTO 50
132  ELSEIF(nval(lun).NE.nrow) THEN
133  writ1 = .true.
134  icol = 1
135  GOTO 20
136  ELSEIF(nval(lun).GT.mxcdv) THEN
137  GOTO 901
138  ENDIF
139 
140 C STORE THE NEXT SUBSET FOR COMPRESSION
141 C -------------------------------------
142 
143 C WILL THE CURRENT SUBSET FIT INTO THE CURRENT MESSAGE?
144 C (UNFORTUNATELY, THE ONLY WAY TO FIND OUT IS TO ACTUALLY
145 C RE-DO THE COMPRESSION BY RE-COMPUTING ALL OF THE LOCAL
146 C REFERENCE VALUES, INCREMENTS, ETC.)
147 
148  ncol = ncol+1
149  icol = ncol
150  ibit = 16
151  DO i=1,nval(lun)
152  node = inv(i,lun)
153  ityp(i) = itp(node)
154  iwid(i) = ibt(node)
155  IF(ityp(i).EQ.1.OR.ityp(i).EQ.2) THEN
156  CALL up8(matx(i,ncol),ibt(node),ibay,ibit)
157  ELSEIF(ityp(i).EQ.3) THEN
158  CALL upc(catx(i,ncol),ibt(node)/8,ibay,ibit,.true.)
159  ENDIF
160  ENDDO
161 
162 C COMPUTE THE MIN,MAX,WIDTH FOR EACH ROW - ACCUMULATE LENGTH
163 C ----------------------------------------------------------
164 
165 C LDATA WILL HOLD THE LENGTH IN BITS OF THE COMPRESSED DATA
166 C (I.E. THE SUM TOTAL FOR ALL DATA VALUES FOR ALL SUBSETS
167 C IN THE MESSAGE)
168 
169  20 ldata = 0
170  IF(ncol.LE.0) GOTO 902
171  DO i=1,nrow
172  IF(ityp(i).EQ.1 .OR. ityp(i).EQ.2) THEN
173 
174 C ROW I OF THE COMPRESSION MATRIX CONTAINS NUMERIC VALUES,
175 C SO KMIS(I) WILL STORE:
176 C .FALSE. IF ALL SUCH VALUES ARE NON-"MISSING"
177 C .TRUE. OTHERWISE
178 
179  imiss = 2**iwid(i)-1
180  IF(icol.EQ.1) THEN
181  kmin(i) = imiss
182  kmax(i) = 0
183  kmis(i) = .false.
184  ENDIF
185  DO j=icol,ncol
186  IF(matx(i,j).LT.imiss) THEN
187  kmin(i) = min(kmin(i),matx(i,j))
188  kmax(i) = max(kmax(i),matx(i,j))
189  ELSE
190  kmis(i) = .true.
191  ENDIF
192  ENDDO
193  kmiss = kmis(i).AND.kmin(i).LT.imiss
194  range = real(max(1,kmax(i)-kmin(i)+1))
195  IF(ityp(i).EQ.1.AND.range.GT.1) THEN
196 
197 C THE DATA VALUES IN ROW I OF THE COMPRESSION MATRIX
198 C ARE DELAYED DESCRIPTOR REPLICATION FACTORS AND ARE
199 C NOT ALL IDENTICAL (I.E. RANGE.GT.1), SO WE CANNOT
200 C COMPRESS ALL OF THESE SUBSETS INTO THE SAME MESSAGE.
201 C ASSUMING THAT NONE OF THE VALUES ARE "MISSING",
202 C EXCLUDE THE LAST SUBSET (I.E. THE LAST COLUMN
203 C OF THE MATRIX) AND TRY RE-COMPRESSING AGAIN.
204 
205  IF(kmiss) GOTO 903
206  writ1 = .true.
207  ncol = ncol-1
208  icol = 1
209  GOTO 20
210  ELSEIF(ityp(i).EQ.2.AND.(range.GT.1..OR.kmiss)) THEN
211 
212 C THE DATA VALUES IN ROW I OF THE COMPRESSION MATRIX
213 C ARE NUMERIC VALUES THAT ARE NOT ALL IDENTICAL.
214 C COMPUTE THE NUMBER OF BITS NEEDED TO HOLD THE
215 C LARGEST OF THE INCREMENTS.
216 
217  kbit(i) = nint(log(range)*rln2)
218  IF(2**kbit(i)-1.LE.range) kbit(i) = kbit(i)+1
219 
220 C HOWEVER, UNDER NO CIRCUMSTANCES SHOULD THIS NUMBER
221 C EVER EXCEED THE WIDTH OF THE ORIGINAL UNDERLYING
222 C DESCRIPTOR!
223 
224  IF(kbit(i).GT.iwid(i)) kbit(i) = iwid(i)
225  ELSE
226 
227 C THE DATA VALUES IN ROW I OF THE COMPRESSION MATRIX
228 C ARE NUMERIC VALUES THAT ARE ALL IDENTICAL, SO THE
229 C INCREMENTS WILL BE OMITTED FROM THE MESSAGE.
230 
231  kbit(i) = 0
232  ENDIF
233  ldata = ldata + iwid(i) + 6 + ncol*kbit(i)
234  ELSEIF(ityp(i).EQ.3) THEN
235 
236 C ROW I OF THE COMPRESSION MATRIX CONTAINS CHARACTER VALUES,
237 C SO KMIS(I) WILL STORE:
238 C .FALSE. IF ALL SUCH VALUES ARE IDENTICAL
239 C .TRUE. OTHERWISE
240 
241  IF(icol.EQ.1) THEN
242  cstr(i) = catx(i,1)
243  kmis(i) = .false.
244  ENDIF
245  DO j=icol,ncol
246  IF ( (.NOT.kmis(i)) .AND. (cstr(i).NE.catx(i,j)) ) THEN
247  kmis(i) = .true.
248  ENDIF
249  ENDDO
250  IF (kmis(i)) THEN
251 
252 C THE DATA VALUES IN ROW I OF THE COMPRESSION MATRIX
253 C ARE CHARACTER VALUES THAT ARE NOT ALL IDENTICAL.
254 
255  kbit(i) = iwid(i)
256  ELSE
257 
258 C THE DATA VALUES IN ROW I OF THE COMPRESSION MATRIX
259 C ARE CHARACTER VALUES THAT ARE ALL IDENTICAL, SO THE
260 C INCREMENTS WILL BE OMITTED FROM THE MESSAGE.
261 
262  kbit(i) = 0
263  ENDIF
264  ldata = ldata + iwid(i) + 6 + ncol*kbit(i)
265  ENDIF
266  ENDDO
267 
268 C ROUND DATA LENGTH UP TO A WHOLE BYTE COUNT
269 C ------------------------------------------
270 
271  ibyt = (ldata+8-mod(ldata,8))/8
272 
273 C DEPENDING ON THE EDITION NUMBER OF THE MESSAGE, WE NEED TO ENSURE
274 C THAT WE ROUND TO AN EVEN BYTE COUNT
275 
276  IF( (.NOT.edge4) .AND. (mod(ibyt,2).NE.0) ) ibyt = ibyt+1
277 
278  jbit = ibyt*8-ldata
279 
280 C CHECK ON COMPRESSED MESSAGE LENGTH, EITHER WRITE/RESTORE OR RETURN
281 C ------------------------------------------------------------------
282 
283  IF(msgfull(ibyt,kbyt,maxcmb)) THEN
284 
285 C THE CURRENT SUBSET WILL NOT FIT INTO THE CURRENT MESSAGE.
286 C SET THE FLAG TO INDICATE THAT A MESSAGE WRITE IS NEEDED,
287 C THEN GO BACK AND RE-COMPRESS THE SECTION 4 DATA FOR THIS
288 C MESSAGE WHILE *EXCLUDING* THE DATA FOR THE CURRENT SUBSET
289 C (WHICH WILL BE HELD AND STORED AS THE FIRST SUBSET OF A
290 C NEW MESSAGE AFTER WRITING THE CURRENT MESSAGE!).
291 
292  writ1 = .true.
293  ncol = ncol-1
294  icol = 1
295  GOTO 20
296  ELSEIF(.NOT.writ1) THEN
297 
298 C ADD THE CURRENT SUBSET TO THE CURRENT MESSAGE AND RETURN.
299 
300  CALL usrtpl(lun,1,1)
301  nsub(lun) = -ncol
302  GOTO 100
303  ENDIF
304 
305 C WRITE THE COMPLETE COMPRESSED MESSAGE
306 C -------------------------------------
307 
308 C NOW IT IS TIME TO DO THE "REAL" CALL TO CMSGINI TO ACTUALLY
309 C INITIALIZE SECTIONS 0, 1, 2 AND 3 OF THE FINAL COMPRESSED
310 C BUFR MESSAGE THAT WILL BE WRITTEN OUT.
311 
312  50 CALL cmsgini(lun,mgwa,subset,idate(lun),ncol,ibyt)
313 
314 C NOW ADD THE SECTION 4 DATA.
315 
316  ibit = ibyt*8
317  DO i=1,nrow
318  IF(ityp(i).EQ.1.OR.ityp(i).EQ.2) THEN
319  CALL pkb8(kmin(i),iwid(i),mgwa,ibit)
320  CALL pkb(kbit(i), 6,mgwa,ibit)
321  IF(kbit(i).GT.0) THEN
322  DO j=1,ncol
323  IF(matx(i,j).LT.2_8**iwid(i)-1) THEN
324  incr = matx(i,j)-kmin(i)
325  ELSE
326  incr = 2_8**kbit(i)-1
327  ENDIF
328  CALL pkb8(incr,kbit(i),mgwa,ibit)
329  ENDDO
330  ENDIF
331  ELSEIF(ityp(i).EQ.3) THEN
332  nchr = iwid(i)/8
333  IF(kbit(i).GT.0) THEN
334  CALL ipkm(czero,1,0)
335  DO j=1,nchr
336  CALL pkc(czero,1,mgwa,ibit)
337  ENDDO
338  CALL pkb(nchr, 6,mgwa,ibit)
339  DO j=1,ncol
340  CALL pkc(catx(i,j),nchr,mgwa,ibit)
341  ENDDO
342  ELSE
343  CALL pkc(cstr(i),nchr,mgwa,ibit)
344  CALL pkb( 0, 6,mgwa,ibit)
345  ENDIF
346  ENDIF
347  ENDDO
348 
349 C FILL IN THE END OF THE MESSAGE
350 C ------------------------------
351 
352 C PAD THE END OF SECTION 4 WITH ZEROES UP TO THE NECESSARY
353 C BYTE COUNT.
354 
355  CALL pkb( 0,jbit,mgwa,ibit)
356 
357 C ADD SECTION 5.
358 
359  CALL pkc('7777', 4,mgwa,ibit)
360 
361 C SEE THAT THE MESSAGE BYTE COUNTERS AGREE THEN WRITE A MESSAGE
362 C -------------------------------------------------------------
363 
364  IF(mod(ibit,8).NE.0) GOTO 904
365  lbyt = iupbs01(mgwa,'LENM')
366  nbyt = ibit/8
367  IF(nbyt.NE.lbyt) GOTO 905
368 
369  CALL msgwrt(lunit,mgwa,nbyt)
370 
371  maxrow = max(maxrow,nrow)
372  maxcol = max(maxcol,ncol)
373  ncmsgs = ncmsgs+1
374  ncsubs = ncsubs+ncol
375  ncbyts = ncbyts+nbyt
376 
377 C RESET
378 C -----
379 
380 C NOW, UNLESS THIS WAS A "FLUSH" CALL TO THIS SUBROUTINE, GO BACK
381 C AND INITIALIZE A NEW MESSAGE TO HOLD THE CURRENT SUBSET THAT WE
382 C WERE NOT ABLE TO FIT INTO THE MESSAGE THAT WAS JUST WRITTEN OUT.
383 
384  first = .true.
385  IF(.NOT.flush) GOTO 1
386 
387 C EXITS
388 C -----
389 
390 100 RETURN
391 900 WRITE(bort_str,'("BUFRLIB: WRCMPS - I/O STREAM INDEX FOR THIS '//
392  . .NE.'CALL (",I3,") I/O STREAM INDEX FOR INITIAL CALL (",I3,")'//
393  . ' - UNIT NUMBER NOW IS",I4)') lun,lunc,lunix
394  CALL bort(bort_str)
395 901 WRITE(bort_str,'("BUFRLIB: WRCMPS - NO. OF ELEMENTS IN THE '//
396  . .GT.'SUBSET (",I6,") THE NO. OF ROWS ALLOCATED FOR THE '//
397  . 'COMPRESSION MATRIX (",I6,")")') nval(lun),mxcdv
398  CALL bort(bort_str)
399 902 WRITE(bort_str,'("BUFRLIB: WRCMPS - NO. OF COLUMNS CALCULATED '//
400  . .LE.'FOR COMPRESSION MAXRIX IS 0 (=",I6,")")') ncol
401  CALL bort(bort_str)
402 903 CALL bort('BUFRLIB: WRCMPS - MISSING DELAYED REPLICATION FACTOR')
403 904 CALL bort('BUFRLIB: WRCMPS - THE NUMBER OF BITS IN THE '//
404  . 'COMPRESSED BUFR MSG IS NOT A MULTIPLE OF 8 - MSG MUST END ON '//
405  . ' A BYTE BOUNDARY')
406 905 WRITE(bort_str,'("BUFRLIB: WRCMPS - OUTPUT MESSAGE LENGTH FROM '//
407  . 'SECTION 0",I6," DOES NOT EQUAL FINAL PACKED MESSAGE LENGTH ("'//
408  .',I6,")")') lbyt,nbyt
409  CALL bort(bort_str)
410  END
subroutine bort(STR)
Log one error message and abort application program.
Definition: bort.f:18
subroutine cmsgini(LUN, MESG, SUBSET, IDATE, NSUB, NBYT)
This subroutine initializes a new BUFR message for output in compressed format.
Definition: cmsgini.f:23
recursive subroutine ipkm(CBAY, NBYT, N)
Encode an integer value within a character string.
Definition: ipkm.f:22
recursive function iupbs01(MBAY, S01MNEM)
Read a data value from Section 0 or Section 1 of a BUFR message.
Definition: iupbs01.f:69
subroutine msgwrt(LUNIT, MESG, MGBYT)
Perform final checks and updates on a BUFR message before writing it to a specified Fortran logical u...
Definition: msgwrt.f:38
This module contains array and variable declarations used to store BUFR messages internally for multi...
integer, dimension(:), allocatable ibay
Current data subset.
integer ibit
Bit pointer within IBAY.
integer, dimension(:,:), allocatable mbay
Current BUFR message for each internal I/O stream.
This module contains arrays and variable declarations for the storage of data values needed when writ...
integer ncol
Number of data subsets in message.
integer(8) incr
Increment used when compressing non-character data values.
integer(8), dimension(:,:), allocatable matx
Non-character data values for all data subsets in message.
character *(:), dimension(:,:), allocatable catx
Character data values for all data subsets in message.
This module contains arrays and variable declarations for the storage of data values needed when writ...
character *(:), dimension(:), allocatable cstr
Character data value, if corresponding ityp value is set to 3.
integer(8), dimension(:), allocatable kmax
Maximum of each data value across all data subsets in message.
integer kbyt
Number of bytes required to store Sections 0, 1, 2, and 3 of message.
logical flush
Flush flag.
integer nrow
Number of data values for each data subset in message.
logical writ1
Write-out flag.
integer, dimension(:), allocatable ityp
Type of each data value:
integer, dimension(:), allocatable iwid
Bit width of underlying data descriptor as defined within Table B for each data value.
integer lunc
I/O stream index into internal arrays for output file.
integer(8), dimension(:), allocatable kmin
Minimum of each data value across all data subsets in message.
integer, dimension(:), allocatable kbit
Number of bits needed to hold the increments for this data value within each data subset of the messa...
logical, dimension(:), allocatable kmis
"Missing" values flag.
This module contains a declaration for an array used by various subroutines and functions to hold a t...
integer, dimension(:), allocatable mgwa
Temporary working copy of BUFR message.
This module contains declarations for arrays used to store information about the current BUFR message...
integer, dimension(:), allocatable inode
Table A mnemonic for type of BUFR message.
integer, dimension(:), allocatable idate
Section 1 date-time of message.
integer, dimension(:), allocatable nsub
Current subset pointer within message.
This module contains array and variable declarations used to store custom values for certain mnemonic...
integer, dimension(:), allocatable ivmnem
Custom values for use within Sections 0 and 1 of all future output BUFR messages written to all Fortr...
integer ns01v
Number of custom values stored.
character *8, dimension(:), allocatable cmnem
Section 0 and 1 mnemonics corresponding to ivmnem.
This module contains array and variable declarations used to store the internal jump/link table.
integer, dimension(:), allocatable ibt
Bit widths corresponding to tag and typ:
character *10, dimension(:), allocatable tag
Mnemonics in the jump/link table.
integer, dimension(:), allocatable itp
Integer type values corresponding to typ:
This module contains declarations for arrays used to store data values and associated metadata for th...
integer, dimension(:), allocatable nval
Number of data values in BUFR data subset.
integer, dimension(:,:), allocatable, target inv
Inventory pointer which links each data value to its corresponding node in the internal jump/link tab...
This module declares and initializes the MXCDV variable.
integer mxcdv
Maximum number of data values that can be written into a data subset of a compressed BUFR message by ...
This module declares and initializes the MXCSB variable.
integer mxcsb
Maximum number of data subsets that can be written into a compressed BUFR message by the BUFRLIB soft...
subroutine pkb8(nval, nbits, ibay, ibit)
This subroutine encodes an 8-byte integer value within a specified number of bits of an integer array...
Definition: pkb8.f:28
subroutine pkb(NVAL, NBITS, IBAY, IBIT)
This subroutine encodes an integer value within a specified number of bits of an integer array,...
Definition: pkb.f:28
subroutine pkc(CHR, NCHR, IBAY, IBIT)
Encode a character string within an integer array.
Definition: pkc.f:31
recursive subroutine status(LUNIT, LUN, IL, IM)
Check whether a specified Fortran logical unit number is currently connected to the NCEPLIBS-bufr sof...
Definition: status.f:36
subroutine up8(nval, nbits, ibay, ibit)
This subroutine decodes an 8-byte integer value from within a specified number of bits of an integer ...
Definition: up8.f:27
subroutine upc(CHR, NCHR, IBAY, IBIT, CNVNULL)
Decode a character string from an integer array.
Definition: upc.f:32
subroutine usrtpl(LUN, INVN, NBMP)
Store the subset template into internal arrays.
Definition: usrtpl.f:22
subroutine wrcmps(LUNIX)
This subroutine packs up the current subset within memory (array ibay in module moda_bitbuf),...
Definition: wrcmps.f:23