/********************************************************** * Usage : amda-cdf-to-netcdf-w-false FileName [varToKeep1 varToKeep2 .....] * No 'false dims' suppression *********************************************************/ #include #include #include #include "netcdf.h" #include "cdf.h" #define MAX_FILE_NAME_LEN 120 /* Max. file name length */ #define MAX_ATTRS 3000 /* Max # of CDF attributes */ #define UNKNOWN_DT -99 /* Unsupported CDF datatype indicator */ #define DEFAULT_MAPPING_FILE "cdf_to_netcdf_mapping.dat" #define MAX_REC_LENGTH NC_MAX_NAME+CDF_ATTR_NAME_LEN256+2 /* Max record length of DEFAULT_MAPPING_FILE */ #define TRUE 1 #define FALSE 0 /************************************* Global variables and structures **************************************/ CDFid id; /* CDF file ID */ int ncid; /* netCDF file ID */ long nZvars, /* Number of zVariables in a CDF file */ nAttrs; /* Number of attributes (global & variable) in a CDF file */ typedef struct ncdim { /* netCDF dimension structure */ char name[NC_MAX_NAME+1]; /* Dimension name */ int size; /* Dimension size */ int id; /* Dimension id */ } netcdfDimension; netcdfDimension ncDims[NC_MAX_DIMS]; /* max dimensions per netCDF file */ int totNCdims = 0; /* Total # of netCDF dimensions created */ typedef struct cdfvar { /* CDF variable structure */ char name[CDF_VAR_NAME_LEN256+1]; long datatype; long numElements; /* string length for CDF_CHAR, 1 otherwise */ long dimensionality; /* variable dimensionality */ long dimSizes[CDF_MAX_DIMS]; /* variable dimension sizes */ long recVariance; /* record variance */ long numRecs; /* # of records this variable contains */ } CDFvar; /**************************************************************************** * Arrays to hold the CDF-to-netCDF mapping information that are loaded * from the default or user-define mapping file. ****************************************************************************/ char netcdfAttrNames[MAX_ATTRS][NC_MAX_NAME]; char cdfAttrNames[MAX_ATTRS][CDF_ATTR_NAME_LEN256+1]; char comments[MAX_ATTRS][CDF_ATTR_NAME_LEN256+1]; int totAttrsInMappingFile; /* # of attributes in the mapping file */ char mappingFile[CDF_PATHNAME_LEN]; /* Mapping file name */ int DEBUG = FALSE; /************************** Function prototypes **************************/ int endsWith(char *, char *); char * strlaststr(char *, char *); void get_cdf_attribute(long, long, long, int); void get_cdf_attr_data(char *, long, long, long, int); char * cdf_str_datatype (long); char * NC_datatype (nc_type); nc_type get_netcdf_datatype (long); void usage(); CDFid cdf_open(char *); void read_cdf_file_info(); void get_zVariables(long *, int); int create_netcdf_dimensions_attribute (int *); void create_netcdf_dimensions_variable (CDFvar, long, int *, int *); int create_netcdf_variable (CDFvar, long, int); void get_cdf_variable_data (long, CDFvar, long); void read_cdf_variable_data (long, long, long, long, long [], void *); void removeFilepath(); void handle_netcdf_error (int); void memory_error(char *, char *); void cdf_status_handler (CDFstatus, char *); void insufficient_memory(); /* used for debug */ char * getNextArgument (int, char *[], int); void parseCmdLine (int, char *[]); void errorMsg (char *); void map_CDF_attr_to_netCDF (char *, char *); void breakdown_DIMENSIONS_entry (char *, char **); #define AMDA #ifdef AMDA #include "tools.h" char start_time [DD_TIME_STRING_LEN+1]; char stop_time [DD_TIME_STRING_LEN+1]; #endif /**************************************************************************** NOTE: CDF has the following features that are not supported by netCDF: - CDF_EPOCH datatype (8-byte real number) that is used to store time values referenced from a particular epoch that is 01-Jan-0000 00:00:00.000. CDF_EPOCH values are the number of milliseconds since the epoch described above. - CDF_EPOCH16 datatype (16-byte real number) that is used to store time values referenced from a particular epoch that is 01-Jan-0000 00:00:00.000.000.000.000. CDF_EPOCH16 values are the number of milliseconds since the epoch described above. - CDF global attribute (not variable attribute) can have multiple attribute entries and each entry can have a different datatype. *****************************************************************************/ int main(int argc, char *argv[]) { FILE *inFile; /* Pointer to the CDF-to-netCDF mapping file */ char rec[MAX_REC_LENGTH]; /* CDF-to-netCDF mapping record */ /************************/ /* netCDF declaration */ /************************/ int status, /* netCDF status code */ dummy, i; char *ptr, fileName[CDF_PATHNAME_LEN]; /**********************/ /* CDF declaration */ /**********************/ CDFstatus cstatus; /* CDF status code */ long attrId; /* CDF attribute ID */ long varId; long *varsToGet; int nVarsToGet; if (argc <= 1) usage(); /* CDF input file name not specified */ else { strcpy(fileName, argv[1]); /* Get the input file name */ strcpy(mappingFile, "UNSPECIFIED"); parseCmdLine(argc, argv); if (strcmp(mappingFile, fileName) == 0) errorMsg("** Error - either input file or mapping file is missing"); if (strcmp(mappingFile,"UNSPECIFIED") == 0) strcpy(mappingFile, DEFAULT_MAPPING_FILE); } #ifdef AMDA status = check_version(); #endif /***********************************************/ /* Load the CDF-to-netCDF mapping information */ /***********************************************/ if ((inFile = fopen(mappingFile, "r")) == NULL) { printf ("WARNING : Cannot open file: %s **\n", mappingFile); totAttrsInMappingFile = 0; } else { totAttrsInMappingFile = 0; while (fgets(rec, MAX_REC_LENGTH, inFile) != NULL) { rec[strlen(rec)-1] = '\0'; /* Remove the newline character */ /* Process the mapping record if it's not a comment */ if (rec[0] != '#' && rec[0] != ' ' && strlen(rec) > 0) { sscanf(rec, "%s %s", netcdfAttrNames[totAttrsInMappingFile], cdfAttrNames[totAttrsInMappingFile]); ptr = (char *) strstr(rec, "//"); if (ptr != NULL) { ptr += 3; strcpy (comments[totAttrsInMappingFile], ptr); } if (DEBUG) printf("%s %s %s\n", netcdfAttrNames[totAttrsInMappingFile], cdfAttrNames[totAttrsInMappingFile], comments[totAttrsInMappingFile]); totAttrsInMappingFile++; } } } /*********************************************************** * Process the CDF information and create a netCDF file ***********************************************************/ /* printf ("\nInput file name: %s\n", fileName); */ id = cdf_open (fileName); /* Remove the file path if it exists (/home/mydata.cdf => mydata.cdf). */ removeFilepath(fileName); if (endsWith(fileName,".cdf")) { /* Strip off the .cdf file extension. */ ptr = (char *) strlaststr(fileName, ".cdf"); if (ptr != NULL) *ptr = '\0'; } strcat(fileName, ".nc"); status = nc_create(fileName, NC_CLOBBER, &ncid); if (status != NC_NOERR) handle_netcdf_error(status); printf ("Output file name: %s\n", fileName); /*********************************************************************** * Get the number of dimensions, number of variables, number of global * attributes. * * Note that the information retrieved from read_cdf_file_info are stored * into the global variables defined at the top. ***********************************************************************/ read_cdf_file_info (); if (DEBUG) printf ("nAttrs=%ld, nZvars=%ld\n", nAttrs, nZvars); /* Get the CDF global attributes and create netCDF global attributes. */ if (DEBUG) printf ("Global attributes:\n"); dummy = -1; for (attrId = 0; attrId < nAttrs; attrId++) get_cdf_attribute(attrId, GLOBAL_SCOPE, (long) dummy, dummy); /* Write the placeholder attributes. */ for (i=0; i < totAttrsInMappingFile; i++) { if (strcmp(cdfAttrNames[i],"*") == 0) { status = nc_put_att_text (ncid, NC_GLOBAL, /* vavriable ID */ netcdfAttrNames[i], /* Attribute name */ strlen(comments[i]), /* # of attr values */ comments[i]); } } /* Process CDF variables and create netCDF variables */ if (argc > 2) { varsToGet = (long *) malloc(sizeof(long)*(argc-2)); for (i = 2; i < argc; i++ ) { status = CDFlib ( GET_, zVAR_NUMBER_, argv[i], &varId); varsToGet[i-2] = varId; } nVarsToGet = argc-2; } else { varsToGet = (long *) malloc(sizeof(long)*nZvars); for (i = 0; i < nZvars; i++) varsToGet[i] = (long)i; nVarsToGet = nZvars; } printf("NVARS %d\n",nVarsToGet); if (nZvars > 0) get_zVariables(varsToGet, nVarsToGet); /* Close the netCDF and CDF files */ cstatus = CDFlib (CLOSE_, CDF_, NULL_); if (cstatus != CDF_OK) cdf_status_handler (cstatus, "CLOSE_, CDF_"); status = nc_close(ncid); if (status != NC_NOERR) handle_netcdf_error(status); } /*---------------------------------------------------------------------------- * TRUE if s1 ends with s2. Otherwise, FALSE is returned. *---------------------------------------------------------------------------*/ int endsWith (char *s1, char *s2) { int i; char *ps1, *ps2; if (strlen(s2) > strlen(s1)) return FALSE; ps1 = s1 + strlen(s1) - strlen(s2); ps2 = s2; for (i=0; i < strlen(s2); i++) if (*(ps1++) != *(ps2++)) return FALSE; return TRUE; } /*--------------------------------------------------------------------------------- * Find the last occurence of s2 in s1. If s21 is not found, s1 is returned. *--------------------------------------------------------------------------------*/ char * strlaststr (char *s1, char *s2) { char *sc2, *psc1, *ps1; if (*s2 == '\0') return((char *)s1); ps1 = s1 + strlen(s1); while(ps1 != s1) { --ps1; for (psc1 = ps1, sc2 = s2; ; ) if (*(psc1++) != *(sc2++)) break; else if (*sc2 == '\0') return ((char *)ps1); } return ((char *)NULL); } /*-------------------------------------------------------------------------- * This routine opens a CDF file *-------------------------------------------------------------------------*/ CDFid cdf_open (char *fileName) { CDFstatus status; CDFid id; char msg[500]; status = CDFlib (OPEN_, CDF_, fileName, /* in - file name to be opened */ &id, /* out - CDF file ID */ NULL_); if (status != CDF_OK) { strcpy(msg, "OPEN_, CDF_, "); strcat(msg, fileName); cdf_status_handler (status, msg); } return id; } /*--------------------------------------------------------------------------- * This routine retrievs the following information: * * nAttr - number of attributes (including global and variable) * nZvars - number of zVariables * * CDF file can have both rVariables (old style) and zVariables (new style) * simultaneously. zVariable is a superset of rVariable, and it is a lot * more efficient and offers all the functionality a rVariable offers and * more. Treat all CDF variables as zVariables. *--------------------------------------------------------------------------*/ void read_cdf_file_info () { CDFstatus status; status = CDFlib (SELECT_, CDF_zMODE_, zMODEon2, GET_, CDF_NUMATTRS_, &nAttrs, CDF_NUMzVARS_, &nZvars, NULL_); if (status != CDF_OK) cdf_status_handler (status, "GET_, CDF_FILEINFO_"); } /*---------------------------------------------------------------------------- * This routine retrieves the CDF attribute (global or variable) name * and its data for the given CDF attribute ID. *---------------------------------------------------------------------------*/ void get_cdf_attribute(long attrNum, /* in - CDF attribute number/id */ long scope, /* in - CDF attribute scope */ long cdfVarId, /* in - CDF variable number/id */ int netcdfVarId) /* in - netCDF variable ID */ { int ncstatus, i, len; long status, numEntries, datatype, attrScope, entryNum, numElements; nc_type ncDatatype; /* netCDF datatype */ char *cPtr, attrName[CDF_ATTR_NAME_LEN256+1], mappedAttrName[CDF_ATTR_NAME_LEN256+1]; status = CDFlib (SELECT_, ATTR_, attrNum, GET_, ATTR_NAME_, attrName, ATTR_SCOPE_, &attrScope, NULL_); if (status != CDF_OK) cdf_status_handler (status, "SELECT_, ATTR_"); /****************************************************************/ /* If the attribute scope is not the requested attribute scope */ /* (VARIABLE_SCOPE or GLOBAL_SCOPE), do not process the current */ /* attribute. */ /****************************************************************/ if (attrScope != scope) return; if (strcmp(attrName, "DIMENSIONS_G") == 0 || strcmp(attrName, "DIMENSIONS_V") == 0) return; map_CDF_attr_to_netCDF(attrName, mappedAttrName); strcpy(attrName, mappedAttrName); if (attrScope == GLOBAL_SCOPE) { status = CDFlib (GET_, ATTR_NUMgENTRIES_, &numEntries, NULL_); if (status != CDF_OK) cdf_status_handler (status, "GET_, ATTR_NUMgENTRIES_"); if (DEBUG) printf ("\t%s", attrName); /********************************************************************* * While the CDF global attribute can have multiple entries of * of different datatypes, the CDF variable attribute can only have * one attribute entry. netCDF doesn't allow more than 1 attribute * entry - handle this case ********************************************************************/ for (entryNum=0; entryNum < numEntries; entryNum++) { if (entryNum > 0) /* Attribute has more than 1 entry */ sprintf (attrName, "%s_%ld", mappedAttrName, entryNum); status = CDFlib (SELECT_, gENTRY_, entryNum, GET_, gENTRY_DATATYPE_, &datatype, gENTRY_NUMELEMS_, &numElements, NULL_); if (status == NO_SUCH_ENTRY) return; if (status != CDF_OK) cdf_status_handler(status,"GET_ATTR_INFO_"); get_cdf_attr_data (attrName, gENTRY_DATA_, datatype, numElements, netcdfVarId); } } else { /********************************************************************* * IMPORTANT NOTE: * For the variable attribute, entry number is the variable ID. *********************************************************************/ status = CDFlib (SELECT_, zENTRY_, cdfVarId, GET_, zENTRY_DATATYPE_, &datatype, zENTRY_NUMELEMS_, &numElements, NULL_); /******************************************************************/ /* If there's no attribute entry for the current attribute number */ /* selected, process the next attribute. */ /******************************************************************/ if (status == NO_SUCH_ENTRY) return; if (status != CDF_OK) cdf_status_handler (status,"GET_ATTR_INFO_"); if (DEBUG) printf ("\t%s", attrName); if (attrName[strlen(attrName)-1] == (char) '_') { char name2[CDF_ATTR_NAME_LEN256+1]; strcpy(name2, attrName); name2[strlen(name2)-1] = (char) '\0'; status = CDFlib (GET_, ATTR_NUMBER_, name2, &attrNum, NULL_); if (status == CDF_OK) { strcpy(attrName, name2); map_CDF_attr_to_netCDF(attrName, mappedAttrName); strcpy(attrName, mappedAttrName); } } get_cdf_attr_data (attrName, zENTRY_DATA_, datatype, numElements, netcdfVarId); } } /*-------------------------------------------------------------------------- * This routine retrieves the CDF attribute data (a.k.a. attribute entries) * and write its values to the target netCDF file. *--------------------------------------------------------------------------*/ void get_cdf_attr_data (char *attrName, /* in - attribute name */ long entryData, /* in - type of attr entry data */ long datatype, /* in - attribute datatype */ long numElements, /* in - # of attribute values */ int netcdfVarId) /* in - netCDF variable ID */ { char entryDataType[20], msg[100], epString[EPOCH4_STRING_LEN+1], ep16String[EPOCH16_4_STRING_LEN+1], mappedAttrName[CDF_ATTR_NAME_LEN256+1], tt2000String[TT2000_3_STRING_LEN+1]; double epoch16[2]; nc_type ncDatatype; /* netCDF datatype */ int nc_status, /* netCDF status code */ varId; /* netCDF variable ID */ long status; /* CDF status code */ char *cPtr; signed char *scPtr; unsigned char *uscPtr; short *sPtr; unsigned short *usPtr; int *iPtr, i; unsigned int *uiPtr; long long *jPtr, aLonglong; float *fPtr; double *dPtr; /************************************************* * entryData has one of following values: * * gENTRY_DATA_ - global attribute entry * rENTRY_DATA_ - rVariable attribute entry * zENTRY_DATA_ - zVariable attribute entry *************************************************/ if (entryData == gENTRY_DATA_) { varId = NC_GLOBAL; strcpy(entryDataType, "gENTRY_DATA_"); } else { varId = netcdfVarId; strcpy(entryDataType, "zENTRY_DATA_"); } strcpy (msg, "get_cdf_attr_data, GET_, "); strcat (msg, entryDataType); strcat (msg, cdf_str_datatype(datatype)); /* Map the CDF datatype to an appropriate netCDF datatype. */ ncDatatype = get_netcdf_datatype (datatype); /* Remove trailing blank spaces if there are any */ for (i=strlen(attrName)-1; i >= 0; i--) { if (attrName[i] != ' ') { attrName[i+1] = '\0'; break; } } /* Replace blanks space(s) with underscore(s). */ for (i=0; i < strlen(attrName); i++) { if (attrName[i] == ' ') attrName[i] = '_'; } switch (datatype) { case CDF_CHAR: case CDF_UCHAR: cPtr = (char *) malloc(numElements * sizeof(char) + 1); if (cPtr == NULL) memory_error("get_cdf_attr_data", "NC_CHAR"); status = CDFlib (GET_, entryData, cPtr, NULL_); if (status != CDF_OK) cdf_status_handler (status, msg); *(cPtr+numElements) = '\0'; /* End of string mark */ if (DEBUG) printf (" = \"%s\"", cPtr); nc_status = nc_put_att_text(ncid, varId, attrName, numElements, cPtr); if (nc_status != NC_NOERR) handle_netcdf_error(nc_status); free(cPtr); break; case CDF_BYTE: case CDF_INT1: scPtr = (signed char *) malloc (sizeof(signed char) * numElements); if (scPtr == NULL) memory_error("get_cdf_attr_data", "NC_BYTE"); status = CDFlib (GET_, entryData, scPtr, NULL_); if (status != CDF_OK) cdf_status_handler (status, msg); if (DEBUG) { printf (" = "); for (i=0; i < numElements; i++) { if (i > 0) printf (", "); printf ("%d", *(scPtr+i)); } } nc_status = nc_put_att_schar(ncid, varId, attrName, ncDatatype, numElements, scPtr); if (nc_status != NC_NOERR) handle_netcdf_error(nc_status); free (scPtr); break; case CDF_UINT1: uscPtr = (unsigned char *) malloc (sizeof(unsigned char) * numElements); if (uscPtr == NULL) memory_error("get_cdf_attr_data", "NC_BYTE"); sPtr = (short *) malloc (sizeof(short) * numElements); if (sPtr == NULL) memory_error("get_cdf_attr_data", "NC_SHORT"); status = CDFlib (GET_, entryData, uscPtr, NULL_); if (status != CDF_OK) cdf_status_handler (status, msg); if (DEBUG) { printf (" = "); for (i=0; i < numElements; i++) { if (i > 0) printf (", "); printf ("%d", *(uscPtr+i)); } } for (i = 0; i < numElements; ++i) { *(sPtr+i) = (short) *(uscPtr+i); } nc_status = nc_put_att_short(ncid, varId, attrName, ncDatatype, numElements, sPtr); if (nc_status != NC_NOERR) handle_netcdf_error(nc_status); free (uscPtr); free (sPtr); break; case CDF_INT2: sPtr = (short *) malloc (sizeof(short) * numElements); if (sPtr == NULL) memory_error("get_cdf_attr_data", "NC_SHORT"); status = CDFlib (GET_, entryData, sPtr, NULL_); if (status != CDF_OK) cdf_status_handler (status, msg); if (DEBUG) { printf (" = "); for (i=0; i < numElements; i++) { if (i > 0) printf (", "); printf ("%hd", *(sPtr+i)); } } nc_status = nc_put_att_short(ncid, varId, attrName, ncDatatype, numElements, sPtr); if (nc_status != NC_NOERR) handle_netcdf_error(nc_status); free (sPtr); break; case CDF_UINT2: usPtr = (unsigned short *) malloc (sizeof(unsigned short) * numElements); if (usPtr == NULL) memory_error("get_cdf_attr_data", "NC_SHORT"); iPtr = (int *) malloc (sizeof(int) * numElements); if (iPtr == NULL) memory_error("get_cdf_attr_data", "NC_INT"); status = CDFlib (GET_, entryData, usPtr, NULL_); if (status != CDF_OK) cdf_status_handler (status, msg); if (DEBUG) { printf (" = "); for (i=0; i < numElements; i++) { if (i > 0) printf (", "); printf ("%hu", *(usPtr+i)); } } for (i = 0; i < numElements; ++i) { *(iPtr+i) = (int) *(usPtr+i); } nc_status = nc_put_att_int(ncid, varId, attrName, ncDatatype, numElements, iPtr); if (nc_status != NC_NOERR) handle_netcdf_error(nc_status); free (usPtr); free (iPtr); break; case CDF_INT4: iPtr = (int *) malloc (sizeof(int) * numElements); if (iPtr == NULL) memory_error("get_cdf_attr_data", "NC_INT"); status = CDFlib (GET_, entryData, iPtr, NULL_); if (status != CDF_OK) cdf_status_handler (status, msg); if (DEBUG) { printf (" = "); for (i=0; i < numElements; i++) { if (i > 0) printf (", "); printf ("%d", *(iPtr+i)); } } nc_status = nc_put_att_int(ncid, varId, attrName, ncDatatype, numElements, iPtr); if (nc_status != NC_NOERR) handle_netcdf_error(nc_status); free (iPtr); break; case CDF_UINT4: uiPtr = (unsigned int *) malloc (sizeof(unsigned int) * numElements); if (uiPtr == NULL) memory_error("get_cdf_attr_data", "NC_INT"); dPtr = (double *) malloc (sizeof(double) * numElements); if (dPtr == NULL) memory_error("get_cdf_attr_data", "NC_DOUBLE"); status = CDFlib (GET_, entryData, uiPtr, NULL_); if (status != CDF_OK) cdf_status_handler (status, msg); if (DEBUG) { printf (" = "); for (i=0; i < numElements; i++) { if (i > 0) printf (", "); printf ("%ud", *(uiPtr+i)); } } for (i = 0; i < numElements; ++i) { *(dPtr+i) = (double) *(uiPtr+i); } nc_status = nc_put_att_double(ncid, varId, attrName, ncDatatype, numElements, dPtr); if (nc_status != NC_NOERR) handle_netcdf_error(nc_status); free (uiPtr); free (dPtr); break; case CDF_INT8: jPtr = (long long *) malloc (sizeof(long long) * numElements); if (jPtr == NULL) memory_error("get_cdf_attr_data", "NC_INT64"); dPtr = (double *) malloc (sizeof(double) * numElements); if (dPtr == NULL) memory_error("get_cdf_attr_data", "NC_DOUBLE"); status = CDFlib (GET_, entryData, jPtr, NULL_); if (status != CDF_OK) cdf_status_handler (status, msg); if (DEBUG) { printf (" = "); for (i=0; i < numElements; i++) { if (i > 0) printf (", "); printf ("%lld", *(jPtr+i)); } } for (i = 0; i < numElements; ++i) { *(dPtr+i) = (double) *(jPtr+i); } nc_status = nc_put_att_double(ncid, varId, attrName, ncDatatype, numElements, dPtr); if (nc_status != NC_NOERR) handle_netcdf_error(nc_status); free (jPtr); free (dPtr); break; case CDF_FLOAT: case CDF_REAL4: fPtr = (float *) malloc (sizeof(float) * numElements); if (fPtr == NULL) memory_error("get_cdf_attr_data", "NC_FLOAT"); status = CDFlib (GET_, entryData, fPtr, NULL_); if (status != CDF_OK) cdf_status_handler (status, msg); if (DEBUG) { printf (" = "); for (i=0; i < numElements; i++) { if (i > 0) printf (", "); printf ("%g", *(fPtr+i)); } } nc_status = nc_put_att_float(ncid, varId, attrName, ncDatatype, numElements, fPtr); if (nc_status != NC_NOERR) handle_netcdf_error(nc_status); free (fPtr); break; case CDF_DOUBLE: case CDF_REAL8: dPtr = (double *) malloc (sizeof(double) * numElements); if (dPtr == NULL) memory_error("get_cdf_attr_data", "NC_DOUBLE"); status = CDFlib (GET_, entryData, dPtr, NULL_); if (status != CDF_OK) cdf_status_handler (status, msg); if (DEBUG) { printf (" = "); for (i=0; i < numElements; i++) { if (i > 0) printf (", "); printf ("%g", *(dPtr+i)); } } nc_status = nc_put_att_double(ncid, varId, attrName, ncDatatype, numElements, dPtr); if (nc_status != NC_NOERR) handle_netcdf_error(nc_status); free (dPtr); break; case CDF_EPOCH: /* 8-byte real number */ dPtr = (double *) malloc (sizeof(double) * numElements); if (dPtr == NULL) memory_error("get_cdf_attr_data", "CDF_EPOCH"); status = CDFlib (GET_, entryData, dPtr, NULL_); if (status != CDF_OK) cdf_status_handler (status, msg); if (DEBUG) printf (" = "); for (i=0; i < numElements; i++) { encodeEPOCH4 (* (dPtr+i), epString); nc_status = nc_put_att_text(ncid, varId, attrName, EPOCH4_STRING_LEN, epString); if (nc_status != NC_NOERR) handle_netcdf_error(nc_status); if (DEBUG) { if (i > 0) printf (", "); printf ("%s", epString); if (i == (numElements -1)) printf ("\n"); } } free (dPtr); break; case CDF_EPOCH16: /* 16-byte real number */ dPtr = (double *) malloc (sizeof(double) * numElements * 2); if (dPtr == NULL) memory_error("get_cdf_attr_data", "CDF_EPOCH16"); status = CDFlib (GET_, entryData, dPtr, NULL_); if (status != CDF_OK) cdf_status_handler (status, msg); if (DEBUG) printf (" = "); for (i=0; i < numElements; i++) { epoch16[0] = *(dPtr+i*2); epoch16[1] = *(dPtr+i*2+1); encodeEPOCH16_4 (epoch16, ep16String); nc_status = nc_put_att_text(ncid, varId, attrName, strlen(ep16String), ep16String); if (nc_status != NC_NOERR) handle_netcdf_error(nc_status); if (DEBUG) { if (i > 0) printf (", "); printf ("%s", ep16String); if (i == (numElements -1)) printf ("\n"); } } free (dPtr); break; case CDF_TIME_TT2000: /* 8-byte integer number */ jPtr = (long long *) malloc (sizeof(long long) * numElements); if (jPtr == NULL) memory_error("get_cdf_attr_data", "CDF_TIME_TT2000"); status = CDFlib (GET_, entryData, jPtr, NULL_); if (status != CDF_OK) cdf_status_handler (status, msg); if (DEBUG) printf (" = "); for (i=0; i < numElements; i++) { encodeTT2000 (*(jPtr+i), tt2000String); nc_status = nc_put_att_text(ncid, varId, attrName, TT2000_3_STRING_LEN, tt2000String); if (nc_status != NC_NOERR) handle_netcdf_error(nc_status); if (DEBUG) { if (i > 0) printf (", "); printf ("%s", tt2000String); if (i == (numElements -1)) printf ("\n"); } } free (jPtr); break; default: printf ("** Error in get_cdf_attribute: bad data type"); } if (DEBUG) printf (" ;\n"); } /*-------------------------------------------------------------------------- * Get the zVariables in the CDF file. *--------------------------------------------------------------------------*/ void get_zVariables(long *vars, int nvars) { CDFstatus status; int i, ncstatus, createUnlimitedDim, unlimitedDimId, attrId, netcdfVarId, bypass; char netcdfDimName[NC_MAX_NAME+1]; /* netCDF dimension name */ long holdDim, holdDim0; long varId, ncVarId; CDFvar var; if (DEBUG) printf ("\n"); createUnlimitedDim = TRUE; bypass = FALSE; for (i = 0; i < nvars; i++) { varId = vars[i]; ncVarId = (long)i; status = CDFlib (SELECT_,zVAR_, varId, GET_, zVAR_NAME_, var.name, zVAR_DATATYPE_, &var.datatype, zVAR_NUMELEMS_, &var.numElements, zVAR_NUMDIMS_, &var.dimensionality, zVAR_DIMSIZES_, var.dimSizes, zVAR_NUMRECS_, &var.numRecs, zVAR_RECVARY_, &var.recVariance, NULL_); if (status != CDF_OK) cdf_status_handler (status, "GET_, zVARS_"); if (DEBUG) { printf ("var name = %s, %s/%ld, %ld:[", var.name, cdf_str_datatype(var.datatype), var.numElements, var.dimensionality); for (i=0; i < var.dimensionality; i++) { if (i > 0) printf (","); printf ("%ld", var.dimSizes[i]); } printf("], numRecs = %ld\n", var.numRecs); } if (varId == 0) bypass = create_netcdf_dimensions_attribute (&unlimitedDimId); if (!bypass) create_netcdf_dimensions_variable (var, ncVarId, &createUnlimitedDim, &unlimitedDimId); netcdfVarId = create_netcdf_variable (var, ncVarId, unlimitedDimId); /* Leave the define mode before adding data */ ncstatus = nc_enddef(ncid); if (ncstatus != NC_NOERR) handle_netcdf_error(ncstatus); get_cdf_variable_data (varId, var, ncVarId); /* Enter the define mode before writing netCDF variable attributes */ /* and creating a variable. */ ncstatus = nc_redef(ncid); if (ncstatus != NC_NOERR) handle_netcdf_error(ncstatus); /* Get the variable attributes */ for (attrId = 0; attrId < nAttrs; attrId++) get_cdf_attribute(attrId, VARIABLE_SCOPE, varId, netcdfVarId); } #ifdef AMDA if (set_file_time_coverage() == -1) { printf ("ERROR : unable to compute file time coverage\n"); } if (rename_time_variable () == -1) { printf ("ERROR : uname to rename time variable\n"); } #endif } /*-------------------------------------------------------------------------- * This routine creates all netCDF dimensions from a global attribute if * such attribute exists (likely the CDF is created by netcdf-to-cdf * converter). It returns TRUE if dimensions are creaated, FLASE otherwise. *--------------------------------------------------------------------------*/ int create_netcdf_dimensions_attribute (int *unlimitedDimId) { int status, /* netCDF status code */ i, id, value, len; long numElems, numEntries; char netcdfDimName[NC_MAX_NAME+1]; /* netCDF dimension name */ char valueStr[20+1]; char *ptr, entry[NC_MAX_NAME + 20 + 1]; CDFstatus statusC; statusC = CDFlib (SELECT_, ATTR_NAME_, "DIMENSIONS_G", GET_, ATTR_NUMgENTRIES_, &numEntries, NULL_); if (statusC != CDF_OK) return FALSE; /* A CDF file that was created by netCDF-to-cdf */ for (i = 0; i < (int) numEntries; ++i) { statusC = CDFlib (SELECT_, ATTR_NAME_, "DIMENSIONS_G", gENTRY_, (long) i, GET_, gENTRY_DATA_, entry, gENTRY_NUMELEMS_, &numElems, NULL_); if (statusC != CDF_OK) continue; entry[numElems] = (char) '\0'; ptr = strstr(entry, "="); if (ptr == NULL) continue; len = (int) (ptr - entry); strncpy(netcdfDimName, entry, len); strcpy(valueStr, ptr+1); netcdfDimName[len] = (char) '\0'; if (strcmp(valueStr, "UNLIMITED") == 0) { status = nc_def_dim(ncid, /* in */ netcdfDimName, /* in */ NC_UNLIMITED, /* in */ unlimitedDimId); /* out */ } else { if (sscanf(valueStr, "%d", &value) != 1) continue; status = nc_def_dim(ncid, /* in */ netcdfDimName, /* in */ value, /* in */ &id); /* out */ } if (status != NC_NOERR) handle_netcdf_error(status); } return TRUE; } /*-------------------------------------------------------------------------- * This routine creates a netCDF dimension(s) from a variable. *--------------------------------------------------------------------------*/ void create_netcdf_dimensions_variable (CDFvar var, long varNum, int *createUnlimitedDim, int *unlimitedDimId) { int status, /* netCDF status code */ i, j, dimensionCreated, id; long dimensionality; char netcdfDimName[NC_MAX_NAME+1]; /* netCDF dimension name */ CDFstatus statusC; dimensionality = var.dimensionality; if (var.datatype == CDF_CHAR) { var.dimSizes[dimensionality] = var.numElements; dimensionality++; } else if (var.datatype == CDF_EPOCH) { var.dimSizes[dimensionality] = DD_TIME_STRING_LEN; dimensionality++; } else if (var.datatype == CDF_EPOCH16) { var.dimSizes[dimensionality] = DD_TIME_STRING_LEN; dimensionality++; } else if (var.datatype == CDF_TIME_TT2000) { var.dimSizes[dimensionality] = DD_TIME_STRING_LEN; dimensionality++; } if (*createUnlimitedDim) { if (var.recVariance == VARY) { status = nc_def_dim(ncid, "Time", NC_UNLIMITED,unlimitedDimId); if (status != NC_NOERR) handle_netcdf_error(status); *createUnlimitedDim = FALSE; } } for (i=0; i < dimensionality; i++) { dimensionCreated = FALSE; for (j=0; j < totNCdims; j++) { if (ncDims[j].size == var.dimSizes[i]) { dimensionCreated = TRUE; break; } } if (!dimensionCreated && var.dimSizes[i] > 1) { ncDims[totNCdims].size = var.dimSizes[i]; sprintf (netcdfDimName, "dim%d", totNCdims); strcpy(ncDims[totNCdims].name, netcdfDimName); status = nc_def_dim(ncid, /* in */ ncDims[totNCdims].name, /* in */ ncDims[totNCdims].size, /* in */ &ncDims[totNCdims].id); /* out */ if (status != NC_NOERR) handle_netcdf_error(status); totNCdims++; } } } /*-------------------------------------------------------------------------- * This routine creates a netCDF variable. *--------------------------------------------------------------------------*/ int create_netcdf_variable (CDFvar var, /* in - CDF variable */ long varNum, /* in - CDF variable id */ int unlimitedDimId) /* in - unlimited dim ID */ { int status, /* netCDF status code */ i, j, k, id, varId, /* netCDF variable ID */ nc_dimensionality, dimensionality, /* netCDF dimensionality */ dims[NC_MAX_DIMS]; /* netCDF dimensions */ nc_type datatype; char *entry; char **dimStrings; int count = 0; long numElems; CDFstatus statusC; dimensionality = var.dimensionality; datatype = get_netcdf_datatype (var.datatype); /********************************************************************* * While the string value is treated as 0-d in CDF, it is treated as * 1-D in netCDF. *********************************************************************/ if (var.datatype == CDF_CHAR) { var.dimSizes[dimensionality] = var.numElements; dimensionality++; } /********************************************************************* * In CDF, CDF_EPOCH, CDF_EPOCH16 and CDF_TIME_TT2000 are used to * store a date and time value into a 8-byte real, 16-byte real or * 8-byte integer value, respectively. Since netCDF * doesn't support EPOCH, the CDF EPOCH variable needs to be translated * as a string value. *********************************************************************/ else if (var.datatype == CDF_EPOCH) { var.dimSizes[dimensionality] = DD_TIME_STRING_LEN; dimensionality++; } else if (var.datatype == CDF_EPOCH16) { var.dimSizes[dimensionality] = DD_TIME_STRING_LEN; dimensionality++; } else if (var.datatype == CDF_TIME_TT2000) { var.dimSizes[dimensionality] = DD_TIME_STRING_LEN; dimensionality++; } /************************************************************************ * If CDF's record variance is true, then the netCDF's first dimension * reflects the record number. ************************************************************************/ k = 0; if (var.recVariance == VARY) { dims[k++] = unlimitedDimId; dimensionality++; } entry = (char *) malloc ((size_t) (dimensionality+1) * NC_MAX_NAME + dimensionality + 1 ); statusC = CDFlib (SELECT_, ATTR_NAME_, "DIMENSIONS_V", zENTRY_, varNum, GET_, zENTRY_DATA_, entry, zENTRY_NUMELEMS_, &numElems, NULL_); if (statusC == CDF_OK) { /* A CDF converted from netCDF-to-cdf. */ entry[numElems] = (char) '\0'; for (i = 0; i < strlen(entry); ++i) if (entry[i] == (char) ',') ++ count; ++count; dimStrings = (char **) malloc (sizeof(char *) * count); for (i = 0; i < count; ++i) { dimStrings[i] = (char *) malloc(NC_MAX_NAME + 1); } breakdown_DIMENSIONS_entry(entry, dimStrings); k = 0; for (j = 0; j < count; ++j) { status = nc_inq_dimid(ncid, dimStrings[j], &id); if (status != NC_NOERR) handle_netcdf_error(status); dims[k++] = id; } for (i = 0; i < count; ++i) free (dimStrings[i]); free (dimStrings); } else { for (i=0; i < dimensionality; i++) { for (j=0; j < totNCdims; j++) { if (ncDims[j].size == var.dimSizes[i]) { dims[k++] = ncDims[j].id; break; } } } } free (entry); /* Remove trailing blank spaces if there are any */ for (i=strlen(var.name)-1; i >= 0; i--) { if (var.name[i] != ' ') { var.name[i+1] = '\0'; break; } } /* Replace blank space(s) with underscore(s). */ for (i=0; i < strlen(var.name); i++) { if (var.name[i] == ' ') var.name[i] = '_'; } /* Exclude "false" dimension */ nc_dimensionality = dimensionality; // for (i=0; i < dimensionality; i++) { // if ( var.dimSizes[i] == 1 ) { // nc_dimensionality--; // j = i; // break; // } // } /* Create a netCDF variable. */ status = nc_def_var(ncid, var.name, datatype, nc_dimensionality, dims, &varId); if (status != NC_NOERR) handle_netcdf_error(status); return varId; } /*-------------------------------------------------------------------------- * Get the CDF variable data and write the data just read into the * netCDF variable created in create_netcdf_variable. *--------------------------------------------------------------------------*/ void get_cdf_variable_data (long varId, /* in - variable ID/number */ CDFvar var, /* in - CDF variable structure */ long ncVarId) /* in - netCDF variable ID/number */ { CDFstatus status; /* CDF status code */ int ncstatus; /* netCDF status code */ char epString[EPOCH4_STRING_LEN+1]; char ep16String[EPOCH16_4_STRING_LEN+1]; char tt2000String[TT2000_3_STRING_LEN+1]; double epoch16[2]; size_t start[NC_MAX_DIMS], /* index for where to read first */ count[NC_MAX_DIMS]; /* # of values to read */ int i, j, k, divide, dimensionality, numValues; /* # of values on each record */ char * ptr; char *cPtr; signed char *scPtr; unsigned char *ucPtr; short *sPtr; unsigned short *usPtr; int *iPtr; unsigned int *uiPtr; long long *jPtr, aLonglong; float *fPtr; double *dPtr; long recNo, totRecs, /* total # of records to read */ numRecsLeftToRead, numRecs; /* # of records to read and write at a time */ j = 0; start[0] = 0; numValues = 1; /* # of values on each CDF record */ if (var.recVariance == VARY) { /* Treat it as a netCDF record variable */ start[j] = 0; /* start record # */ count[j++] = var.numRecs; /* # of records to write */ } dimensionality = var.dimensionality; if (var.datatype == CDF_CHAR) { var.dimSizes[dimensionality] = var.numElements; dimensionality++; } /********************************************************************* * In CDF, CDF_EPOCH and CDF_EPOCH16 are used to store a date and time * value into a 8-byte and 16-byte real value, respectively. Since netCDF * doesn't support EPOCH, the CDF EPOCH variable needs to be translated * as a string value. Added newer 8-byte integer CDF_TIME_TT2000 data. *********************************************************************/ else if (var.datatype == CDF_EPOCH) { var.dimSizes[dimensionality] = DD_TIME_STRING_LEN; dimensionality++; } else if (var.datatype == CDF_EPOCH16) { var.dimSizes[dimensionality] = DD_TIME_STRING_LEN; dimensionality++; } else if (var.datatype == CDF_TIME_TT2000) { var.dimSizes[dimensionality] = DD_TIME_STRING_LEN; dimensionality++; } for (i=0; i < dimensionality; i++) { start[j] = 0; if (var.dimSizes[i] > 1) count[j++] = var.dimSizes[i]; numValues *= var.dimSizes[i]; } if (var.datatype == CDF_EPOCH) numValues /= DD_TIME_STRING_LEN; else if (var.datatype == CDF_EPOCH16) numValues /= DD_TIME_STRING_LEN; else if (var.datatype == CDF_TIME_TT2000) numValues /= DD_TIME_STRING_LEN; totRecs = var.numRecs; /* total # of records for this var */ numRecsLeftToRead = var.numRecs; while (numRecsLeftToRead > 0) { recNo = start[0]; /* record # to start reading */ divide = 1; numRecs = numRecsLeftToRead; /* # of records to read at a time */ switch (var.datatype) { case CDF_CHAR: case CDF_UCHAR: cPtr = NULL; while (cPtr == NULL) { cPtr = (char *) malloc (sizeof(char) * numValues * numRecs); if (cPtr == NULL) { if (DEBUG) insufficient_memory(); divide *= 2; numRecs = totRecs / divide; } } read_cdf_variable_data (varId, recNo, /* starting record # */ numRecs, /* # of records to read */ var.dimensionality, var.dimSizes, /* dimesion sizes */ cPtr); /* data pointer */ if (DEBUG) { printf (" retrieved CDF data = \n"); for (k=0; k < numRecs; k++) { printf("\""); for (i=0; i < numValues; i++) printf ("%c", *(cPtr+(k*numValues+i))); printf("\"\n"); } } start[0] = 0; start[1] = 0; if (var.recVariance == VARY) { count[0] = numRecs; } if (DEBUG) { for (i=0; i < dimensionality; i++) printf (" start[%d] = %ld, count[%d] = %ld\n", i, start[i], i, count[i]); } ncstatus = nc_put_vara_text(ncid, ncVarId, start, count, cPtr); if (ncstatus != NC_NOERR) handle_netcdf_error(ncstatus); if (DEBUG && ncstatus != NC_NOERR) { if (ncstatus != NC_NOERR) printf (" Error putting data...\n"); else printf (" Done putting data...\n"); } free (cPtr); break; case CDF_BYTE: case CDF_INT1: scPtr = NULL; while (scPtr == NULL) { scPtr = (signed char *) malloc (sizeof(signed char)*numValues*numRecs); if (scPtr == NULL) { if (DEBUG) insufficient_memory(); divide *= 2; numRecs = totRecs / divide; } } read_cdf_variable_data (varId, recNo, /* starting record # */ numRecs, /* # of records to read */ var.dimensionality, var.dimSizes, /* dimesion sizes */ scPtr); /* data pointer */ if (var.recVariance == VARY) count[0] = numRecs; ncstatus = nc_put_vara_schar(ncid, ncVarId, start, count, scPtr); if (ncstatus != NC_NOERR) handle_netcdf_error(ncstatus); free (scPtr); break; case CDF_UINT1: ucPtr = NULL; sPtr = NULL; while (ucPtr == NULL || sPtr == NULL) { ucPtr = (unsigned char *) malloc (sizeof(unsigned char)*numValues*numRecs); sPtr = (short *) malloc (sizeof(short)*numValues*numRecs); if (ucPtr == NULL || sPtr == NULL) { if (DEBUG) insufficient_memory(); divide *= 2; numRecs = totRecs / divide; } } read_cdf_variable_data (varId, recNo, /* starting record # */ numRecs, /* # of records to read */ var.dimensionality, var.dimSizes, /* dimesion sizes */ ucPtr); /* data pointer */ if (var.recVariance == VARY) count[0] = numRecs; for (j = 0; j < numValues*numRecs; ++j) { *(sPtr+j) = (short) *(ucPtr+j); } ncstatus = nc_put_vara_short(ncid, ncVarId, start, count, sPtr); if (ncstatus != NC_NOERR) handle_netcdf_error(ncstatus); free (ucPtr); free (sPtr); break; case CDF_INT2: sPtr = NULL; while (sPtr == NULL) { sPtr = (short *) malloc (sizeof(short) * numValues * numRecs); if (sPtr == NULL) { if (DEBUG) insufficient_memory(); divide *= 2; numRecs = totRecs / divide; } } read_cdf_variable_data (varId, recNo, /* starting record # */ numRecs, /* # of records to read */ var.dimensionality, var.dimSizes, /* dimesion sizes */ sPtr); /* data pointer */ if (var.recVariance == VARY) count[0] = numRecs; ncstatus = nc_put_vara_short(ncid, ncVarId, start, count, sPtr); if (ncstatus != NC_NOERR) handle_netcdf_error(ncstatus); free (sPtr); break; case CDF_UINT2: usPtr = NULL; iPtr = NULL; while (usPtr == NULL || iPtr == NULL) { usPtr = (unsigned short *) malloc (sizeof(unsigned short) * numValues * numRecs); iPtr = (int *) malloc (sizeof(int) * numValues * numRecs); if (usPtr == NULL || iPtr == NULL) { if (DEBUG) insufficient_memory(); divide *= 2; numRecs = totRecs / divide; } } read_cdf_variable_data (varId, recNo, /* starting record # */ numRecs, /* # of records to read */ var.dimensionality, var.dimSizes, /* dimesion sizes */ usPtr); /* data pointer */ if (var.recVariance == VARY) count[0] = numRecs; for (j = 0; j < numValues*numRecs; ++j) { *(iPtr+j) = (int) *(usPtr+j); } ncstatus = nc_put_vara_int(ncid, ncVarId, start, count, iPtr); if (ncstatus != NC_NOERR) handle_netcdf_error(ncstatus); free (usPtr); free (iPtr); break; case CDF_INT4: iPtr = NULL; while (iPtr == NULL) { iPtr = (int *) malloc (sizeof(int) * numValues * numRecs); if (iPtr == NULL) { if (DEBUG) insufficient_memory(); divide *= 2; numRecs = totRecs / divide; } } read_cdf_variable_data (varId, recNo, /* starting record # */ numRecs, /* # of records to read */ var.dimensionality, var.dimSizes, /* dimesion sizes */ iPtr); /* data pointer */ if (var.recVariance == VARY) count[0] = numRecs; ncstatus = nc_put_vara_int(ncid, ncVarId, start, count, iPtr); if (ncstatus != NC_NOERR) handle_netcdf_error(ncstatus); free (iPtr); break; case CDF_UINT4: uiPtr = NULL; dPtr = NULL; while (uiPtr == NULL || dPtr == NULL) { uiPtr = (unsigned int *) malloc (sizeof(unsigned int) * numValues * numRecs); dPtr = (double *) malloc (sizeof(double) * numValues * numRecs); if (uiPtr == NULL) { if (DEBUG) insufficient_memory(); divide *= 2; numRecs = totRecs / divide; } } read_cdf_variable_data (varId, recNo, /* starting record # */ numRecs, /* # of records to read */ var.dimensionality, var.dimSizes, /* dimesion sizes */ uiPtr); /* data pointer */ if (var.recVariance == VARY) count[0] = numRecs; for (j = 0; j < numValues*numRecs; ++j) { *(dPtr+j) = (double) *(uiPtr+j); } ncstatus = nc_put_vara_double(ncid, ncVarId, start, count, dPtr); if (ncstatus != NC_NOERR) handle_netcdf_error(ncstatus); free (uiPtr); free (dPtr); break; case CDF_INT8: jPtr = NULL; dPtr = NULL; while (jPtr == NULL || dPtr == NULL) { jPtr = (long long *) malloc (sizeof(long long) * numValues * numRecs); dPtr = (double *) malloc (sizeof(double) * numValues * numRecs); if (jPtr == NULL || dPtr == NULL) { if (DEBUG) insufficient_memory(); divide *= 2; numRecs = totRecs / divide; } } read_cdf_variable_data (varId, recNo, /* starting record # */ numRecs, /* # of records to read */ var.dimensionality, var.dimSizes, /* dimesion sizes */ jPtr); /* data pointer */ if (var.recVariance == VARY) count[0] = numRecs; for (j = 0; j < numValues*numRecs; ++j) { *(dPtr+j) = (double) *(jPtr+j); } ncstatus = nc_put_vara_double(ncid, ncVarId, start, count, dPtr); if (ncstatus != NC_NOERR) handle_netcdf_error(ncstatus); free (jPtr); free (dPtr); break; case CDF_FLOAT: case CDF_REAL4: fPtr = NULL; while (fPtr == NULL) { fPtr = (float *) malloc (sizeof(float) * numValues * numRecs); if (fPtr == NULL) { if (DEBUG) insufficient_memory(); divide *= 2; numRecs = totRecs / divide; } } read_cdf_variable_data (varId, recNo, /* starting record # */ numRecs, /* # of records to read */ var.dimensionality, var.dimSizes, /* dimesion sizes */ fPtr); /* data pointer */ if (var.recVariance == VARY) count[0] = numRecs; ncstatus = nc_put_vara_float(ncid, ncVarId, start, count, fPtr); if (ncstatus != NC_NOERR) handle_netcdf_error(ncstatus); free (fPtr); break; case CDF_DOUBLE: case CDF_REAL8: dPtr = NULL; while (dPtr == NULL) { dPtr = (double *) malloc (sizeof(double) * numValues * numRecs); if (dPtr == NULL) { if (DEBUG) insufficient_memory(); divide *= 2; numRecs = totRecs / divide; } } read_cdf_variable_data (varId, recNo, /* starting record # */ numRecs, /* # of records to read */ var.dimensionality, var.dimSizes, /* dimesion sizes */ dPtr); /* data pointer */ if (var.recVariance == VARY) count[0] = numRecs; ncstatus = nc_put_vara_double(ncid, ncVarId, start, count, dPtr); if (ncstatus != NC_NOERR) handle_netcdf_error(ncstatus); free (dPtr); break; case CDF_EPOCH: dPtr = NULL; while (dPtr == NULL) { dPtr = (double *) malloc (sizeof(double)*numValues*numRecs); if (dPtr == NULL) { if (DEBUG) insufficient_memory(); divide *= 2; numRecs = totRecs / divide; } } read_cdf_variable_data (varId, recNo, /* starting record # */ numRecs, /* # of records to read */ var.dimensionality, var.dimSizes, /* dimesion sizes */ dPtr); /* data pointer */ if (var.recVariance == VARY) count[0] = numRecs; cPtr = (char *) malloc (sizeof(char) * numValues * numRecs * DD_TIME_STRING_LEN + 1); if (cPtr == NULL) memory_error("get_cdf_variable_data", "CDF_EPOCH"); ptr = cPtr; /* Get all the EPOCH values into a single string. */ for (i=0; i < numRecs * numValues; i++) { encodeEPOCH4 (*(dPtr+i), epString); strcpy (ptr, isotime_to_dd_time (epString)); ptr += DD_TIME_STRING_LEN; } ncstatus = nc_put_vara_text(ncid, ncVarId, start, count, cPtr); if (ncstatus != NC_NOERR) handle_netcdf_error(ncstatus); free (cPtr); free (dPtr); break; case CDF_EPOCH16: dPtr = NULL; while (dPtr == NULL) { dPtr = (double *) malloc (sizeof(double) * numValues*numRecs*2); if (dPtr == NULL) { if (DEBUG) insufficient_memory(); divide *= 2; numRecs = totRecs / divide; } } read_cdf_variable_data (varId, recNo, /* starting record # */ numRecs, /* # of records to read */ var.dimensionality, var.dimSizes, /* dimesion sizes */ dPtr); /* data pointer */ if (var.recVariance == VARY) count[0] = numRecs; cPtr = (char *) malloc (sizeof(char) * numValues * numRecs * DD_TIME_STRING_LEN + 1); if (cPtr == NULL) memory_error("get_cdf_variable_data", "CDF_EPOCH16"); ptr = cPtr; /* Get all the EPOCH16 values into a single string. */ for (i=0; i < numRecs * numValues; i++) { epoch16[0] = *(dPtr+i*2); epoch16[1] = *(dPtr+i*2+1); encodeEPOCH16_4 (epoch16, ep16String); strcpy (ptr, isotime_to_dd_time (ep16String)); ptr += DD_TIME_STRING_LEN; } printf(" %d %d\n", count[0], count[1]); ncstatus = nc_put_vara_text(ncid, ncVarId, start, count, cPtr); if (ncstatus != NC_NOERR) handle_netcdf_error(ncstatus); free (cPtr); free (dPtr); break; case CDF_TIME_TT2000: jPtr = NULL; while (jPtr == NULL) { jPtr = (long long *) malloc (sizeof(long long)*numValues*numRecs); if (jPtr == NULL) { if (DEBUG) insufficient_memory(); divide *= 2; numRecs = totRecs / divide; } } read_cdf_variable_data (varId, recNo, /* starting record # */ numRecs, /* # of records to read */ var.dimensionality, var.dimSizes, /* dimesion sizes */ jPtr); /* data pointer */ if (var.recVariance == VARY) count[0] = numRecs; cPtr = (char *) malloc (sizeof(char) * numValues * numRecs * DD_TIME_STRING_LEN + 1); if (cPtr == NULL) memory_error("get_cdf_variable_data", "CDF_EPOCH"); ptr = cPtr; /* Get all the TT2000 values into a single string. */ for (i=0; i < numRecs * numValues; i++) { // encodeTT2000 (*(jPtr+i), tt2000String); CDF_TT2000_to_UTC_string(*(jPtr+i), tt2000String, 3); strcpy (ptr, isotime_to_dd_time (tt2000String)); ptr += DD_TIME_STRING_LEN; } ncstatus = nc_put_vara_text(ncid, ncVarId, start, count, cPtr); if (ncstatus != NC_NOERR) handle_netcdf_error(ncstatus); free (cPtr); free (jPtr); break; default: printf ("** Error in getVarData: bad type"); } numRecsLeftToRead = totRecs - numRecs; if (numRecsLeftToRead > 0) { totRecs = numRecsLeftToRead; start[0] = numRecs; } } /* end of the 'while' loop */ } /*-------------------------------------------------------------------------- * This routine returns the string representation of the given CDF * datatype. *--------------------------------------------------------------------------*/ char * cdf_str_datatype (long type) { switch (type) { case CDF_BYTE: return "CDF_BYTE"; case CDF_INT1: return "CDF_INT1"; case CDF_CHAR: return "CDF_CHAR"; case CDF_INT2: return "CDF_INT2"; case CDF_UCHAR: return "CDF_UCHAR"; case CDF_UINT1: return "CDF_UINT1"; case CDF_INT4: return "CDF_INT4"; case CDF_INT8: return "CDF_INT8"; case CDF_UINT2: return "CDF_UINT2"; case CDF_FLOAT: return "CDF_FLOAT"; case CDF_REAL4: return "CDF_REAL4"; case CDF_DOUBLE: return "CDF_DOUBLE"; case CDF_REAL8: return "CDF_REAL8"; case CDF_UINT4: return "CDF_UINT4"; case CDF_EPOCH: return "CDF_EPOCH"; case CDF_EPOCH16: return "CDF_EPOCH16"; case CDF_TIME_TT2000: return "CDF_TIME_TT2000"; default: return "BAD_CDF_TYPE"; } } /*-------------------------------------------------------------------------- * This routine returns the string representation of the given netCDF * datatype. *--------------------------------------------------------------------------*/ char * NC_datatype (nc_type type) { switch (type) { case NC_BYTE: return "byte"; case NC_CHAR: return "char"; case NC_SHORT: return "short"; case NC_INT: return "int"; case NC_FLOAT: return "float"; case NC_DOUBLE: return "double"; default: return "UNKNOWN"; } } /*-------------------------------------------------------------------------- * This routine returns the netCDF datatype for the given CDF datatype. * All unsigned types are bumped up, either to double the size, or to * a double. CDF's epoch types are converted to string. *--------------------------------------------------------------------------*/ nc_type get_netcdf_datatype (long type) { nc_type netcdf_type; switch (type) { case CDF_BYTE: case CDF_INT1: netcdf_type = NC_BYTE; break; case CDF_CHAR: case CDF_UCHAR: case CDF_EPOCH: case CDF_EPOCH16: case CDF_TIME_TT2000: netcdf_type = NC_CHAR; break; case CDF_UINT1: netcdf_type = NC_SHORT; break; case CDF_INT2: netcdf_type = NC_SHORT; break; case CDF_UINT2: netcdf_type = NC_INT; break; case CDF_INT4: netcdf_type = NC_INT; break; case CDF_UINT4: netcdf_type = NC_DOUBLE; break; case CDF_INT8: netcdf_type = NC_DOUBLE; break; case CDF_FLOAT: case CDF_REAL4: netcdf_type = NC_FLOAT; break; case CDF_DOUBLE: case CDF_REAL8: netcdf_type = NC_DOUBLE; break; default: { printf ("** ERROR: Unknown CDF datatype\n"); exit (1); } } return netcdf_type; } /*--------------------------------------------------------------------------- * Read the CDF variable data for the given CDF variable number. *---------------------------------------------------------------------------*/ void read_cdf_variable_data (long varNum, /* CDF variable number */ long recNo, /* record # for start reading */ long recCount, /* # of records to read */ long dim, /* CDF dimensionality */ long dimSizes[], /* CDF dimesion sizes */ void *data) /* data pointer */ { CDFstatus status; int i; long recInterval, /* No. of recors to skip */ dimIndices[CDF_MAX_DIMS], /* Beginning location of the array */ /* to be dumped */ dimIntervals[CDF_MAX_DIMS]; /* No. of elements to skip */ recInterval = 1L; /* # of records to skip between writes */ for (i=0; i < dim; i++) { dimIndices[i] = 0; /* Dump data from the beginning of array */ dimIntervals[i] = 1; /* Dump all the elements in the array */ } status = CDFlib (SELECT_,zVAR_, varNum, zVAR_RECNUMBER_, recNo, zVAR_RECCOUNT_, recCount, zVAR_RECINTERVAL_, recInterval, zVAR_DIMINDICES_, dimIndices, zVAR_DIMCOUNTS_, dimSizes, zVAR_DIMINTERVALS_, dimIntervals, GET_, zVAR_HYPERDATA_, data, NULL_); if (status != CDF_OK) cdf_status_handler (status, "GET_, zVAR_HYPERDATA_"); } /*-------------------------------------------------------------------------- * Remove the filepath from a file name. * * Example: * /home/data/mydata.txt => mydata.txt *--------------------------------------------------------------------------*/ void removeFilepath (char *fileName) { char *ptr; ptr = (char *) strrchr(fileName, '/'); /* Unix file path separator */ if (ptr != NULL) { ptr++; strcpy(fileName, ptr); } else { ptr = (char *) strrchr(fileName, '\\'); /* Windows file separator */ if (ptr != NULL) { ptr++; strcpy(fileName, ptr); } } } /*-------------------------------------------------------------------------- * Handles a CDF error. *--------------------------------------------------------------------------*/ void cdf_status_handler (CDFstatus status, char *source) { char message[CDF_STATUSTEXT_LEN+1]; CDFerror (status, message); /* Get the appropriate message */ if (status < CDF_WARN) { printf ("An error has occurred, halting...\n"); printf ("%s\n", message); printf ("** Error source: %s\n", source); exit (status); } else if (status < CDF_OK) { printf ("Warning, function may not have compeleted as expected...\n"); printf ("%s\n", message); } else if (status > CDF_OK) { printf ("Function compeleted successfully, but be advised that...\n"); printf ("%s\n", message); } } /*-------------------------------------------------------------------------- * Handles a netCDF error. *--------------------------------------------------------------------------*/ void handle_netcdf_error(int status) { fprintf(stderr, "%s\n", nc_strerror(status)); } /*-------------------------------------------------------------------------- * Handles a memory allocation error. *--------------------------------------------------------------------------*/ void memory_error(char *source, char *datatype) { printf ("** Memory allocation error occurred in %s. data type = %s", source, datatype); exit (1); } void insufficient_memory () { printf("Insufficient memory to load all the records at once"); } /*--------------------------------------------------------------------------*/ void usage() { printf ("\nDescription:\n"); printf (" This program converts a CDF file into a netCDF file."); printf ("\n"); printf ("Usage: cdf-to-netCDF -[Options] \n"); printf ("\n"); printf ("Options:\n"); printf (" -map Use the user-supplied mapping file.\n"); printf (" -debug Show debug information.\n"); printf ("\n"); printf ("Examples of usage: \n"); printf ("1) cdf-to-netCDF test.cdf\n"); printf (" will convert the test.cdf file into the test.nc file.\n\n"); printf ("2) cdf-to-netCDF -map mymap.dat test.cdf\n"); printf (" will convert the test.cdf file into the test.nc file using\n"); printf (" the user-supplied mapping file called 'mymap.dat' instead\n"); printf (" of using the default cdf-to-netCDF mapping file.\n"); printf ("\n"); exit(1); } void parseCmdLine (int argc, char *argv[]) { int i; char *nextArg; for (i=0; i < argc; i++) { if (strcmp(argv[i],"-map") == 0) { nextArg = getNextArgument(argc, argv, i); if (strcmp(nextArg, "No next argument") == 0 || *(nextArg+0) == '-') errorMsg("** Error - mapping file is not defined"); else strcpy(mappingFile, nextArg); } else if (strcmp(argv[i],"-debug") == 0) DEBUG = TRUE; } } char * getNextArgument (int argc, char *argv[], int currentIndex) { char *nextArg, msg[30]; int nextIndex; nextIndex = currentIndex+1; if (nextIndex == argc) { strcpy (msg, "No next argument"); nextArg = msg; } else nextArg = argv[nextIndex]; return nextArg; } void errorMsg (char *msg) { printf ("%s\n", msg); exit (1); } void map_CDF_attr_to_netCDF (char *searchAttr, /* in - CDF attr name */ char *mappedAttrName) /* out - netCDF attr name */ { int i; strcpy(mappedAttrName, searchAttr); for (i=0; i < totAttrsInMappingFile; i++) { if (strcmp(cdfAttrNames[i], searchAttr) == 0) { strcpy(mappedAttrName, netcdfAttrNames[i]); break; } } } void breakdown_DIMENSIONS_entry (char *entry, /* in - a DIMENSIONS entry */ char **dimStrings) /* out - dimesion names */ { char *ptr, *ptr1; int i = 0, j; ptr = entry; ptr1 = strstr(ptr, ","); i = 0; while (ptr1 != NULL) { j = ptr1 - ptr; strncpy (dimStrings[i], ptr, (size_t)j); dimStrings[i][j] = (char) '\0'; ptr = ptr1 + 1; ptr1 = strstr(ptr, ","); ++i; } if (ptr != NULL) strcpy (dimStrings[i], ptr); }