Ticket 752: Add support for quantities to wrwp binary
[baltrad-wrwp.git] / bin / wrwp_main.c
1 /* --------------------------------------------------------------------
2 Copyright (C) 2011 Swedish Meteorological and Hydrological Institute, SMHI
3
4 This is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 This software is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with baltrad-wrwp.  If not, see <http://www.gnu.org/licenses/>.
16 ------------------------------------------------------------------------*/
17 #include "wrwp.h"
18 #include "rave_debug.h"
19 #include <getopt.h>
20 #include <libgen.h>
21 #include "rave_utilities.h"
22
23 static void PrintUsage(char* name, int full)
24 {
25   char* namecopy = RAVE_STRDUP(name);
26
27   printf("Usage: %s [options] <input volume.h5> <output verticalprofile.h5>\n", basename(namecopy));
28
29   if (full) {
30     printf("--help             - Prints this output\n");
31     printf("--verbose          - Produces some information about the generated product\n");
32     printf("--debug            - Produces some debug information during the generation\n");
33     printf("--dz=<value>       - Height interval for deriving a profile [m] (default: %d)\n", DZ);
34     printf("--nodata=<value>   - Nodata value (default: %d)\n", NODATA_VP);
35     printf("--undetect=<value> - Undetect value (default: %d)\n", UNDETECT_VP);
36     printf("--gain=<value>     - Gain value (default: %f)\n", GAIN_VP);
37     printf("--offset=<value>   - Offset value (default: %f)\n", OFFSET_VP);
38     printf("--hmax=<value>     - Maximum height of the profile [m] (default: %d)\n", HMAX);
39     printf("--dmin=<value>     - Minimum distance for deriving a profile [m] (default: %d)\n", DMIN);
40     printf("--dmax=<value>     - Maximum distance for deriving a profile [m] (default: %d)\n", DMAX);
41     printf("--emin=<value>     - Minimum elevation angle [deg] (default: %f)\n", EMIN);
42     printf("--vmin=<value>     - Radial velocity threshold [m/s] (default: %f)\n", VMIN);
43     printf("--quantity=<value> - A comma separated list of quanities (default: ff,ff_dev,dd,dbzh,dbzh_dev,nz)\n");
44     printf("                     Currently supported quantities are: NV,HGHT,UWND,VWND,ff,ff_dev,dd,dbzh,dbzh_dev,nz\n");
45     printf("\n");
46     printf("<input volume.h>  must be a polar volume in ODIM H5 format\n");
47     printf("<output verticalprofile.h5> will be a vertical profile in ODIM H5 format\n\n");
48   }
49
50   RAVE_FREE(namecopy);
51 }
52
53 /**
54  * Tries to translate an string into an int value.
55  * @param[in] arg - the argument
56  * @param[in,out] pInt - the outvalue
57  * @return 1 on success otherwise 0
58  */
59 int ParseInt(char* arg, int* pInt)
60 {
61   if (arg != NULL) {
62     int i = 0;
63     while (arg[i] != '\0') {
64       if (arg[i] < '0' || arg[i] > '9') {
65         return 0;
66       }
67       i++;
68     }
69   }
70   if (arg != NULL && pInt != NULL && sscanf(arg, "%d",pInt) == 1) {
71     return 1;
72   }
73   return 0;
74 }
75
76 /**
77  * Tries to translate an string into an int value.
78  * @param[in] arg - the argument
79  * @param[in,out] pDouble - the outvalue
80  * @return 1 on success otherwise 0
81  */
82 int ParseDouble(char* arg, double* pDouble)
83 {
84   if (arg != NULL) {
85     int i = 0;
86     int nrDots = 0;
87     while (arg[i] != '\0') {
88       if (arg[i] < '0' || arg[i] > '9') {
89         if (arg[i] == '.' && nrDots==0) {
90           nrDots++;
91         } else {
92           return 0;
93         }
94       }
95       i++;
96     }
97   }
98   if (arg != NULL && pDouble != NULL && sscanf(arg, "%lf",pDouble) == 1) {
99     return 1;
100   }
101   return 0;
102 }
103
104 /**
105  * Extracts the quantity list from a string. Verifies that it's a comma separated list
106  * @param[in] arg - the argument
107  * @param[in,out] quantities - the list of quantities
108  * @return 1 on success otherwise 0
109  */
110 int ParseQuantities(char* arg, char** quantities)
111 {
112   int result = 0;
113   RaveList_t* quantityList = NULL;
114   if (arg != NULL) {
115     quantityList = RaveUtilities_getTrimmedTokens(arg, ',');
116     if (quantityList == NULL || RaveList_size(quantityList) == 0) { /* When 0 length, we let wrwp:s default mechanism decide */
117       *quantities = NULL;
118     } else {
119       int i = 0, sz = 0;
120       sz = RaveList_size(quantityList);
121       for (i = 0; i < sz; i++) {
122         char* q = (char*)RaveList_get(quantityList, i);
123         if (q != NULL) {
124           if (strcmp(q, "NV") == 0 ||
125               strcmp(q, "HGHT") == 0 ||
126               strcmp(q, "UWND") == 0 ||
127               strcmp(q, "VWND") == 0 ||
128               strcmp(q, "ff") == 0 ||
129               strcmp(q, "ff_dev") == 0 ||
130               strcmp(q, "dd") == 0 ||
131               strcmp(q, "dbzh") == 0 ||
132               strcmp(q, "dbzh_dev") == 0 ||
133               strcmp(q, "nz") == 0) {
134             continue;
135           } else {
136             fprintf(stderr, "quantity = %s is not supported\n", q);
137             goto done;
138           }
139         }
140       }
141       *quantities = RAVE_STRDUP(arg);
142       if (*quantities == NULL) {
143         fprintf(stderr, "Failed to allocate memory for quantities\n");
144         goto done;
145       }
146     }
147   }
148   result = 1;
149 done:
150   if (quantityList != NULL) {
151     RaveList_freeAndDestroy(&quantityList);
152   }
153   return result;
154 }
155
156
157 /** Main function for deriving weather radar wind and reflectivity profiles
158  * @file
159  * @author G´┐Żnther Haase, SMHI
160  * @date 2011-11-29
161  */
162 int main (int argc,char *argv[]) {
163         RaveIO_t* raveio = NULL;
164         PolarVolume_t* inobj = NULL;
165         VerticalProfile_t* result = NULL;
166         Wrwp_t* wrwp = NULL;
167         int exitcode = 127;
168         char* inputfile = NULL; /* do not delete */
169         char* outputfile = NULL; /* do not delete */
170
171         int verbose_flag=0;
172         int debug_flag=0;
173         int help_flag=0;
174         int dz_value = DZ;
175         int nodata_vp = NODATA_VP;
176         int undetect_vp = UNDETECT_VP;
177         double gain_vp = GAIN_VP;
178         double offset_vp = OFFSET_VP;
179         int hmax = HMAX;
180         int dmin = DMIN;
181         int dmax = DMAX;
182         double emin = EMIN;
183         double vmin = VMIN;
184         char* quantities = NULL;
185
186         int getopt_ret, option_index;
187
188         struct option long_options[] = {
189             {"help", no_argument, &help_flag, 1},
190             {"verbose", no_argument, &verbose_flag, 1},
191       {"debug", no_argument, &debug_flag, 1},
192             {"dz", optional_argument, 0, 'z'},
193             {"nodata", optional_argument, 0, 'n'},
194             {"undetect", optional_argument, 0, 'u'},
195       {"gain", optional_argument, 0, 'g'},
196       {"offset", optional_argument, 0, 'o'},
197       {"hmax", optional_argument, 0, 'h'},
198       {"dmin", optional_argument, 0, 'd'},
199       {"dmax", optional_argument, 0, 'D'},
200       {"emin", optional_argument, 0, 'e'},
201       {"vmin", optional_argument, 0, 'v'},
202       {"quantities", optional_argument, 0, 'q'},
203             {0, 0, 0, 0}
204         };
205
206
207         Rave_initializeDebugger();
208         Rave_setDebugLevel(RAVE_INFO);
209
210   while (1) {
211       getopt_ret = getopt_long( argc, argv, "",
212                                 long_options,  &option_index);
213       if (getopt_ret == -1) break;
214       if (help_flag) {
215         PrintUsage(argv[0], 1);
216         exitcode=1;
217         goto done;
218       }
219       if (verbose_flag) {
220         Rave_setDebugLevel(RAVE_DEBUG);
221       }
222
223       switch(getopt_ret) {
224       case 0:
225         /* Here all non named options will arrive */
226         /*printf("option %s\n", long_options[option_index].name);*/
227         break;
228       case 'z':
229         if (!ParseInt(optarg, &dz_value)) {
230           fprintf(stderr, "--dz=<value> must be an integer value\n");
231           PrintUsage(argv[0], 0);
232           goto done;
233         }
234         break;
235       case 'n':
236         if (!ParseInt(optarg, &nodata_vp)) {
237           fprintf(stderr, "--nodata=<value> must be an integer value\n");
238           PrintUsage(argv[0], 0);
239           goto done;
240         }
241         break;
242       case 'u':
243         if (!ParseInt(optarg, &undetect_vp)) {
244           fprintf(stderr, "--undetect=<value> must be an integer value\n");
245           PrintUsage(argv[0], 0);
246           goto done;
247         }
248         break;
249       case 'g':
250         if (!ParseDouble(optarg, &gain_vp)) {
251           fprintf(stderr, "--gain=<value> must be a double value\n");
252           PrintUsage(argv[0], 0);
253           goto done;
254         }
255         break;
256       case 'o':
257         if (!ParseDouble(optarg, &offset_vp)) {
258           fprintf(stderr, "--offset=<value> must be a double value\n");
259           PrintUsage(argv[0], 0);
260           goto done;
261         }
262         break;
263       case 'h':
264         if (!ParseInt(optarg, &hmax)) {
265           fprintf(stderr, "--hmax=<value> must be an integer value\n");
266           PrintUsage(argv[0], 0);
267           goto done;
268         }
269         break;
270       case 'd':
271         if (!ParseInt(optarg, &dmin)) {
272           fprintf(stderr, "--dmin=<value> must be an integer value\n");
273           PrintUsage(argv[0], 0);
274           goto done;
275         }
276         break;
277       case 'D':
278         if (!ParseInt(optarg, &dmax)) {
279           fprintf(stderr, "--dmax=<value> must be an integer value\n");
280           PrintUsage(argv[0], 0);
281           goto done;
282         }
283         break;
284       case 'e':
285         if (!ParseDouble(optarg, &emin)) {
286           fprintf(stderr, "--emin=<value> must be a double value\n");
287           PrintUsage(argv[0], 0);
288           goto done;
289         }
290         break;
291       case 'v':
292         if (!ParseDouble(optarg, &vmin)) {
293           fprintf(stderr, "--vmin=<value> must be a double value\n");
294           PrintUsage(argv[0], 0);
295           goto done;
296         }
297         break;
298       case 'q':
299         if (!ParseQuantities(optarg, &quantities)) {
300           fprintf(stderr, "--quantities=<value> must be a comma separated list of valid quantities.\n");
301           PrintUsage(argv[0], 0);
302           goto done;
303         }
304         break;
305       case '?':
306       default:
307         fprintf(stderr, "Unknown argument\n");
308         PrintUsage(argv[0], 0);
309         break;
310       }
311   }
312
313   if (argc - optind != 2) {
314     PrintUsage(argv[0], 0);
315     goto done;
316   }
317
318   inputfile=argv[optind++];
319   outputfile=argv[optind++];
320
321   if (argc<3) {
322                 printf ("Usage: %s <input ODIM_H5 polar volume> <output ODIM_H5 polar volume> \n",argv[0]);
323                 exit (1);
324         }
325
326         raveio = RaveIO_open(inputfile);
327         if (raveio == NULL) {
328           fprintf(stderr, "Failed to open file = %s\n", inputfile);
329           goto done;
330         }
331
332         wrwp = RAVE_OBJECT_NEW(&Wrwp_TYPE);
333         if (wrwp == NULL) {
334           fprintf(stderr, "Failed to create wrwp object\n");
335           goto done;
336         }
337
338         Wrwp_setDZ(wrwp, dz_value);
339         Wrwp_setNODATA_VP(wrwp, nodata_vp);
340         Wrwp_setUNDETECT_VP(wrwp, undetect_vp);
341         Wrwp_setOFFSET_VP(wrwp, offset_vp);
342         Wrwp_setGAIN_VP(wrwp, gain_vp);
343         Wrwp_setHMAX(wrwp, hmax);
344         Wrwp_setDMIN(wrwp, dmin);
345         Wrwp_setDMAX(wrwp, dmax);
346         Wrwp_setEMIN(wrwp, emin);
347         Wrwp_setVMIN(wrwp, vmin);
348
349         /*Opening of HDF5 radar input file.*/
350         if (RaveIO_getObjectType(raveio)== Rave_ObjectType_PVOL) {
351                 inobj = (PolarVolume_t*)RaveIO_getObject(raveio);
352         }
353         else {
354                 printf ("Input file is not a polar volume. Giving up ...\n");
355                 goto done;
356         }
357         RaveIO_close (raveio);
358
359         result = Wrwp_generate(wrwp, inobj, quantities);
360         if (inobj == NULL) {
361                 printf ("Could not derive wind profile %s, exiting ...\n", argv[1]);
362                 goto done;
363         }
364
365         RaveIO_setObject(raveio, (RaveCoreObject*)result);
366
367         if (!RaveIO_save(raveio, outputfile))
368           goto done;
369
370   if (debug_flag) {
371     printf("Generated vertical profile...\n");
372     printf("Input file: %s\n", inputfile);
373     printf("Output file: %s\n", outputfile);
374     printf("DZ         = %d\n", Wrwp_getDZ(wrwp));
375     printf("NODATA     = %d\n", Wrwp_getNODATA_VP(wrwp));
376     printf("UNDETECT   = %d\n", Wrwp_getUNDETECT_VP(wrwp));
377     printf("GAIN       = %lf\n", Wrwp_getGAIN_VP(wrwp));
378     printf("OFFSET     = %lf\n", Wrwp_getOFFSET_VP(wrwp));
379     printf("HMAX       = %d\n", Wrwp_getHMAX(wrwp));
380     printf("DMIN       = %d\n", Wrwp_getDMIN(wrwp));
381     printf("DMAX       = %d\n", Wrwp_getDMAX(wrwp));
382     printf("EMIN       = %lf\n", Wrwp_getEMIN(wrwp));
383     printf("VMIN       = %lf\n", Wrwp_getVMIN(wrwp));
384   }
385
386         exitcode = 0;
387 done:
388         RAVE_OBJECT_RELEASE(raveio);
389         RAVE_OBJECT_RELEASE(inobj);
390         RAVE_OBJECT_RELEASE(result);
391         RAVE_FREE(quantities);
392
393         return exitcode;
394 }