1 /* Copyright (c) 1999-2017 Massachusetts Institute of Technology
2 *
3 * [ IMPORTANT: Note that the following is DIFFERENT from the license
4 * for the rest of the h5utils package. ]
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25
26 #include <unistd.h>
27
28 #include "config.h"
29 #include "arrayh5.h"
30 #include "h5utils.h"
31
32 /* Vis5d header files: */
33 #if defined(HAVE_VIS5Dp_V5D_H)
34 # include <vis5d+/v5d.h>
35 #elif defined(HAVE_VIS5D_V5D_H)
36 # include <vis5d/v5d.h>
37 #else
38 # include <v5d.h>
39 #endif
40
41 #define CHECK(cond, msg) { if (!(cond)) { fprintf(stderr, "h5tov5d error: %s\n", msg); exit(EXIT_FAILURE); } }
42
usage(FILE * f)43 void usage(FILE *f)
44 {
45 fprintf(f, "Usage: h5tov5d [options] [<filenames>]\n"
46 "Options:\n"
47 " -h : this help message\n"
48 " -V : print version number and copyright\n"
49 " -v : verbose output\n"
50 " -T : transposed output dimensions\n"
51 " -x <ix> : take x=<ix> slice of data\n"
52 " -y <iy> : take y=<iy> slice of data\n"
53 " -z <iz> : take z=<iz> slice of data\n"
54 " -t <it> : take t=<it> slice of data's last dimension\n"
55 " -0 : use dataset center as origin for -x/-y/-z\n"
56 " -o <file> : output datasets from all input files to <file>\n"
57 " -1,-2,-4 : number of bytes per data point to use in output (default: 1)\n"
58 " (fewer bytes is faster, but has less resolution)\n"
59 " -d <name> : use dataset <name> in the input files (default: first dataset)\n"
60 " -- you can also specify a dataset via <filename>:<name>\n"
61 );
62 }
63
64 /* The following routine was adapted from convert/foo2_to_v5d.c from
65 Vis5D 4.2, which is Copyright (C) 1990-1997 Bill Hibbard, Johan
66 Kellum, Brian Paul, Dave Santek, and Andre Battaiola, and is
67 distributed under the GNU General Public License. */
output_v5d(char * v5d_fname,char * data_label,int nslicedim,const int * slicedim,const int * islice,const int * center_slice,int store_bytes,int transpose,char ** h5_fnames,int num_h5,int join)68 void output_v5d(char *v5d_fname, char *data_label,
69 int nslicedim, const int *slicedim,
70 const int *islice, const int *center_slice,
71 int store_bytes, int transpose,
72 char **h5_fnames, int num_h5, int join)
73 {
74 char *data_name;
75 char *fname;
76 arrayh5 a;
77 int it, iv, firstdim, ifile;
78 float *g = 0;
79
80 /** Parameters to v5dCreate: */
81 int NumTimes; /* number of time steps */
82 int NumVars; /* number of variables */
83 int Nr, Nc, Nl[MAXVARS]; /* size of 3-D grids */
84 char VarName[MAXVARS][10]; /* names of variables */
85 int TimeStamp[MAXTIMES]; /* real times for each time step */
86 int DateStamp[MAXTIMES]; /* real dates for each time step */
87 int CompressMode; /* number of bytes per grid */
88 int Projection; /* a projection number */
89 float ProjArgs[100]; /* the projection parameters */
90 int Vertical; /* a vertical coord system number */
91 float VertArgs[MAXLEVELS]; /* the vertical coord sys parameters */
92
93 if (num_h5 <= 0)
94 return;
95
96 for (ifile = 0; ifile < num_h5; ++ifile) {
97 int err;
98 fname = split_fname(h5_fnames[ifile], &data_name);
99 if (!data_name[0]) data_name = data_label;
100 err = arrayh5_read(&a, fname, data_name, NULL,
101 nslicedim, slicedim, islice, center_slice);
102 free(fname);
103 CHECK(!err, arrayh5_read_strerror[err]);
104 CHECK(a.rank >= 1, "data must have at least one dimension");
105 CHECK(a.rank <= 5, "data cannot have more than 5 dimensions");
106
107
108 /* if the data is 4 dimensional, express that by using
109 different times and/or variables */
110 NumTimes = a.rank < 4 ? 1 : a.dims[a.rank - 1];
111 CHECK(NumTimes <= MAXTIMES, "too many time steps");
112 firstdim = a.rank <= 4 ? 0 : a.rank - 4;
113
114 /* If the data is 5 dimensional, express that by using different
115 variables. Alternatively, if we are joining, the different
116 variables are the different files; in that case, the data
117 cannot be 5d. */
118 NumVars = a.rank < 5 ? 1 : a.dims[0];
119 if (join) {
120 CHECK(NumVars == 1, "cannot join 5d datasets");
121 NumVars = num_h5;
122 }
123 CHECK(NumVars <= MAXVARS, "too many vars");
124
125 if (!transpose) {
126 /* we will need to transpose the data, since HDF5 gives
127 us the data in row-major order, while Vis5D expects
128 it in column-major order (we could avoid physically
129 transposing the data by passing Vis5d transposed
130 dimensions, but that seems ugly). */
131 Nr = firstdim >= a.rank ? 1 : a.dims[firstdim];
132 Nc = firstdim+1 >= a.rank ? 1 : a.dims[firstdim+1];
133 Nl[0] = firstdim+2 >= a.rank ? 1 : a.dims[firstdim+2];
134 }
135 else {
136 Nr = firstdim+2 >= a.rank ? 1 : a.dims[firstdim+2];
137 Nc = firstdim+1 >= a.rank ? 1 : a.dims[firstdim+1];
138 Nl[0] = firstdim >= a.rank ? 1 : a.dims[firstdim];
139 }
140
141 if (!v5d_fname) {
142 fname = split_fname(h5_fnames[ifile], &data_name);
143 v5d_fname = replace_suffix(fname, ".h5", ".v5d");
144 free(fname);
145 }
146
147 if (join && ifile == 0) {
148 arrayh5_destroy(a); /* destroy while we check other datasets */
149
150 /* loop to assign VarName[] and Nl[] arrays: */
151 for (iv = 0; iv < NumVars; ++iv) {
152 char *name;
153 int numTimes, nr, nc, fdim;
154
155 fname = split_fname(h5_fnames[iv], &data_name);
156 name = replace_suffix(fname, ".h5",
157 data_name[0] ? data_name - 1 : "");
158 if (!data_name[0]) data_name = data_label;
159
160 for (it = 0; it < 9 && name[it]; ++it)
161 VarName[iv][it] = name[it];
162 VarName[iv][it] = 0;
163 free(name);
164
165 /* we don't really have to read the whole array;
166 if we called HDF5 routines directly, we could just
167 get the dimensions...oh well */
168 err = arrayh5_read(&a, fname, data_name, NULL,
169 nslicedim, slicedim,
170 islice, center_slice);
171 CHECK(!err, arrayh5_read_strerror[err]);
172 free(fname);
173
174 numTimes = a.rank < 4 ? 1 : a.dims[a.rank - 1];
175 fdim = a.rank <= 4 ? 0 : a.rank - 4;
176 if (!transpose) {
177 nr = fdim >= a.rank ? 1 : a.dims[fdim];
178 nc = fdim+1 >= a.rank ? 1 : a.dims[fdim+1];
179 Nl[iv] = fdim+2 >= a.rank ? 1 : a.dims[fdim+2];
180 }
181 else {
182 nr = fdim+2 >= a.rank ? 1 : a.dims[fdim+2];
183 nc = fdim+1 >= a.rank ? 1 : a.dims[fdim+1];
184 Nl[iv] = fdim >= a.rank ? 1 : a.dims[fdim];
185 }
186 CHECK(numTimes == NumTimes && nr == Nr && nc == Nc,
187 "datasets to be joined must have same dimensions");
188
189 arrayh5_destroy(a);
190 }
191
192 /* read first array back in */
193 fname = split_fname(h5_fnames[ifile], &data_name);
194 if (!data_name[0]) data_name = data_label;
195 err = arrayh5_read(&a, fname, data_name, NULL,
196 nslicedim, slicedim, islice, center_slice);
197 CHECK(!err, arrayh5_read_strerror[err]);
198 free(fname);
199 }
200 else if (!join) {
201 if (data_label) {
202 for (it = 0; it < 9 && data_label[it]; ++it)
203 VarName[0][it] = data_label[it];
204 VarName[0][it] = 0;
205 }
206 else { /* use file name, minus ".v5d" suffix, for var name */
207 int suff = strlen(v5d_fname) - 4;
208 if (suff < 0 || strcmp(v5d_fname + suff, ".v5d"))
209 suff += 4; /* no ".v5d"; suff = end of string */
210
211 for (it = 0; it < 9 && it < suff; ++it)
212 VarName[0][it] = v5d_fname[it];
213 VarName[0][it] = 0;
214 }
215
216 for (iv = 1; iv < NumVars; ++iv) {
217 Nl[iv] = Nl[0]; /* all variables have the same dims */
218 if (iv <= 999999999) /* paranoia: ensure sprintf is safe */
219 sprintf(VarName[iv], "%d", iv);
220 else
221 strcpy(VarName[iv], "Infinity");
222 }
223 }
224
225 for (it = 0; it < NumTimes; ++it) {
226 TimeStamp[it] = it;
227 DateStamp[it] = 0; /* don't bother to make up a real date */
228 }
229
230 CompressMode = store_bytes;
231 CHECK(CompressMode == 1 || CompressMode == 2 || CompressMode == 4,
232 "can only store v5d data as 1, 2, or 4 bytes!");
233
234 Projection = 0; /* linear, rectangular, generic units */
235 ProjArgs[0] = ProjArgs[1] = 0; /* origin of row/col coord system */
236 ProjArgs[2] = ProjArgs[3] = 1; /* coord increment between rows/cols*/
237
238 Vertical = 0; /* equally spaced levels in generic units */
239 VertArgs[0] = 0.0; /* position of bottom level */
240 VertArgs[1] = 1.0; /* spacing between levels */
241
242 /* use v5dCreate call to create the v5d file and write the header */
243 if (!join || ifile == 0) {
244 CHECK(v5dCreate(v5d_fname, NumTimes, NumVars, Nr, Nc, Nl,
245 VarName, TimeStamp, DateStamp, CompressMode,
246 Projection, ProjArgs, Vertical, VertArgs),
247 "couldn't create v5d file");
248 }
249
250 /* may call v5dSetLowLev() or v5dSetUnits() here; see Vis5d README */
251
252 /* allocate array for copying transpose of data: */
253 g = (float *) malloc(sizeof(float) * Nr * Nc * Nl[0]);
254 CHECK(g, "out of memory!");
255
256 for (iv = join ? ifile : 0; iv < (join ? ifile + 1 : NumVars); ++iv)
257 for (it = 0; it < NumTimes; ++it) {
258 double *d = a.data + it +
259 (join ? 0 : iv) * NumTimes * Nr * Nc * Nl[0];
260
261 if (!transpose) {
262 int ir, ic, il;
263 for (ir = 0; ir < Nr; ++ir)
264 for (ic = 0; ic < Nc; ++ic)
265 for (il = 0; il < Nl[0]; ++il)
266 g[ir + Nr * (ic + Nc * il)] =
267 d[(il + Nl[0] * (ic + Nc * ir))
268 * NumTimes];
269 }
270 else {
271 int id;
272 for (id = 0; id < Nr * Nc * Nl[0]; ++id)
273 g[id] = d[id * NumTimes];
274 }
275 CHECK(v5dWrite(it + 1, iv + 1, g),
276 "error writing v5d output");
277 }
278
279 free(g);
280
281 if (!join || ifile == num_h5 - 1)
282 v5dClose();
283
284 arrayh5_destroy(a);
285 if (v5d_fname)
286 free(v5d_fname);
287 v5d_fname = NULL;
288 }
289 }
290
main(int argc,char ** argv)291 int main(int argc, char **argv)
292 {
293 char *v5d_fname = NULL, *data_name = NULL;
294 extern char *optarg;
295 extern int optind;
296 int c;
297 int verbose = 0, transpose = 0;
298 int slicedim[4] = {NO_SLICE_DIM,NO_SLICE_DIM,NO_SLICE_DIM,NO_SLICE_DIM};
299 int islice[4], center_slice[4] = {0,0,0,0};
300 int store_bytes = 1;
301
302 while ((c = getopt(argc, argv, "ho:d:vTV124x:y:z:t:0")) != -1)
303 switch (c) {
304 case 'h':
305 usage(stdout);
306 return EXIT_SUCCESS;
307 case 'V':
308 printf("h5tov5d " PACKAGE_VERSION " by Steven G. Johnson\n"
309 "Copyright (c) 1999-2017 Massachusetts Institute of Technology\n"
310 "\n"
311 "This program is free software; you can redistribute it and/or modify\n"
312 "it under the terms of the GNU General Public License as published by\n"
313 "the Free Software Foundation; either version 2 of the License, or\n"
314 "(at your option) any later version.\n"
315 "\n"
316 "This program is distributed in the hope that it will be useful,\n"
317 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
318 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
319 "GNU General Public License for more details.\n"
320 );
321 return EXIT_SUCCESS;
322 case 'v':
323 verbose = 1;
324 break;
325 case 'T':
326 transpose = 1;
327 break;
328 case 'x':
329 islice[0] = atoi(optarg);
330 slicedim[0] = 0;
331 break;
332 case 'y':
333 islice[1] = atoi(optarg);
334 slicedim[1] = 1;
335 break;
336 case 'z':
337 islice[2] = atoi(optarg);
338 slicedim[2] = 2;
339 break;
340 case 't':
341 islice[3] = atoi(optarg);
342 slicedim[3] = LAST_SLICE_DIM;
343 break;
344 case '0':
345 center_slice[0] = center_slice[1] = center_slice[2] = 1;
346 break;
347 case '1':
348 store_bytes = 1;
349 break;
350 case '2':
351 store_bytes = 2;
352 break;
353 case '4':
354 store_bytes = 4;
355 break;
356 case 'o':
357 v5d_fname = my_strdup(optarg);
358 break;
359 case 'd':
360 data_name = my_strdup(optarg);
361 break;
362 default:
363 fprintf(stderr, "Invalid argument -%c\n", c);
364 usage(stderr);
365 return EXIT_FAILURE;
366 }
367 if (optind == argc) { /* no parameters left */
368 usage(stderr);
369 return EXIT_FAILURE;
370 }
371
372 output_v5d(v5d_fname, data_name,
373 4, slicedim, islice, center_slice,
374 store_bytes, transpose,
375 argv + optind, argc - optind, v5d_fname != NULL);
376
377 if (data_name)
378 free(data_name);
379
380 return EXIT_SUCCESS;
381 }
382