Converts MM5 files, given in NetCDF format, to F5, as time-dependent 3D unidistant scalar and vector fields.
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <netcdf.h> #include <hdf5.h> #include <F5/F5uniform.h> #include <F5/F5coordinates.h> #include <F5/F5X.h> #ifdef DEBUG_ON # define DEBUG(fmt, ...) printf("DEBUG: " fmt "\n", __VA_ARGS__) #else # define DEBUG(...) #endif #define MAXDIMS (NC_MAX_VAR_DIMS) #define MAXGROUPS 10 #define MAXPATH 1024 #define MAXATTR 256 #define VARSEP ",; " struct varinfo { char *name; nc_type type; int ndims, id; size_t *dim; int *ivar, size; }; struct vardata { struct varinfo *ncref; union { void *vptr; double *dptr; float *fptr; int *iptr; short *sptr; }; hid_t h5type; }; typedef struct varinfo vinfo; typedef struct vardata vdata; void error(char *msg) { fprintf(stderr, "ERROR: %s\n", msg); exit(1); } vinfo *get_varinfo(int fd, int id) { int i, dimid[MAXDIMS], natt; char nm[NC_MAX_NAME+1]; vinfo *v = 0; v = malloc(sizeof(vinfo)); if (nc_inq_var(fd, id, nm, &(v->type), &(v->ndims), dimid, &natt) != NC_NOERR) error("cannot retrieve variable information"); v->id = id; strcpy(v->name = malloc(strlen(nm)+1), nm); if (v->ndims > 0) { int tot = 1; v->ivar = malloc(v->ndims*sizeof(int)); v->dim = malloc(v->ndims*sizeof(size_t)); for (i = 0; i < v->ndims; i++) { v->ivar[i] = dimid[i]; if (nc_inq_dimlen(fd, dimid[i], v->dim+i) != NC_NOERR) error("failed to retrieve dimension length"); DEBUG("dimlen of index id=%d is %d", dimid[i], v->dim[i]); tot *= v->dim[i]; } v->size = tot; } else { v->ivar = v->dim = 0; v->size = 1; } DEBUG("variable '%s' info: id=%d ndims=%d size=%d", nm, id, v->ndims, v->size); return v; } vdata **get_ncvars(int fd, int nvars, char *vars[]) { int i, vid, nd; size_t start[MAXDIMS]; nc_type type; vdata **outvar = malloc(sizeof(vdata)*nvars); memset(start, 0, sizeof(size_t)*MAXDIMS); for (i = 0; i < nvars; i++) { int rc, k; vinfo *vi; vdata *vd = malloc(sizeof(vdata)); outvar[i] = vd; if (nc_inq_varid(fd, vars[i], &vid) != NC_NOERR) error("cannot find requested variable"); vd->ncref = vi = get_varinfo(fd, vid); } return outvar; } void read_ncvars(int fd, vinfo *ui, vdata **vd, int nvars) { int i; size_t start[MAXDIMS]; memset(start, 0, sizeof(size_t)*MAXDIMS); for (i = 0; i < nvars; i++) { vinfo *vi = vd[i]->ncref; switch (vi->type) { case NC_FLOAT: vd[i]->fptr = malloc(ui->size*sizeof(float)); DEBUG("allocated %d bytes for \"%s\" data", ui->size*sizeof(float), vi->name); if (nc_get_vara_float(fd, vi->id, start, ui->dim, vd[i]->fptr) != NC_NOERR) error("failed to read float array"); vd[i]->h5type = H5T_NATIVE_FLOAT; break; case NC_DOUBLE: vd[i]->dptr = malloc(ui->size*sizeof(double)); DEBUG("allocated %d bytes for \"%s\" data", ui->size*sizeof(double), vi->name); if (nc_get_vara_double(fd, vi->id, start, ui->dim, vd[i]->dptr) != NC_NOERR) error("failed to read double array"); vd[i]->h5type = H5T_NATIVE_DOUBLE; break; case NC_INT: vd[i]->iptr = malloc(ui->size*sizeof(int)); DEBUG("allocated %d bytes for \"%s\" data", ui->size*sizeof(int), vi->name); if (nc_get_vara_int(fd, vi->id, start, ui->dim, vd[i]->iptr) != NC_NOERR) error("failed to read int array"); vd[i]->h5type = H5T_NATIVE_INT; break; case NC_SHORT: vd[i]->sptr = malloc(ui->size*sizeof(short)); DEBUG("allocated %d bytes for \"%s\" data", ui->size*sizeof(short), vi->name); if (nc_get_vara_short(fd, vi->id, start, ui->dim, vd[i]->sptr) != NC_NOERR) error("failed to read short array"); vd[i]->h5type = H5T_NATIVE_SHORT; break; default: /* TODO: add other netcdf types */ error("unrecognized variable type"); } } } vinfo *get_time(int fd, char *tname) { int tid; vinfo *tv; if (nc_inq_varid(fd, tname, &tid) != NC_NOERR) error("couldn't find time variable"); if (!(tv = get_varinfo(fd, tid))) error("failed to extract time variable info"); if ((tv->ndims > 1) || ((tv->ndims == 1) && (tv->dim[0] > 1))) error("multiple time steps within netCDF file are not supported yet"); return tv; } vinfo *unify(vinfo *tinfo, vdata **vd, int vnum) { int i, k; vinfo *vi, *m = malloc(sizeof(vinfo)); for (i = 0; i < vnum; i++) { vi = vd[i]->ncref; if (!i) { m->dim = malloc(sizeof(size_t)*(m->ndims = vi->ndims)); memcpy(m->dim, vi->dim, m->ndims*sizeof(size_t)); } else { if (m->ndims != vi->ndims) return 0; for (k = 0; k < vi->ndims; k++) { /* simplistic for now: just chop of any additional grid points */ if (m->dim[k] > vi->dim[k]) m->dim[k] = vi->dim[k]; } } } for (m->size = 1, k = 0; k < m->ndims; k++) { DEBUG("unified dim[%d]=%d", k, m->dim[k]); m->size *= m->dim[k]; } return m; } void dimopt(vinfo *ui) { int k, l = 0; for (k = 0; k < ui->ndims; k++) { if (ui->dim[k] != 1) ui->dim[l++] = ui->dim[k]; else { DEBUG("eliminated index %d", k); } } ui->ndims = l; DEBUG("number of unified dimensions set to %d:", l); for (k = 0; k < ui->ndims; k++) DEBUG("dim[%d]=%d", k, ui->dim[k]); } void usage(char *pname, int rc) { fprintf(stderr, "Usage: %s [options] netcdf-files...\n", pname); fprintf(stderr, "options:\n" " -v var1[,var2]... : variable group of interest (required)\n" " -n name : dataset name for the preceding variable group\n" " -t name : name of time variable\n" " -o pathname : output file name (default: out.f5)\n" " -r float : domain resolution (meters)\n"); exit(rc); } char **optvars(char *s, int *n) { int space = MAXDIMS, done = 0; char *p, **tab = malloc(sizeof(char *)*space); for (*n = 0; s[0]; (*n)++) { if (*n >= space) { space += MAXDIMS; tab = realloc(tab, sizeof(char *)*space); } p = strpbrk(s, VARSEP); if (!p) {p = s+strlen(s); done = 1;} tab[*n] = strncpy(malloc(p-s+1), s, p-s); tab[*n][p-s] = 0; s += p-s+(done == 0); } return tab; } F5Path *writef5_uni3d_scalar(hid_t f, double t, char *name, F5_vec3_point_t *orig, F5_vec3_float_t *space, vinfo *ui, vdata *vd) { char tname[MAXATTR]; hsize_t dim[3]; F5Path *f5p; if (ui->ndims != 3) error("not a 3D grid"); dim[2] = ui->dim[0]; dim[1] = ui->dim[1]; dim[0] = ui->dim[2]; space->x /= ui->dim[0]; space->y /= ui->dim[1]; space->z /= ui->dim[2]; DEBUG("scalar type %c= float", (H5Tequal(H5T_NATIVE_FLOAT, vd->h5type) > 0? '=': '!')); DEBUG("invoking F5Fwrite_uniform_cartesian3D() with dim=[%lld,%lld,%lld] name=\"%s\" data=%p", dim[0], dim[1], dim[2], name, vd->vptr); f5p = F5Fwrite_uniform_cartesian3D(f, t, "UniformCartesian", orig, space, dim, name, vd->h5type, vd->vptr, 0, H5P_DEFAULT); F5close(f5p); return f5p; } void writef5_uni3d_f3(hid_t f, double t, char *name, F5_vec3_point_t *orig, F5_vec3_float_t *space, vinfo *ui, vdata **vd) { char tname[MAXATTR]; hsize_t dim[3]; const void *data[3]; const float *fdata[3]; F5Path *f5p; int i, rc, base; int NumOfDataValues; F5_vec3f_t* VectorData; if (ui->ndims != 3) error("not a 3D grid"); dim[2] = ui->dim[0]; dim[1] = ui->dim[1]; dim[0] = ui->dim[2]; data[0] = vd[0]->vptr; data[1] = vd[1]->vptr; data[2] = vd[2]->vptr; fdata[0] = (float*)vd[0]->vptr; fdata[1] = (float*)vd[1]->vptr; fdata[2] = (float*)vd[2]->vptr; /*Added by shalini to write array of vectors*/ NumOfDataValues = dim[2]*dim[1]*dim[0]; VectorData = malloc(sizeof(F5_vec3f_t)*NumOfDataValues); /*Convert each component array to the array of vectors*/ for (i=0;i<NumOfDataValues;i++) { VectorData[i].x = fdata[0][i]; VectorData[i].y = fdata[1][i]; VectorData[i].z = fdata[2][i]; /*fprintf(f,"Converted vector for base %d - {%f %f %f}\n",base, data[base],data[base+1],data[base+2]);*/ } if (!(f5p = F5Rcreate_uniform_cartesian3D(f, t, "UniformCartesian", orig, space, dim, 0))) error("failed to create uniform grid"); DEBUG("invoking F5Fwrites(%p, %s, 3, [%lld,%lld,%lld], float-3D, float-3D, " "[%p,%p,%p], default)", f5p, name, dim[0], dim[1], dim[2], data[0], data[1], data[2]); // F5Fwrites(f5p, name, 3, dim, F5T_VEC3_FLOAT, F5T_VEC3_FLOAT, data, // H5P_DEFAULT); //Shalin- to write the tor values as is ie array of structs F5Fwrite(f5p, name, /* fieldname */ 3, dim, /* dataspace */ F5T_VEC3_FLOAT, /* type as to appear in the file */ F5T_VEC3_FLOAT, /* type as it resides in memory */ VectorData, /* dataPtr */ F5P_DEFAULT); /* property_id */ } #if 0 void writef5_uni3d_f3(hid_t f, double t, char *name, F5_vec3_point_t *orig, F5_vec3_float_t *space, vinfo *ui, vdata **vd) { char tname[MAXATTR]; hsize_t dim[3]; F5_vec3f_t *data; /*const void *data[3];*/ F5Path *f5p; int i, rc; if (ui->ndims != 3) error("not a 3D grid"); dim[0] = ui->dim[0]; dim[1] = ui->dim[1]; dim[2] = ui->dim[2]; /* data[0] = vd[0]->vptr; data[1] = vd[1]->vptr; data[2] = vd[2]->vptr; */ data = malloc(sizeof(float)*3*ui->size); for (i = 0; i < ui->size; i++) { data[i].x = vd[0]->fptr[i]; data[i].y = vd[1]->fptr[i]; data[i].z = vd[2]->fptr[i]; } if (!(f5p = F5Rcreate_uniform_cartesian3D(f, t, "UniformCartesian", orig, space, dim, 0))) error("failed to create uniform grid"); DEBUG("invoking F5Fwrite(%p, %s, 3, [%lld,%lld,%lld], float-3D, float-3D, %p, default)", f5p, name, dim[0], dim[1], dim[2], data); F5Fwrite(f5p, name, 3, dim, F5T_VEC3_FLOAT, F5T_VEC3_FLOAT, data, H5P_DEFAULT); /* DEBUG("invoking F5Fwrites(%p, %s, 3, [%lld,%lld,%lld], float-3D, float-3D, " "[%p,%p,%p], default)", f5p, name, dim[0], dim[1], dim[2], data[0], data[1], data[2]); F5Fwrites(f5p, name, 3, dim, F5T_VEC3_FLOAT, F5T_VEC3_FLOAT, data, H5P_DEFAULT); */ } void writef5_cart3d(hid_t f, double t, char *name, F5_vec3_point_t *orig, F5_vec3_float_t *space, vinfo *ui, vdata **vd, int nvars) { char tpath[MAXATTR]; hsize_t dim[3], tsz = 0; void *data[MAXDIMS]; hid_t h5t; int i; dim[0] = ui->dim[0]; dim[1] = ui->dim[1]; dim[2] = ui->dim[2]; snprintf(tpath, MAXATTR, "%s_type", name); h5t = H5Topen(f, tpath); if (h5t < 0) { tsz = H5Tget_size(vd[0]->h5type); h5t = H5Tcreate(H5T_COMPOUND, tsz*nvars); DEBUG("created compound type of %d bytes", tsz*nvars); for (i = 0; i < nvars; i++) { if (tsz != H5Tget_size(vd[i]->h5type)) error("different sizes of vector component types"); H5Tinsert(h5t, vd[i]->ncref->name, tsz*i, vd[i]->h5type); DEBUG("inserted \"%s\" member at offset %d", vd[i]->ncref->name, tsz*i); data[i] = vd[i]->vptr; } H5Tcommit(f, tpath, h5t); } DEBUG("trying to write_uniform_cartesian3Ds(%d, %f, %s, %p, %p, %p, %s, %d, %p, %p, %d)", f, t, "Cartesian", orig, space, dim, name, h5t, (const void **)data, 0, H5P_DEFAULT); F5Fwrite_uniform_cartesian3Ds(f, t, "Cartesian", orig, space, dim, name, h5t, (const void **)data, 0, H5P_DEFAULT); } #endif void free_memory(vdata **vd, int n) { int i; for (i = 0; i < n; i++) { vinfo *vi = vd[i]->ncref; free(vd[i]->vptr); free(vi->name); if (vi->dim) free(vi->dim); if (vi->ivar) free(vi->ivar); } free(vd); } int main(int argc, char **argv) { int c, nnames[MAXGROUPS], ngroups = 0; char **vnames[MAXGROUPS], *vtags[MAXGROUPS]; char *ofile = "out.f5", *timevar = "time"; hid_t h5f; double t = 0.0, dist; while ((c = getopt(argc, argv, "v:o:n:t:r:h")) != -1) { switch (c) { case 'v': if (ngroups >= MAXGROUPS) error("exceeded max. number of variable groups"); vnames[ngroups] = optvars(optarg, nnames+ngroups); vtags[ngroups++] = 0; break; case 'n': if (ngroups <= 0) error("variable name precedes variable specifier"); vtags[ngroups-1] = optarg; break; case 't': timevar = optarg; break; case 'r': dist = strtod(optarg, 0); break; case 'o': ofile = optarg; break; case 'h': usage(argv[0], 0); default: usage(argv[0], 1); } } if (optind >= argc) usage(argv[0], 1); if ((h5f = H5Fcreate(ofile, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) error("cannot create output F5 file"); while (optind < argc) { int g, st, ncid; vdata **vtab; vinfo *uvar, *tinfo; char *ifn; ifn = argv[optind++]; if ((st = nc_open(ifn, NC_NOWRITE, &ncid) != NC_NOERR)) error("cannot open NETCDF file"); tinfo = get_time(ncid, timevar); for (g = 0; g < ngroups; g++) { F5_vec3_point_t orig; F5_vec3_float_t spc; if (!(vtab = get_ncvars(ncid, nnames[g], vnames[g]))) error("failed to get variable info from NETCDF file"); if (!(uvar = unify(tinfo, vtab, nnames[g]))) error("failed to unify dimensionalities"); read_ncvars(ncid, uvar, vtab, nnames[g]); dimopt(uvar); /* if (writef5(h5f, t, vtags[g], uvar, vtab, nnames[g]) != F5_SUCCESS) error("F5 write failed"); */ if (!vtags[g]) vtags[g] = "unspecified"; switch (uvar->ndims) { case 3: orig.x = orig.y = orig.z = 0.0; spc.x = spc.y = spc.z = dist; /* if (writef5_cart3d(h5f, t, vtags[g], &orig, &spc, uvar, vtab, nnames[g]) != F5_SUCCESS) error("failed to write field on 3D grid"); */ switch (nnames[g]) { case 3: writef5_uni3d_f3(h5f, t, vtags[g], &orig, &spc, uvar, vtab); break; case 1: writef5_uni3d_scalar(h5f, t, vtags[g], &orig, &spc, uvar, vtab[0]); break; default: error("only scalars or 3D vectors supported"); } break; case 1: error("1D grids not suppoted yet"); break; default: error("unsupported grid rank"); } } free_memory(vtab, nnames[g]); t += 1; } F5Xclose(h5f); return 0; }