/* $Id: ConvertDDTimeToDouble.c,v 1.0 2019/10/03 13:39:00 benjamin Exp $*/ /*===================================================================== * DD SYSTEM base package * DD_Server library * ConvertDDTimeToDouble.c * * usage ConvertDDTimeToDouble * * Versions: *=====================================================================*/ /*===================================================================== * Description: * Program to convert DDTime of a list of nc_data_files to timestamp (double). Data file can be gzipped *======================================================================*/ #include #include #include #include #include #include #include #include /*================================================================================== * READ NC FILE INFO *==================================================================================*/ typedef struct { int id; char name[NC_MAX_NAME+1]; size_t length; int isUnlimited; } NCDimInfo; typedef struct { int id; char name[NC_MAX_NAME+1]; size_t length; nc_type type; void* value; } NCAttInfo; typedef struct { int id; char name[NC_MAX_NAME+1]; int ndims; int dimids[NC_MAX_VAR_DIMS]; int natts; NCAttInfo *atts; nc_type type; } NCVarInfo; typedef struct { int id; int ndims; NCDimInfo *dims; int natts; NCAttInfo *atts; int nvars; NCVarInfo *vars; } NCFileInfo; /*================================================================================== * READ NC FILE INFO *==================================================================================*/ int readNCFileInfo(char* filePath, NCFileInfo* info) { memset(info, 0, sizeof(NCFileInfo)); int status = nc_open(filePath, 0, &info->id); if (status != NC_NOERR) { fprintf(stderr,"Cannot open NC file %s\n",filePath); return 0; } // General info int unlimdimid; status = nc_inq(info->id, &info->ndims, &info->nvars, &info->natts, &unlimdimid); if (status != NC_NOERR) { fprintf(stderr,"Cannot retrieve general info of NC file %s\n",filePath); return 0; } //Load dims int i, j; if (info->ndims > 0) { info->dims = malloc(info->ndims * sizeof(NCDimInfo)); } for (i = 0; i < info->ndims; ++i) { status = nc_inq_dim(info->id, i, info->dims[i].name, &info->dims[i].length); if (status != NC_NOERR) { fprintf(stderr,"Cannot retrieve dim info %d of NC file %s\n",i,filePath); return 0; } status = nc_inq_dimid(info->id, info->dims[i].name, &info->dims[i].id); if (status != NC_NOERR) { fprintf(stderr,"Cannot retrieve dim id %d of NC file %s\n",i,filePath); return 0; } info->dims[i].isUnlimited = (unlimdimid == info->dims[i].id); } //Load global attributes if (info->natts > 0) { info->atts = malloc(info->natts * sizeof(NCAttInfo)); } for (i = 0; i < info->natts; ++i) { status = nc_inq_attname(info->id, NC_GLOBAL, i, info->atts[i].name); if (status != NC_NOERR) { fprintf(stderr,"Cannot retrieve global att name %d of NC file %s\n",i,filePath); return 0; } status = nc_inq_att(info->id, NC_GLOBAL, info->atts[i].name, &info->atts[i].type, &info->atts[i].length); if (status != NC_NOERR) { fprintf(stderr,"Cannot retrieve global att info %d of NC file %s\n",i,filePath); return 0; } info->atts[i].value = malloc(info->atts[i].length * nctypelen(info->atts[i].type)); status = nc_get_att(info->id, NC_GLOBAL, info->atts[i].name, info->atts[i].value); if (status != NC_NOERR) { fprintf(stderr,"Cannot retrieve global att value %d of NC file %s\n",i,filePath); } } //Load variables if (info->nvars > 0) { info->vars = malloc(info->nvars * sizeof(NCVarInfo)); } for (i = 0; i < info->nvars; ++i) { status = nc_inq_var(info->id, i, info->vars[i].name, &info->vars[i].type, &info->vars[i].ndims, info->vars[i].dimids, &info->vars[i].natts); if (status != NC_NOERR) { fprintf(stderr,"Cannot retrieve variable info %d of NC file %s\n",i,filePath); return 0; } //Load variable attributes if (info->vars[i].natts > 0) { info->vars[i].atts = malloc(info->vars[i].natts * sizeof(NCAttInfo)); } for (j = 0; j < info->vars[i].natts; ++j) { status = nc_inq_attname(info->id, i, j, info->vars[i].atts[j].name); if (status != NC_NOERR) { fprintf(stderr,"Cannot retrieve variable %d att name %d of NC file %s\n",i,j,filePath); return 0; } status = nc_inq_att(info->id, i, info->vars[i].atts[j].name, &info->vars[i].atts[j].type, &info->vars[i].atts[j].length); if (status != NC_NOERR) { fprintf(stderr,"Cannot retrieve variable %d att info %d of NC file %s\n",i,j,filePath); return 0; } info->vars[i].atts[j].value = malloc(info->vars[i].atts[j].length * nctypelen(info->vars[i].atts[j].type)); status = nc_get_att(info->id, i, info->vars[i].atts[j].name, info->vars[i].atts[j].value); if (status != NC_NOERR) { fprintf(stderr,"Cannot retrieve variable %d att value %d of NC file %s\n",i,j,filePath); } } } return 1; } /*================================================================================== * CLOSE NC FILE and free memory *==================================================================================*/ void closeNCFile(NCFileInfo* info) { int i,j; if (info->ndims > 0) { free(info->dims); } if (info->natts > 0) { for (i = 0; i < info->natts; ++i) { if (info->atts[i].value != NULL) { free(info->atts[i].value); } } free(info->atts); } if (info->nvars > 0) { for (i = 0; i < info->nvars; ++i) { if (info->vars[i].natts > 0) { for (j = 0; j < info->vars[i].natts; ++j) { if (info->vars[i].atts[j].value != NULL) { free(info->vars[i].atts[j].value); } } free(info->vars[i].atts); } } free(info->vars); } int status = nc_close(info->id); if (status != NC_NOERR) { fprintf(stderr,"Cannot close NC file\n"); } memset(info, 0, sizeof(NCFileInfo)); } /*================================================================================== * convertDDTimeToDouble *==================================================================================*/ void convertDDTimeToDouble(void* values, void* values_converted, int nbRecs) { int i; double TimeStampValue; char DDTimeValue[TIMELENGTH+1]; memset(DDTimeValue,0,(TIMELENGTH+1)*sizeof(char)); for (i = 0; i < nbRecs; ++i) { memcpy(DDTimeValue, values + i * (TIMELENGTH*sizeof(char)), TIMELENGTH*sizeof(char)); TimeStampValue = DD_Time2Double(DDTimeValue); memcpy(values_converted + i * sizeof(double), &TimeStampValue, sizeof(double)); } } /*================================================================================== * CONVERT NC FILE *==================================================================================*/ #define CONV_OK 1 #define CONV_NOTNEED 2 #define CONV_ERROR 0 int convertNCFile(char* oldFilePath, char* newFilePath) { char TimeName[] = "Time"; //Read info of old NC file NCFileInfo info; int status = readNCFileInfo(oldFilePath,&info); if (status == 0) { closeNCFile(&info); return CONV_ERROR; } //Retrieve time in old file int oldFileTimeVarIndex = -1; int i; for (i = 0; i < info.nvars; ++i) { if (strcmp(info.vars[i].name, TimeName) == 0) { oldFileTimeVarIndex = i; break; } } if (oldFileTimeVarIndex < 0) { fprintf(stderr,"Cannot retrieve %s variable in old NC file\n", TimeName); closeNCFile(&info); return CONV_ERROR; } if (info.vars[oldFileTimeVarIndex].type == NC_DOUBLE) { //Time is already in double format => Nothing to do closeNCFile(&info); return CONV_NOTNEED; } //Retrieve time dim in old file int oldFileTimeDimIndex = -1; int isTimeUnlimitedDim = 0; for (i = 0; i < info.ndims; ++i) { if (info.dims[i].id == info.vars[oldFileTimeVarIndex].dimids[0]) { oldFileTimeDimIndex = i; isTimeUnlimitedDim = info.dims[i].isUnlimited; break; } } //Create new file int newFileId; status = nc_create(newFilePath, NC_CLOBBER, &newFileId); if (status != NC_NOERR) { fprintf(stderr,"Cannot create NC file %s %s\n",newFilePath,nc_strerror(status)); closeNCFile(&info); return CONV_ERROR; } //Create dimensions in new file int tmpId; for (i = 0; i < info.ndims; ++i) { status = nc_def_dim(newFileId, info.dims[i].name, (info.dims[i].isUnlimited == 1) ? NC_UNLIMITED : info.dims[i].length, &tmpId); if (status != NC_NOERR) { fprintf(stderr,"Cannot create dim %d in new file %s\n",i,newFilePath); closeNCFile(&info); return CONV_ERROR; } } //Create global attributes in new file for (i = 0; i < info.natts; ++i) { status = nc_put_att(newFileId, NC_GLOBAL, info.atts[i].name, info.atts[i].type, info.atts[i].length, info.atts[i].value); if (status != NC_NOERR) { fprintf(stderr,"Cannot create global att %d in new file %s\n",i,newFilePath); closeNCFile(&info); return CONV_ERROR; } } //Create variables in new file int j; for (i = 0; i < info.nvars; ++i) { if (oldFileTimeVarIndex == i) { status = nc_def_var(newFileId, info.vars[i].name, NC_DOUBLE, 1, info.vars[i].dimids, &tmpId); } else { status = nc_def_var(newFileId, info.vars[i].name, info.vars[i].type, info.vars[i].ndims, info.vars[i].dimids, &tmpId); } if (status != NC_NOERR) { fprintf(stderr,"Cannot create var %d in new file %s\n",i,newFilePath); closeNCFile(&info); return CONV_ERROR; } //Create variable attributes for (j = 0; j < info.vars[i].natts; ++j) { status = nc_put_att(newFileId, i, info.vars[i].atts[j].name, info.vars[i].atts[j].type, info.vars[i].atts[j].length, info.vars[i].atts[j].value); if (status != NC_NOERR) { fprintf(stderr,"Cannot create local att %d for var %d in new file %s\n",j,i,newFilePath); closeNCFile(&info); return CONV_ERROR; } } } status = nc_enddef(newFileId); void* values; void* values_converted; int k; int size; size_t* start; size_t* count; for (i = 0; i < info.nvars; ++i) { start = malloc(info.vars[i].ndims * sizeof(size_t)); count = malloc(info.vars[i].ndims * sizeof(size_t)); //Load old values size = 1; for (j = 0; j < info.vars[i].ndims; ++j) { start[j] = 0; for (k = 0; k < info.ndims; ++k) { if (info.vars[i].dimids[j] == info.dims[k].id) { count[j] = info.dims[k].length; size *= info.dims[k].length; break; } } } values = malloc(size * nctypelen(info.vars[i].type)); status = nc_get_vara(info.id, i, start, count, values); if (status != NC_NOERR) { fprintf(stderr,"Cannot load var values %d from old file %s\n",i,oldFilePath); free(values); free(start); free(count); closeNCFile(&info); return CONV_ERROR; } //Copy or convert values if (oldFileTimeVarIndex == i) { values_converted = malloc(size * nctypelen(NC_DOUBLE)); convertDDTimeToDouble(values, values_converted, count[0]); status = nc_put_vara(newFileId, i, start, count, values_converted); free(values_converted); } else { status = nc_put_vara(newFileId, i, start, count, values); } free(values); free(start); free(count); if (status != NC_NOERR) { fprintf(stderr,"Cannot copy var values %d in new file %s\n",i,newFilePath); closeNCFile(&info); return CONV_ERROR; } } nc_close(newFileId); closeNCFile(&info); return CONV_OK; } /*================================================================================== * MAIN *==================================================================================*/ #define COMMAND_MAX_LEN 1000 #define MAX_FILENAME_LEN 100 main(int argc, char **argv) { static char usage[] = "usage: ConvertDDTimeToDouble nc_data_file[*.gz]"; if (argc < 2) {fprintf(stderr,"%s\n",usage); exit(1); } char inputFileName[MAX_FILENAME_LEN+1]; char unzippedFileName[MAX_FILENAME_LEN+1]; char workingFileName[] = "ConvertDDTimeToDouble.nc"; char command[COMMAND_MAX_LEN+1]; int i; int zippedFile = 0; int status; for (i = 1; i < argc; ++i) { if (strlen(argv[i]) > MAX_FILENAME_LEN) { fprintf(stderr,"File name size exceed the max size : %s\n",argv[i]); continue; } memset(inputFileName, 0, (MAX_FILENAME_LEN+1) * sizeof(char)); strcpy(inputFileName,argv[i]); memset(command, 0, (COMMAND_MAX_LEN+1) * sizeof(char)); if((strlen(inputFileName) > 3) && (strcmp(inputFileName+strlen(inputFileName)-3,".gz") == 0)) // Zipped file { strcpy(unzippedFileName, inputFileName); unzippedFileName[strlen(inputFileName)-3] = '\0'; sprintf(command,"gunzip -c %s > %s",inputFileName,unzippedFileName); zippedFile = 1; } else { zippedFile = 0; strcpy(unzippedFileName, inputFileName); } status = system(command); if (status != 0) { fprintf(stderr,"Cannot create working input file for %s\n",argv[i]); continue; } status = convertNCFile(unzippedFileName, workingFileName); if (status == CONV_NOTNEED) { fprintf(stderr,"[WARNING] File %s already converted\n", inputFileName); continue; } else if (status == CONV_ERROR) { fprintf(stderr,"[ERROR] Error detected during %s file conversion\n", inputFileName); continue; } memset(command, 0, (COMMAND_MAX_LEN+1) * sizeof(char)); sprintf(command,"cp -p %s %s",workingFileName,unzippedFileName); status = system(command); if (status != 0) { fprintf(stderr,"[ERROR] Cannot copy result file in %s\n",inputFileName); continue; } if (zippedFile == 1) { memset(command, 0, (COMMAND_MAX_LEN+1) * sizeof(char)); sprintf(command,"gzip -f %s",unzippedFileName); status = system(command); if (status != 0) { fprintf(stderr,"[ERROR] Cannot compress result file\n"); } } fprintf(stderr,"[INFO] File %s converted\n", inputFileName); } memset(command, 0, (COMMAND_MAX_LEN+1) * sizeof(char)); sprintf(command,"rm -f %s",workingFileName); status = system(command); return(0); } /*=========================================================================================================*/