/******************************************************************************* * * tools.c - 2014/01/29 * * Some specific functions requiered for AMDA converter * */ #include #include #include "tools.h" #include "netcdf.h" #include "cdf.h" #ifndef TRUE #define TRUE 1 #define FALSE (! TRUE) #endif #define VERSION_MIN "3.4.0" #define START_TIME "StartTime" #define STOP_TIME "StopTime" #define TIME_VAR "Time" extern CDFid id; /* CDF file identifier */ extern int ncid; /* netCDF file identifier */ extern long nZvars; /* Number of CDF zVariables */ /******************************************************************************* * * Check version of CDFlib greated or equal to 3.5 (needed for TT2000) */ int check_version (void) { long version, release, increment; char subincrement; int status; char str_version [30]; status = CDFgetLibraryVersion (& version, & release, & increment, & subincrement); if (status < CDF_OK) { printf ("ERROR : unable to get CDFlib version\n"); goto EXIT; } sprintf (str_version, "%d.%d.%d-%c", version, release, increment, subincrement); printf ("CDFlib version : %s\n", str_version); if (strcmp (str_version, VERSION_MIN) < 0) { printf ("ERROR : version %s < %s", str_version, VERSION_MIN); } EXIT: return status; } /******************************************************************************* * * Check if the given year is a leap one */ int leap_year (int year) { if ((year % 400) == 0) return TRUE; if ((year % 100) == 0) return FALSE; if ((year % 4) == 0) return TRUE; return FALSE; } /******************************************************************************* * * Convert an ISO 8601 date time to a DD Time string */ char * isotime_to_dd_time (char * input) { static char output [DD_TIME_STRING_LEN + 1]; int i, count, ddd; int yy, mm, dd, h, m, s, ms; int duration[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; count = sscanf (input, "%d-%d-%dT%d:%d:%d.%3d", & yy, & mm, & dd, & h, & m, & s, &ms); if (count != 7) { printf ("Unexpected time format: %s\n", input); strcpy (output, "ERROR "); goto EXIT; } if (leap_year (yy)) duration [2] = 29; ddd = dd - 1; /* Jan-01 : 0 => ddd in [0, 366[ */ for (i = 1; i < mm; i++) ddd += duration [i]; sprintf (output, "%04.4d%03.3d%02.2d%02.2d%02.2d%03.3d", yy, ddd, h, m, s, ms); EXIT: return output; } /******************************************************************************* * * Parse variables metadata to define time variable ID : * * ID of a variable that appears in DEPEND_0 attribute of other variables */ char * get_time_variable() { long timeVarId = -1; long varId; CDFstatus status; long attrNum = CDFgetAttrNum (id, "DEPEND_0"); char * timeVarName = NULL; if (attrNum < CDF_OK) { printf ("ERROR : no DEPEND_0 attribute\n"); attrNum = CDFgetAttrNum (id, "Depend_0"); if (attrNum < CDF_OK) { printf ("ERROR : no Depend_0 attribute\n"); // goto EXIT; goto NO_DEPEND_0; } } for (varId = 0; varId < nZvars; varId++) { char name [CDF_VAR_NAME_LEN256+1]; long dataType; long numElems; char buffer [CDF_VAR_NAME_LEN256+1]; status = CDFgetzVarName (id, varId, name); if (status != CDF_OK) cdf_status_handler (status, "Get var name"); status = CDFinquireAttrzEntry (id, attrNum, varId, & dataType, & numElems); if (status == NO_SUCH_ENTRY) continue; if (status != CDF_OK) cdf_status_handler (status, "Get DEPEND_0"); else { if (dataType == CDF_CHAR || dataType == CDF_UCHAR) { status = CDFgetAttrzEntry (id, attrNum, varId, buffer); buffer [numElems] = 0; if (timeVarName == NULL) { timeVarName = strdup (buffer); } else if (strcmp (timeVarName, buffer) != 0) { printf ("WARNING : Search time variable conflict between %s and %s\n %s is taken as Time\n", timeVarName, buffer, timeVarName); // EB: select the first time variable // timeVarName = NULL; // goto EXIT; } } } } if (timeVarName != NULL) printf ("Identified time variable : %s\n", timeVarName); EXIT: return timeVarName; NO_DEPEND_0 : for (varId = 0; varId < nZvars; varId++) { char name [CDF_VAR_NAME_LEN256+1]; long dataType; long numElems; long numDims, recVary; long dimSizes [CDF_MAX_DIMS]; long dimVarys [CDF_MAX_DIMS]; status = CDFgetzVarName (id, varId, name); if (status != CDF_OK) cdf_status_handler (status, "Get var name"); status = CDFinquirezVar (id, varId, name, & dataType, & numElems, & numDims, dimSizes, & recVary, dimVarys); if (status != CDF_OK) cdf_status_handler (status); if ( dataType == CDF_EPOCH ) { timeVarName = strdup (name); printf ("Identified time variable : %s\n", timeVarName); break; } } return timeVarName; } /******************************************************************************* * * Compute time coverage (DD_TIME strings) of a currently opened CDF file */ int get_file_coverage (char * start_coverage, char * stop_coverage) { int error = -1; long varId = -1; CDFstatus status; char varName [CDF_VAR_NAME_LEN256+1]; long dataType, numElems, numDims, recVary, numRecs; long dimSizes [CDF_MAX_DIMS]; long dimVarys [CDF_MAX_DIMS]; long indices [CDF_MAX_DIMS]; double d_buffer [2]; long long l_buffer [2]; char * timeVar = NULL; char str1 [EPOCH16_4_STRING_LEN+1]; char str2 [EPOCH16_4_STRING_LEN+1]; strcpy (start_coverage, ""); strcpy (stop_coverage, ""); timeVar = get_time_variable (); if (timeVar == NULL) { printf ("Error : no time variable identified\n"); goto EXIT; } varId = CDFvarNum (id, timeVar); if (varId == -1) { printf ("Error : no time variable identified\n"); goto EXIT; } status = CDFinquirezVar (id, varId, varName, & dataType, & numElems, & numDims, dimSizes, & recVary, dimVarys); if (status != CDF_OK) cdf_status_handler (status, "CDF inquire zVar"); if (recVary != VARY) { printf ("ERROR : variable %s not record varying\n", varName); goto EXIT; } if (numDims > 1) { printf ("Error : variable %s numDims > 1\n", varName); goto EXIT; } status = CDFgetzVarNumRecsWritten (id, varId, & numRecs); if (status != CDF_OK) cdf_status_handler (status, "CDF get zVar num recs"); indices [0] = 0; indices [1] = 0; indices [3] = 0; switch (dataType) { case CDF_EPOCH: status = CDFgetzVarData (id, varId, 0L, indices, d_buffer); encodeEPOCH4 (d_buffer [0], str1); status = CDFgetzVarData (id, varId, numRecs -1, indices, d_buffer); encodeEPOCH4 (d_buffer [0], str2); break; case CDF_EPOCH16: status = CDFgetzVarData (id, varId, 0L, indices, d_buffer); encodeEPOCH16_4 (d_buffer, str1); status = CDFgetzVarData (id, varId, numRecs -1, indices, d_buffer); encodeEPOCH16_4 (d_buffer, str2); break; case CDF_TIME_TT2000: status = CDFgetzVarData (id, varId, 0L, indices, l_buffer); encodeTT2000 (l_buffer [0], str1, 3); status = CDFgetzVarData (id, varId, numRecs -1, indices, l_buffer); encodeTT2000 (l_buffer [0], str2, 3); break; default: printf ("Error : variable %d is not a Time variable\n"); goto EXIT; } strcpy (start_coverage, isotime_to_dd_time (str1)); strcpy (stop_coverage, isotime_to_dd_time (str2)); error = 0; EXIT: return error; } #define NDIM 2 /******************************************************************************* * * Set file time coverage metadata */ int set_file_time_coverage () { int error = 0; char start_time [DD_TIME_STRING_LEN + 1]; char stop_time [DD_TIME_STRING_LEN + 1]; int time_dim; int start_id, stop_id; int nc_status = NC_NOERR; size_t start [NDIM]; size_t count [NDIM]; error = get_file_coverage (start_time, stop_time); if (error != 0) goto EXIT; printf ("CDF time coverage : %s - %s\n", start_time, stop_time); nc_status = nc_def_dim (ncid, "TimeLength", DD_TIME_STRING_LEN, & time_dim); if (nc_status != NC_NOERR) goto EXIT; nc_status = nc_def_var (ncid, START_TIME, NC_CHAR, 1, & time_dim, & start_id); if (nc_status != NC_NOERR) goto EXIT; nc_status = nc_def_var (ncid, STOP_TIME, NC_CHAR, 1, & time_dim, & stop_id); if (nc_status != NC_NOERR) goto EXIT; start [0] = 0; count [0] = DD_TIME_STRING_LEN; nc_enddef (ncid); nc_status = nc_put_vara_text (ncid, start_id, start, count, start_time); if (nc_status != NC_NOERR) goto EXIT; nc_status = nc_put_vara_text (ncid, stop_id, start, count, stop_time); if (nc_status != NC_NOERR) goto EXIT; EXIT: printf ("NC status = %d\n", nc_status); return error; } /******************************************************************************* * * Rename time_variable to "Time" (necessary for AMDA DD server usage) */ int rename_time_variable () { int error = -1; char * timeVar = NULL; int varId; int nc_status; timeVar = get_time_variable (); if (timeVar == NULL) { printf ("ERROR : no time variable identified\n"); goto EXIT; } nc_status = nc_redef (ncid); if (nc_status != NC_NOERR) goto EXIT; nc_status = nc_inq_varid (ncid, timeVar, & varId); if (nc_status != NC_NOERR) goto EXIT; nc_status = nc_rename_var (ncid, varId, TIME_VAR); if (nc_status != NC_NOERR) goto EXIT; nc_status = nc_enddef (ncid); if (nc_status != NC_NOERR) goto EXIT; error = 0; EXIT: return error; }