Commit d1c8cd73 authored by Uwe Schulzweida's avatar Uwe Schulzweida
Browse files

0004-made-reference-time-accessible-via-the-iterator-inte.patch

parent 039e3e44
......@@ -408,6 +408,7 @@ int cdiIterator_nextField(CdiIterator *me); //Points the iterator at the ne
//All outXXX arguments to these functions may be NULL.
char *cdiIterator_inqStartTime(CdiIterator *me); //Returns the (start) time as an ISO-8601 coded string. The caller is responsible to Free() the returned string.
char *cdiIterator_inqEndTime(CdiIterator *me); //Returns the end time of an integration period as an ISO-8601 coded string, or NULL if there is no end time. The caller is responsible to Free() the returned string.
char *cdiIterator_inqRTime(CdiIterator *me); //Returns the reference date as an ISO-8601 coded string. The caller is responsible to Free() the returned string.
char *cdiIterator_inqVTime(CdiIterator *me); //Returns the validity date as an ISO-8601 coded string. The caller is responsible to Free() the returned string.
int cdiIterator_inqLevelType(CdiIterator *me, int levelSelector, char **outName_optional, char **outLongName_optional, char **outStdName_optional, char **outUnit_optional); //callers are responsible to Free() strings that they request
int cdiIterator_inqLevel(CdiIterator *me, int levelSelector, double *outValue1_optional, double *outValue2_optional); //outValue2 is only written to if the level is a hybrid level
......
......@@ -282,6 +282,13 @@ typedef struct
int subtype_index; /* tile index for this key-value pair */
} opt_key_val_pair_t;
//enum for differenciating between the different times that we handle
typedef enum {
kCdiTimeType_referenceTime,
kCdiTimeType_startTime,
kCdiTimeType_endTime
} CdiTimeType;
......
......@@ -289,24 +289,15 @@ static int getAvailabilityOfRelativeTimes(grib_handle* gh, bool* outHaveForecast
}
}
char* gribMakeTimeString(grib_handle* gh, bool getEndTime)
char* gribMakeTimeString(grib_handle* gh, CdiTimeType timeType)
{
//Get the parts of the reference date.
#ifdef __cplusplus
struct tm date;
date.tm_mon = (int) gribGetLong(gh, "month") - 1; //months are zero based in struct tm and one based in GRIBy
struct tm date;
date.tm_mon = (int)gribGetLong(gh, "month") - 1; //months are zero based in struct tm and one based in GRIB
date.tm_mday = (int)gribGetLong(gh, "day");
date.tm_hour = (int)gribGetLong(gh, "hour");
date.tm_min = (int)gribGetLong(gh, "minute");
date.tm_mday = (int)gribGetLong(gh, "day");
date.tm_hour = (int)gribGetLong(gh, "hour");
date.tm_min = (int)gribGetLong(gh, "minute");
#else
struct tm date = {
.tm_mon = (int)gribGetLong(gh, "month") - 1, //months are zero based in struct tm and one based in GRIBy
.tm_mday = (int)gribGetLong(gh, "day"),
.tm_hour = (int)gribGetLong(gh, "hour"),
.tm_min = (int)gribGetLong(gh, "minute")
};
#endif
if(gribEditionNumber(gh) == 1)
{
date.tm_year = (int)gribGetLong(gh, "yearOfCentury"); //years are -1900 based both in struct tm and GRIB1
......@@ -316,23 +307,27 @@ char* gribMakeTimeString(grib_handle* gh, bool getEndTime)
date.tm_year = (int)gribGetLong(gh, "year") - 1900; //years are -1900 based in struct tm and zero based in GRIB2
date.tm_sec = (int)gribGetLong(gh, "second");
//Determine whether we have a forecast time and a time range.
bool haveForecastTime, haveTimeRange;
if(getAvailabilityOfRelativeTimes(gh, &haveForecastTime, &haveTimeRange)) return NULL;
if(getEndTime && !haveTimeRange) return NULL; //tell the caller that the requested time does not exist
//If we have relative times, apply them to the date
if(haveForecastTime)
//If the start or end time are requested, we need to take the relative times into account.
if(timeType != kCdiTimeType_referenceTime)
{
long offset = gribGetLongDefault(gh, "forecastTime", 0); //if(stepUnits == indicatorOfUnitOfTimeRange) assert(startStep == forecastTime)
long offsetUnit = gribGetLongDefault(gh, "indicatorOfUnitOfTimeRange", 255);
if(addToDate(&date, offset, offsetUnit)) return NULL;
if(getEndTime)
//Determine whether we have a forecast time and a time range.
bool haveForecastTime, haveTimeRange;
if(getAvailabilityOfRelativeTimes(gh, &haveForecastTime, &haveTimeRange)) return NULL;
if(timeType == kCdiTimeType_endTime && !haveTimeRange) return NULL; //tell the caller that the requested time does not exist
//If we have relative times, apply the relative times to the date
if(haveForecastTime)
{
assert(haveTimeRange);
long range = gribGetLongDefault(gh, "lengthOfTimeRange", 0); //if(stepUnits == indicatorOfUnitForTimeRange) assert(endStep == startStep + lengthOfTimeRange)
long rangeUnit = gribGetLongDefault(gh, "indicatorOfUnitForTimeRange", 255);
if(addToDate(&date, range, rangeUnit)) return NULL;
long offset = gribGetLongDefault(gh, "forecastTime", 0); //if(stepUnits == indicatorOfUnitOfTimeRange) assert(startStep == forecastTime)
long offsetUnit = gribGetLongDefault(gh, "indicatorOfUnitOfTimeRange", 255);
if(addToDate(&date, offset, offsetUnit)) return NULL;
if(timeType == kCdiTimeType_endTime)
{
assert(haveTimeRange);
long range = gribGetLongDefault(gh, "lengthOfTimeRange", 0); //if(stepUnits == indicatorOfUnitForTimeRange) assert(endStep == startStep + lengthOfTimeRange)
long rangeUnit = gribGetLongDefault(gh, "indicatorOfUnitForTimeRange", 255);
if(addToDate(&date, range, rangeUnit)) return NULL;
}
}
}
}
......
......@@ -3,6 +3,7 @@
#ifdef HAVE_LIBGRIB_API
#include "cdi_int.h"
#include "grid.h"
#include <grib_api.h>
......@@ -24,7 +25,7 @@ void gribGetDoubleArray(grib_handle* gribHandle, const char* key, double* array)
void gribGetLongArray(grib_handle* gribHandle, const char* key, long* array); //The caller is responsible to ensure a sufficiently large buffer.
long gribEditionNumber(grib_handle* gh);
char* gribMakeTimeString(grib_handle* gh, bool getEndTime); //For statistical fields, setting getEndTime produces the time of the end of the integration period, otherwise the time of the start of the integration period is returned. Returns NULL if getEndTime is set and the field does not have an integration period.
char* gribMakeTimeString(grib_handle* gh, CdiTimeType timeType); //Returns NULL if timeType is kCdiTimeType_endTime and the field does not have an integration period (statistical data).
int gribapiTimeIsFC(grib_handle *gh);
int gribapiGetTsteptype(grib_handle *gh);
int gribGetDatatype(grib_handle* gribHandle);
......
......@@ -433,7 +433,7 @@ int cdiIterator_nextField(CdiIterator* me)
}
}
static char* cdiIterator_inqTime(CdiIterator* me, bool getEndTime)
static char* cdiIterator_inqTime(CdiIterator* me, CdiTimeType timeType)
{
sanityCheck(me);
switch(me->filetype)
......@@ -441,7 +441,7 @@ static char* cdiIterator_inqTime(CdiIterator* me, bool getEndTime)
#ifdef HAVE_LIBGRIB_API
case FILETYPE_GRB:
case FILETYPE_GRB2:
return cdiGribIterator_inqTime(me, getEndTime);
return cdiGribIterator_inqTime(me, timeType);
#endif
#ifdef HAVE_LIBNETCDF
......@@ -459,7 +459,7 @@ static char* cdiIterator_inqTime(CdiIterator* me, bool getEndTime)
#ifdef HAVE_LIBIEG
case FILETYPE_IEG:
#endif
return cdiFallbackIterator_inqTime(me, getEndTime);
return cdiFallbackIterator_inqTime(me, timeType);
default:
Error(kUnexpectedFileTypeMessage);
......@@ -490,7 +490,7 @@ This is due to the fact that GRIB-API version 1.12.3 still does not implement th
*/
char* cdiIterator_inqStartTime(CdiIterator* me)
{
return cdiIterator_inqTime(me, false);
return cdiIterator_inqTime(me, kCdiTimeType_startTime);
}
/*
......@@ -516,7 +516,34 @@ This is due to the fact that GRIB-API version 1.12.3 still does not implement th
*/
char* cdiIterator_inqEndTime(CdiIterator* me)
{
return cdiIterator_inqTime(me, true);
return cdiIterator_inqTime(me, kCdiTimeType_endTime);
}
/*
@Function cdiIterator_inqRTime
@Title Get the validity time of the current field
@Prototype char* cdiIterator_inqRTime(CdiIterator* me)
@Parameter
@item iterator The iterator to operate on.
@Result A malloc'ed string containing the validity time of the current field in the format "YYYY-MM-DDTHH:MM:SS.mmm".
@Description
The returned time is the validity time as it is returned by taxisInqVtime(), only more precise.
That is, if the field is a time point, its time is returned,
if it is a statistical field with an integration period, the end time of the integration period is returned.
Converts the time to the ISO-8601 format and returns it in a newly allocated buffer.
The caller is responsible to Free() the resulting string.
If the file is a GRIB file, the calendar that is used to resolve the relative times is the proleptic calendar
as it is implemented by the standard C mktime() function.
This is due to the fact that GRIB-API version 1.12.3 still does not implement the calendar identification fields.
*/
char* cdiIterator_inqRTime(CdiIterator* me)
{
return cdiIterator_inqTime(me, kCdiTimeType_referenceTime);
}
/*
......
......@@ -207,13 +207,33 @@ int cdiFallbackIterator_nextField(CdiIterator *super)
return CDI_NOERR;
}
char *cdiFallbackIterator_inqTime(CdiIterator *super, bool getEndTime)
char *cdiFallbackIterator_inqTime(CdiIterator *super, CdiTimeType timeType)
{
CdiFallbackIterator *me = (CdiFallbackIterator *)(void *)super;
if(getEndTime) return NULL; //The stream interface does not export the start/end times of statistical fields, so we treat all data as point of time data, returning the validity time as the start time.
//retrieve the time information
int taxisId = vlistInqTaxis(me->vlistId);
int date = taxisInqVdate(taxisId);
int time = taxisInqVtime(taxisId);
int date = 0, time = 0;
switch(timeType)
{
case kCdiTimeType_referenceTime:
date = taxisInqRdate(taxisId);
time = taxisInqRtime(taxisId);
break;
case kCdiTimeType_startTime:
date = taxisInqVdate(taxisId);
time = taxisInqVtime(taxisId);
break;
case kCdiTimeType_endTime:
return NULL; //The stream interface does not export the start/end times of statistical fields, so we treat all data as point of time data, returning the validity time as the start time.
default:
assert(0 && "internal error, please report this bug");
}
//decode the time information and reencode it into an ISO-compliant string
int year, month, day, hour, minute, second;
cdiDecodeDate(date, &year, &month, &day);
cdiDecodeTime(time, &hour, &minute, &second);
......
......@@ -9,6 +9,7 @@
#define INCLUDE_GUARD_CDI_ITERATOR_FALLBACK_H
#include "cdi.h"
#include "cdi_int.h"
#include "iterator.h"
typedef struct CdiFallbackIterator CdiFallbackIterator;
......@@ -21,7 +22,7 @@ CdiFallbackIterator *cdiFallbackIterator_deserialize(const char *me);
int cdiFallbackIterator_nextField(CdiIterator *me);
char *cdiFallbackIterator_inqTime(CdiIterator *me, bool getEndTime);
char *cdiFallbackIterator_inqTime(CdiIterator *me, CdiTimeType timeType);
int cdiFallbackIterator_levelType(CdiIterator *me, int levelSelector, char **outName, char **outLongName, char **outStdName, char **outUnit);
int cdiFallbackIterator_level(CdiIterator *me, int levelSelector, double *outValue1, double *outValue2);
int cdiFallbackIterator_zaxisUuid(CdiIterator *me, int *outVgridNumber, int *outLevelCount, unsigned char outUuid[CDI_UUID_SIZE]);
......
......@@ -367,10 +367,10 @@ int cdiGribIterator_nextField(CdiIterator *super)
return CDI_NOERR;
}
char *cdiGribIterator_inqTime(CdiIterator *super, bool getEndTime)
char *cdiGribIterator_inqTime(CdiIterator *super, CdiTimeType timeType)
{
CdiGribIterator *me = (CdiGribIterator*)super;
return gribMakeTimeString(me->gribHandle, getEndTime);
return gribMakeTimeString(me->gribHandle, timeType);
}
int cdiGribIterator_levelType(CdiIterator *super, int levelSelector, char **outName, char **outLongName, char **outStdName, char **outUnit)
......
......@@ -8,6 +8,7 @@
#define INCLUDE_GUARD_CDI_ITERATOR_GRIB_H
#include "cdi.h"
#include "cdi_int.h"
#include "iterator.h"
#include "input_file.h"
......@@ -25,7 +26,7 @@ CdiGribIterator *cdiGribIterator_deserialize(const char *me);
int cdiGribIterator_nextField(CdiIterator *me);
char *cdiGribIterator_inqTime(CdiIterator *me, bool getEndTime);
char *cdiGribIterator_inqTime(CdiIterator *me, CdiTimeType timeType);
int cdiGribIterator_levelType(CdiIterator *me, int levelSelector, char **outName, char **outLongName, char **outStdName, char **outUnit);
int cdiGribIterator_level(CdiIterator *me, int levelSelector, double *outValue1, double *outValue2);
int cdiGribIterator_zaxisUuid(CdiIterator *me, int *outVgridNumber, int *outLevelCount, unsigned char outUuid[CDI_UUID_SIZE]);
......
......@@ -269,6 +269,7 @@ module mo_cdi
public :: cdiIterator_nextField
public :: cdiIterator_inqStartTime
public :: cdiIterator_inqEndTime
public :: cdiIterator_inqRTime
public :: cdiIterator_inqVTime
public :: cdiIterator_inqLevelType
public :: cdiIterator_inqLevel
......@@ -3281,6 +3282,32 @@ contains
end if
end function cdiIterator_inqEndTime
function cdiIterator_inqRTime(me_dummy) result(f_result)
character(kind = c_char), dimension(:), pointer :: f_result
type(t_CdiIterator), intent(in) :: me_dummy
type(c_ptr) :: cString
integer :: rv_shape(1)
character(kind = c_char), dimension(:), pointer :: temp
interface
function lib_cdiIterator_inqRTime(me_dummy) bind(c, name =&
& 'cdiIterator_inqRTime') result(c_result)
import c_ptr
type(c_ptr) :: c_result
type(c_ptr), value :: me_dummy
end function lib_cdiIterator_inqRTime
end interface
cString = lib_cdiIterator_inqRTime(me_dummy%ptr)
if(c_associated(cString)) then
rv_shape(1) = int(lib_strlen(cString))
call c_f_pointer(cString, temp, rv_shape)
allocate(f_result(rv_shape(1)))
f_result = temp
call lib_free(cString)
else
f_result => null()
end if
end function cdiIterator_inqRTime
function cdiIterator_inqVTime(me_dummy) result(f_result)
character(kind = c_char), dimension(:), pointer :: f_result
type(t_CdiIterator), intent(in) :: me_dummy
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment