bufr2synop 0.24.0
bufrtotac.c
Go to the documentation of this file.
1/***************************************************************************
2 * Copyright (C) 2013-2022 by Guillermo Ballester Valor *
3 * gbv@ogimet.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20/*! \file bufrtotac.c
21 \brief This file includes the code to test bufr to TAC libraries using bufrdeco library to decode bufr
22
23 \mainpage Bufr to traditional alphanumeric code
24
25 \section Introduction
26 This is a package to make the transition to bufr reports from alphanumeric text easiest as possible.
27
28 A lot of software is coded assuming that the primary source of meteorological reports is in alphanumeric format. Decode libraries are expecting this. But time is changing, meteorological services are migrating to bufr and other binary formats. Most decode sofware have to be changed.
29
30 This is a software to get meteorological reports in old alphanumeric format from bufr files. At the moment includes the following reports:
31
32 - FM 12-XIV SYNOP
33 - FM 13-XIV SHIP
34 - FM 14-XIV SYNOP MOBIL
35 - FM 18-XII BUOY
36 - FM 35-XI TEMP
37 - FM 36-XI TEMP SHIP
38 - FM 38-XI TEMP MOBIL
39 - FM 71-XII CLIMAT
40
41 The software is based in bufrdc library from ECMWF. Before version 0.7 this package should to be
42 installed. Since version 0.7, a library for decode a wide subset of bufr reports has been writen
43 from scratch. This is a fast and light bufr decoder. Anyway it still uses the bufr tables installed
44 by ECMWF packages so it still need to be installed. You can grab ECMWF library from
45
46 https://software.ecmwf.int/wiki/display/BUFR/Releases
47
48 Note that the results from this library is not intended to match at %100 level to original alphanumeric reports. It cannot. Some variables in alphanumeric code rules can be coded in several ways, and there is not a regional even national decision about them. As example, the 'hshs' item (table code 1617) for synop FM 12 can be coded using 00-80 range or 90-99 one. A numeric value for heigh of base clouds can be coded in two ways. And there some few more examples.
49
50 \section Install
51
52 Remember you have to download and install bufrdc library from ECMWF
53
54 https://software.ecmwf.int/wiki/display/BUFR/Releases
55
56 You also will need a Fortran and C compilers in your system and the usual development packages. GNU gcc and gfortran compilers are ok.
57
58 Then, to install bufr2synop, download the tarball and uncompress it
59
60 \code
61 tar -xvzf bufr2synop-X.Y.tar.gz
62 \endcode
63
64 Where X.Y is the current version. This will create the directory \a bufr2synop-X.Y
65
66 You then have to configure
67
68 \code
69 cd bufr2synop-X.Y
70 ./configure
71 \endcode
72
73 after a succesfully configuration you then can then compile the package
74
75 \code
76 make
77 \endcode
78
79 and finally install it.
80 \code
81 make install
82 \endcode
83
84 by default, it will install binaries and libraries under \a /usr/local tree, so you will need root privileges.
85*/
86
87#include "bufrtotac.h"
88
90struct metreport REPORT; /*!< stuct to set the parsed report */
91struct bufr2tac_subset_state STATE; /*!< Includes the info when parsing a subset sequence */
92struct bufr2tac_error_stack ERRS; /*!< struct to store warnings and errors */
93
94const char SELF[]= "bufrtotac"; /*! < the name of this binary */
95char ERR[256]; /*!< string with an error */
96char BUFRTABLES_DIR[256]; /*!< Directory for BUFR tables set by user */
97char LISTOFFILES[256]; /*!< The pathname of a file which includes a list of bufr files to parse */
98char INPUTFILE[256]; /*!< The pathname of input file */
99char OFFSETFILE[BUFRDECO_PATH_LENGTH + 8]; /*< The path name of optional file with bit offsets for non-compressed BUFR. */
100char OUTPUTFILE[256]; /*!< The pathname of output file */
101int VERBOSE; /*!< If != 0 the verbose output */
102int SHOW_SEQUENCE; /*!< Output explained sequence */
103int DEBUG; /*!< Show debug information */
104int NFILES; /*!< The amount of files processed */
105int GTS_HEADER; /*!< If == 1 GTS header have been guessed from filename */
106int XML; /*!< If == 1 then output is in xml format */
107int JSON; /*!< If == 1 then output is in json format */
108int CSV; /*!< If == 1 then output is in csv format */
109int EXTRACT; /*!< if != 0 then the decoder tries to extract an embebed bufr in a file seraching for a first '7777' after first 'BUFR' */
110int ECMWF; /*!< If == 1 then use tables from ECMWF package */
111int HTML; /*!< If == 1 then output is in HTML format */
112int NOTAC; /*!< if == 1 then do not decode to TAC */
113int FIRST_SUBSET; /*!< First subset index in output. First available is 0 */
114int LAST_SUBSET; /*!< Last subset index in output. First available is 0 */
115int PRINT_WIGOS_ID; /*!< if != 0 then print wigos id in output */
116int PRINT_GEO; /*!< if != 0 then print latitude, longitude and altitude */
117int READ_OFFSETS; /*!< if != then read bit offsets */
118int WRITE_OFFSETS; /*!< if != 0 then write bit offsets */
119int USE_CACHE; /*!< if != 0 then use cache of tables */
120int SUBSET ; /*!< Index of subset in a BUFR being parsed */
121int PRINT_JSON_DATA; /*!< If != 0 then the data subset is in json format */
127
128FILE *FL; /*!< Buffer to read the list of files */
129FILE *OUT; /*!< Buffer to write to OUTPUTFILE */
130#ifdef DEBUG_TIME
131 clock_t clk_start, clk_end;
132#endif
133
134int main ( int argc, char *argv[] )
135{
136 int first_subset, last_subset;
137 char subset_id[32];
139
140
141 if ( bufrtotac_read_args ( argc, argv ) < 0 )
142 exit ( EXIT_FAILURE );
143
144 // init bufr struct
145#ifdef DEBUG_TIME
146 clk_start = clock ();
147#endif
148 if ( bufrdeco_init ( &BUFR ) )
149 {
150 printf ( "%s(): Cannot init bufr struct\n", SELF );
151 return 1;
152 }
153
154#ifdef DEBUG_TIME
155 clk_end = clock();
156 print_timing (clk_start,clk_end,bufrdeco_init());
157#endif
158
159 /**** set bitmask according with args readed from shell ****/
161
162 /**** Set bufr tables dir ****/
164
165 /**** Big loop. a cycle per file. Get input filenames from LISTOFFILES[] ****/
167 {
168#ifdef __DEBUG
169 printf ( "####### %s ######\n", INPUTFILE );
170#endif
171 if ( DEBUG )
172 printf ( "# %s\n", INPUTFILE );
173
174 // The following call to bufrdeco_read_bufr() does the folowing tasks:
175 // - Read the file and checks the marks at the begining and end to see wheter is a BUFR file
176 // - Init the structs and allocate the needed memory if not done previously
177 // - Splits and parse the BUFR sections (without expanding descriptors nor parsing data)
178 // - Reads the needed Table files and store them in memory.
179 //
180 // If EXTRACT != 0 then the function bufrdeco_extract_bufr() is used instead of bufrdeco_read_bufr()
181 // This act in the same way, but search and extract the first BUFR embebed in a file.
182#ifdef DEBUG_TIME
183 clk_start = clock ();
184#endif
185
186 if ( ( EXTRACT && bufrdeco_extract_bufr ( &BUFR, INPUTFILE ) ) ||
187 ( EXTRACT == 0 && bufrdeco_read_bufr ( &BUFR, INPUTFILE ) ) )
188 {
189 if ( DEBUG )
190 printf ( "# %s\n", BUFR.error );
191 NFILES++;
192 bufrdeco_reset ( &BUFR );
193 continue;
194 }
195#ifdef DEBUG_TIME
196 clk_end = clock();
197 print_timing (clk_start,clk_end,bufrdeco_extract_bufr());
198#endif
199
200 // Check if have to read bit offsets file
201 if ( READ_OFFSETS &&
202 BUFR.sec3.compressed == 0 &&
203 BUFR.sec3.subsets > 1 )
204 {
205 #ifdef DEBUG_TIME
206 clk_start = clock ();
207 #endif
209#ifdef DEBUG_TIME
210 clk_end = clock();
211 print_timing (clk_start,clk_end,bufrdeco_read_subset_offset_bits());
212#endif
213 }
214
215 /* Try to guess a GTS header from filename*/
216 GTS_HEADER = guess_gts_header ( &BUFR.header, INPUTFILE ); // GTS_HEADER = 1 if succeeded
217 if ( GTS_HEADER && DEBUG )
218 printf ( "# Guessed GTS Header: %s %s %s %s %s\n", BUFR.header.timestamp, BUFR.header.bname, BUFR.header.center,
220
221 /* Prints sections if verbose */
222 if ( VERBOSE )
223 {
228 }
229
230 // To get any data from any subset we need to parse the tree
231#ifdef DEBUG_TIME
232 clk_start = clock ();
233#endif
234 if ( bufrdeco_parse_tree ( &BUFR ) )
235 {
236 if ( DEBUG )
237 printf ( "# %s", BUFR.error );
238 NFILES++;
239 bufrdeco_reset ( &BUFR );
240 continue;
241 }
242#ifdef DEBUG_TIME
243 clk_end = clock();
244 print_timing (clk_start,clk_end,bufrdeco_parse_tree());
245#endif
248
249 if ( VERBOSE )
251
252 first_subset = FIRST_SUBSET;
253 last_subset = LAST_SUBSET;
254
255 // Fix first and last subset
256 if ( first_subset >= ( int ) BUFR.sec3.subsets )
257 goto fin;
258
259 if ( last_subset < first_subset)
260 last_subset = BUFR.sec3.subsets - 1;
261
262 for ( SUBSET = first_subset; SUBSET <= last_subset ; SUBSET++ )
263 {
264#ifdef DEBUG_TIME
265 clk_start = clock ();
266#endif
267 if ( ( seq = bufrdeco_get_target_subset_sequence_data ( SUBSET, &BUFR ) ) == NULL )
268 {
269 if ( DEBUG )
270 printf ( "# %s", BUFR.error );
271 goto fin;
272 }
273#ifdef DEBUG_TIME
274 clk_end = clock();
275 print_timing (clk_start, clk_end,bufrdeco_get_target_subset_sequence_data());
276#endif
277
278 if ( VERBOSE )
279 {
280 if ( ( SUBSET == first_subset ) && BUFR.sec3.compressed )
283 {
284 sprintf ( subset_id, "subset_%d", SUBSET );
286 }
287 else
289 }
290
291 if ( ! NOTAC )
292 {
293 // Here we perform the decode to TAC
294#ifdef DEBUG_TIME
295 clk_start = clock ();
296#endif
298 {
299 if ( DEBUG )
300 fprintf ( stderr, "# %s\n", ERR );
301 }
302#ifdef DEBUG_TIME
303 clk_end = clock();
304 print_timing (clk_start, clk_end, bufrtotac_parse_subset_sequence());
305#endif
306
307 // And here print the results
308 if ( XML )
309 {
310 if ( SUBSET == 0 )
311 fprintf ( OUT, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
312 print_xml ( stdout, &REPORT );
313 }
314 else if ( JSON )
315 {
316 print_json ( OUT, &REPORT );
317 }
318 else if ( CSV )
319 {
320 if ( SUBSET == 0 )
321 fprintf ( OUT, "TYPE,FILE,DATETIME,INDEX,NAME,COUNTRY,LATITUDE,LONGITUDE,ALTITUDE,REPORT\n" );
322 print_csv ( OUT, &REPORT );
323 }
324 else if ( HTML )
325 {
326 print_html ( OUT, &REPORT );
327 }
328 else
329 {
330 print_plain ( OUT, &REPORT );
331 }
332 }
333 }
334 fin:
335 ;
336
337 // check if has to write bit offsets file
338 if ( BUFR.sec3.compressed == 0 &&
339 BUFR.sec3.subsets > 1 &&
341 {
343 }
344
345#ifdef DEBUG_TIME
346 clk_start = clock ();
347#endif
348 bufrdeco_reset ( &BUFR );
349#ifdef DEBUG_TIME
350 clk_end = clock();
351 print_timing (clk_start, clk_end, bufrdeco_reset());
352#endif
353 NFILES ++;
354 } // End of big loop parsing files
355
356 bufrdeco_close ( &BUFR );
357
358 // Close the file if needed
359 if (OUTPUTFILE[0])
360 fclose (OUT);
361
362 exit ( EXIT_SUCCESS );
363}
int guess_gts_header(struct gts_header *h, const char *f)
Guess the WMO GTS header from filename.
int print_json(FILE *f, struct metreport *m)
prints a struct metreport in json format
Definition: bufr2tac_json.c:62
int print_csv(FILE *f, struct metreport *m)
prints a struct metreport in labeled csv format
Definition: bufr2tac_csv.c:85
int print_xml(FILE *f, struct metreport *m)
prints a struct metreport in xml format
Definition: bufr2tac_xml.c:71
int print_plain(FILE *f, struct metreport *m)
Print in a file the report decoded to Traditional Alphanumeric Code in plain text format....
int print_html(FILE *f, struct metreport *m)
Print in a file the report decoded to Traditional Alphanumeric Code in plain html format....
int bufrdeco_reset(struct bufrdeco *b)
Reset an struct bufrdeco. This is needed when changing to another bufr.
Definition: bufrdeco.c:180
int bufrdeco_close(struct bufrdeco *b)
Free all allocated memory. Needed when no more task to do with bufrdeco library.
Definition: bufrdeco.c:259
int bufrdeco_write_subset_offset_bits(struct bufrdeco *b, char *filename)
Write offset bit array for subsets in a non-compressed bufr.
Definition: bufrdeco.c:330
int bufrdeco_parse_tree(struct bufrdeco *b)
Parse the tree of descriptors without expand the replicators.
Definition: bufrdeco.c:120
int bufrdeco_read_subset_offset_bits(struct bufrdeco *b, char *filename)
Write offset bit array for subsets in a non-compressed bufr.
Definition: bufrdeco.c:358
struct bufrdeco_subset_sequence_data * bufrdeco_get_target_subset_sequence_data(buf_t nset, struct bufrdeco *b)
Prepare the struct bufrdeco to get data from the solicited subset.
Definition: bufrdeco.c:396
int bufrdeco_init(struct bufrdeco *b)
Inits and allocate memory for a struct bufrdeco.
Definition: bufrdeco.c:138
int bufrdeco_print_subset_sequence_data(struct bufrdeco_subset_sequence_data *s)
Prints a struct bufrdeco_subset_sequence_data.
buf_t bufrdeco_print_json_tree(struct bufrdeco *b)
int print_sec0_info(struct bufrdeco *b)
Prints info from sec0.
int print_bufrdeco_compressed_data_references(struct bufrdeco_compressed_data_references *r)
prints a struct bufrdeco_compressed_references
#define BUFRDECO_OUTPUT_HTML
Bit mask to the member mask for struct bufrdeco to format output as html for SECs 0 to 3.
Definition: bufrdeco.h:256
#define BUFRDECO_PATH_LENGTH
Length for files/directory path strings.
Definition: bufrdeco.h:335
int print_sec3_info(struct bufrdeco *b)
Prints info from sec3.
int bufrdeco_print_subset_sequence_data_tagged_html(struct bufrdeco_subset_sequence_data *s, char *id)
int bufrdeco_extract_bufr(struct bufrdeco *b, char *filename)
Read file and try to find a bufr report inserted in. Once found do the same that bufrdeco_read_file()
int bufrdeco_print_tree(struct bufrdeco *b)
Print a tree of descriptors.
int print_sec4_info(struct bufrdeco *b)
Prints info from sec3.
int bufrdeco_read_bufr(struct bufrdeco *b, char *filename)
Read bufr file and does preliminary and first decode pass.
Definition: bufrdeco_read.c:41
int print_sec1_info(struct bufrdeco *b)
Prints info from sec1.
int JSON
Definition: bufrtotac.c:107
char OUTPUTFILE[256]
Definition: bufrtotac.c:100
int PRINT_JSON_EXPANDED_TREE
Definition: bufrtotac.c:126
int main(int argc, char *argv[])
Definition: bufrtotac.c:134
int PRINT_JSON_SEC1
Definition: bufrtotac.c:123
char ERR[256]
Definition: bufrtotac.c:95
const char SELF[]
Definition: bufrtotac.c:94
int XML
Definition: bufrtotac.c:106
char INPUTFILE[256]
Definition: bufrtotac.c:98
FILE * OUT
Definition: bufrtotac.c:129
int PRINT_JSON_SEC2
Definition: bufrtotac.c:124
int PRINT_JSON_SEC0
Definition: bufrtotac.c:122
int PRINT_GEO
Definition: bufrtotac.c:116
int GTS_HEADER
Definition: bufrtotac.c:105
struct bufr2tac_error_stack ERRS
Definition: bufrtotac.c:92
int NFILES
Definition: bufrtotac.c:104
int DEBUG
Definition: bufrtotac.c:103
int WRITE_OFFSETS
Definition: bufrtotac.c:118
int READ_OFFSETS
Definition: bufrtotac.c:117
char LISTOFFILES[256]
Definition: bufrtotac.c:97
int CSV
Definition: bufrtotac.c:108
struct bufr2tac_subset_state STATE
Definition: bufrtotac.c:91
int SHOW_SEQUENCE
Definition: bufrtotac.c:102
int PRINT_JSON_SEC3
Definition: bufrtotac.c:125
struct bufrdeco BUFR
Definition: bufrtotac.c:89
int PRINT_JSON_DATA
Definition: bufrtotac.c:121
FILE * FL
Definition: bufrtotac.c:128
char OFFSETFILE[BUFRDECO_PATH_LENGTH+8]
Definition: bufrtotac.c:99
int SUBSET
Definition: bufrtotac.c:120
int USE_CACHE
Definition: bufrtotac.c:119
int HTML
Definition: bufrtotac.c:111
int FIRST_SUBSET
Definition: bufrtotac.c:113
int NOTAC
Definition: bufrtotac.c:112
int VERBOSE
Definition: bufrtotac.c:101
struct metreport REPORT
Definition: bufrtotac.c:90
int EXTRACT
Definition: bufrtotac.c:109
int LAST_SUBSET
Definition: bufrtotac.c:114
char BUFRTABLES_DIR[256]
Definition: bufrtotac.c:96
int PRINT_WIGOS_ID
Definition: bufrtotac.c:115
int ECMWF
Definition: bufrtotac.c:110
Include header file for binary bufrtotac.
int bufrtotac_parse_subset_sequence(struct metreport *m, struct bufr2tac_subset_state *st, struct bufrdeco *b, char *err)
Definition: bufrtotac_io.c:356
char * get_bufrfile_path(char *filename, char *fileoffset, char *err)
Definition: bufrtotac_io.c:419
int bufrtotac_set_bufrdeco_bitmask(struct bufrdeco *b)
Set the bufrdeco struct bitmask according with readed args from shell.
Definition: bufrtotac_io.c:463
int bufrtotac_read_args(int _argc, char *_argv[])
Definition: bufrtotac_io.c:145
A stack of structs bufr2tac_error.
Definition: bufr2tac.h:235
stores information needed to parse a sequential list of expanded descriptors for a subset
Definition: bufr2tac.h:246
uint8_t compressed
Definition: bufrdeco.h:812
uint32_t ndesc
Definition: bufrdeco.h:813
uint32_t subsets
Definition: bufrdeco.h:810
Contains all the information for a subset in a expanded squence This is a version to use with bufrdec...
Definition: bufrdeco.h:458
This struct contains all needed data to parse and decode a BUFR file.
Definition: bufrdeco.h:965
uint32_t mask
Definition: bufrdeco.h:966
struct bufrdeco_compressed_data_references refs
Definition: bufrdeco.h:978
char bufrtables_dir[BUFRDECO_PATH_LENGTH]
Definition: bufrdeco.h:982
struct bufr_sec3 sec3
Definition: bufrdeco.h:971
struct gts_header header
Definition: bufrdeco.h:967
char error[1024]
Definition: bufrdeco.h:983
char center[8]
Definition: bufrdeco.h:709
char dtrel[16]
Definition: bufrdeco.h:710
char order[8]
Definition: bufrdeco.h:711
char bname[16]
Definition: bufrdeco.h:708
char timestamp[16]
Definition: bufrdeco.h:713
all the information for a meteorological report in WMO text format from a BUFR file
Definition: bufr2tac.h:309