tools.c 8.61 KB
/*******************************************************************************
 *   
 * 	tools.c - 2014/01/29
 *
 *  	Some specific functions requiered for AMDA converter
 *
 */ 
#include <stdio.h>
#include <string.h>

#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;
                }
	}

	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) {

				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;
}


/*******************************************************************************
 *  
 *  	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;

}