From 4c9db07768c38cf4996a65f7d4b9d3b3b130fc2b Mon Sep 17 00:00:00 2001 From: Maarten Plieger Date: Mon, 23 Dec 2024 12:44:54 +0100 Subject: [PATCH 1/3] Made it possible to reference the time dimension to the default value of the forecast_reference dimension --- CCDFDataModel/CTime.cpp | 20 ++ CCDFDataModel/CTime.h | 11 + adagucserverEC/utils/XMLGenUtils.cpp | 304 ++++++++++++++------------- 3 files changed, 192 insertions(+), 143 deletions(-) diff --git a/CCDFDataModel/CTime.cpp b/CCDFDataModel/CTime.cpp index e873760e..0f83b646 100644 --- a/CCDFDataModel/CTime.cpp +++ b/CCDFDataModel/CTime.cpp @@ -1055,6 +1055,10 @@ time_t CTime::getEpochTimeFromDateString(CT::string dateString) { CTime::Date CTime::subtractPeriodFromDate(CTime::Date date, CT::string period) { CTime::Date datePeriod = periodToDate(period); + return this->subtractPeriodFromDate(date, datePeriod); +} + +CTime::Date CTime::subtractPeriodFromDate(CTime::Date date, CTime::Date datePeriod) { Date newDate; newDate.year = date.year - datePeriod.year; newDate.month = date.month - datePeriod.month; @@ -1063,7 +1067,23 @@ CTime::Date CTime::subtractPeriodFromDate(CTime::Date date, CT::string period) { newDate.minute = date.minute - datePeriod.minute; newDate.second = date.second - datePeriod.second; double offset = this->dateToOffset(newDate); + return this->offsetToDate(offset); +} +CTime::Date CTime::addPeriodToDate(CTime::Date date, CT::string period) { + CTime::Date datePeriod = periodToDate(period); + return this->addPeriodToDate(date, datePeriod); +} + +CTime::Date CTime::addPeriodToDate(CTime::Date date, CTime::Date datePeriod) { + Date newDate; + newDate.year = date.year + datePeriod.year; + newDate.month = date.month + datePeriod.month; + newDate.day = date.day + datePeriod.day; + newDate.hour = date.hour + datePeriod.hour; + newDate.minute = date.minute + datePeriod.minute; + newDate.second = date.second + datePeriod.second; + double offset = this->dateToOffset(newDate); return this->offsetToDate(offset); } diff --git a/CCDFDataModel/CTime.h b/CCDFDataModel/CTime.h index 70ad9cc6..8677a457 100644 --- a/CCDFDataModel/CTime.h +++ b/CCDFDataModel/CTime.h @@ -231,6 +231,17 @@ class CTime { * @return Date */ Date subtractPeriodFromDate(CTime::Date date, CT::string period); + Date subtractPeriodFromDate(CTime::Date date, Date period); + + /** + * @brief Can be used to add an iso8601 period string to a date. The function ensures that allowed ranges for the individual time componets are preserved. + * + * @param date + * @param period + * @return Date + */ + Date addPeriodToDate(CTime::Date date, CT::string period); + Date addPeriodToDate(CTime::Date date, Date period); /** * @brief Converts a iso8601 period string to a date diff --git a/adagucserverEC/utils/XMLGenUtils.cpp b/adagucserverEC/utils/XMLGenUtils.cpp index 5a7a31b1..7d83de3f 100644 --- a/adagucserverEC/utils/XMLGenUtils.cpp +++ b/adagucserverEC/utils/XMLGenUtils.cpp @@ -141,14 +141,69 @@ int populateMetadataLayerStruct(MetadataLayer *metadataLayer, bool readFromDB) { return 0; } +int checkDependenciesBetweenDims(MetadataLayer *mL) { + // mL->layerMetadata.dimList[0].defaultValue = "A"; + auto &lmDims = mL->layerMetadata.dimList; // Layer metadata dimensions, referenced by & so we can adjust the value in the object of the vector + auto cfgDims = mL->dataSource->cfgLayer->Dimension; // Layer configuration dimensions + + // Find time and reference_time dimensions in the layerMetadata dimList + auto lmDimTimeIt = std::find_if(lmDims.begin(), lmDims.end(), [](const LayerMetadataDim &d) -> bool { return d.serviceName.equals("time"); }); + auto lmDimRefTimeIt = + std::find_if(lmDims.begin(), lmDims.end(), [](const LayerMetadataDim &d) -> bool { return d.serviceName.equals("reference_time") || d.serviceName.equals("forecast_reference_time"); }); + if (lmDimTimeIt == lmDims.end() || lmDimRefTimeIt == lmDims.end()) { + return 1; + } + // Find time and reference_time dimensions configuration options in the XMLE_DIMENSION list + auto xmleDimTimeIt = std::find_if(cfgDims.begin(), cfgDims.end(), [](const CServerConfig::XMLE_Dimension *d) -> bool { return d->value.equals("time"); }); + auto xmleDimRefTimeIt = + std::find_if(cfgDims.begin(), cfgDims.end(), [](const CServerConfig::XMLE_Dimension *d) -> bool { return d->value.equals("reference_time") || d->value.equals("forecast_reference_time"); }); + if (xmleDimTimeIt == cfgDims.end() || xmleDimRefTimeIt == cfgDims.end()) { + return 1; + } + + LayerMetadataDim layerMetadataTimeDim = lmDimTimeIt[0]; + LayerMetadataDim layerMetadataRefTimeDim = lmDimRefTimeIt[0]; + CServerConfig::XMLE_Dimension *layerCfgTimeDim = xmleDimTimeIt[0]; + CServerConfig::XMLE_Dimension *layerCfgRefTimeDim = xmleDimRefTimeIt[0]; + + // Time dimension references the forecast reference time dimension + if (layerCfgTimeDim->attr.defaultV.startsWith(layerCfgRefTimeDim->attr.name)) { + // Check if a duration is added, if so, try to work with this + int hasIsoDuration = layerCfgTimeDim->attr.defaultV.indexOf("+"); + if (hasIsoDuration > 0) { + CT::string isoDurationString = layerCfgTimeDim->attr.defaultV.substring(hasIsoDuration + 1, -1); + CDBDebug("Going to use isoduration [%s] to add to [%s]", isoDurationString.c_str(), layerMetadataRefTimeDim.defaultValue.c_str()); + try { + CTime *time = CTime::GetCTimeInstance(mL->dataSource->getDataObject(0)->cdfObject->getVariable("time")); + CTime::Date refTimeDate = time->freeDateStringToDate(layerMetadataRefTimeDim.defaultValue.c_str()); + CTime::Date refTimeWithAddedPeriod = time->addPeriodToDate(refTimeDate, isoDurationString); + // Assign the default value of the reference time dimension in the layer metadata to the default value of the the time dimension + lmDimTimeIt->defaultValue = time->dateToISOString(refTimeWithAddedPeriod); + } catch (int e) { + CDBWarning("Unable to parse given duration in default value of time dimension"); + } + } else { + CDBDebug("Assigning default value of reference time to time: [%s]", layerCfgTimeDim->attr.defaultV.c_str()); + // Assign the default value of the reference time dimension in the layer metadata to the default value of the the time dimension + lmDimTimeIt->defaultValue = layerMetadataRefTimeDim.defaultValue; + } + CDBDebug("New defaultvalue for time is [%s]", lmDimTimeIt->defaultValue.c_str()); + } + + return 0; +} + int getDimsForLayer(MetadataLayer *metadataLayer) { + bool verboseLog = false; #ifdef CXMLGEN_DEBUG CDBDebug("getDimsForLayer"); + verboseLog = true; +#endif +#ifdef MEASURETIME + verboseLog = true; #endif char szMaxTime[32]; char szMinTime[32]; - // char szInterval[32]; - // int hastimedomain = 0; // Dimensions if (metadataLayer->dataSource->dLayerType == CConfigReaderLayerTypeDataBase || metadataLayer->dataSource->dLayerType == CConfigReaderLayerTypeStyled) { @@ -157,11 +212,10 @@ int getDimsForLayer(MetadataLayer *metadataLayer) { return 0; } -#ifdef CXMLGEN_DEBUG - CDBDebug("Start looping dimensions"); - CDBDebug("Number of dimensions is %d", metadataLayer->dataSource->cfgLayer->Dimension.size()); -#endif - /* Auto configure dimensions */ + if (verboseLog) { + CDBDebug("Start looping dimensions. Number of dimensions is %d", metadataLayer->dataSource->cfgLayer->Dimension.size()); + } + /// Auto configure dimensions for (size_t i = 0; i < metadataLayer->dataSource->cfgLayer->Dimension.size(); i++) { /* This dimension is a filetimedate type, its values come from the modification date of the file */ @@ -179,9 +233,9 @@ int getDimsForLayer(MetadataLayer *metadataLayer) { metadataLayer->layerMetadata.dimList.push_back(dim); break; } -#ifdef CXMLGEN_DEBUG - CDBDebug("%d = %s / %s", i, metadataLayer->dataSource->cfgLayer->Dimension[i]->attr.name.c_str(), metadataLayer->dataSource->cfgLayer->Dimension[i]->value.c_str()); -#endif + if (verboseLog) { + CDBDebug("%d = %s / %s", i, metadataLayer->dataSource->cfgLayer->Dimension[i]->attr.name.c_str(), metadataLayer->dataSource->cfgLayer->Dimension[i]->value.c_str()); + } if (i == 0 && metadataLayer->dataSource->cfgLayer->Dimension[i]->attr.name.equals("none")) break; // Shorthand dimName const char *pszDimName = metadataLayer->dataSource->cfgLayer->Dimension[i]->attr.name.c_str(); @@ -231,14 +285,9 @@ int getDimsForLayer(MetadataLayer *metadataLayer) { } catch (int e) { } if (units.length() > 0) { -#ifdef CXMLGEN_DEBUG - CDBDebug("Time dimension units = %s", units.c_str()); -#endif - -#ifdef MEASURETIME - StopWatch_Stop("Get the first 100 values from the database, and determine whether the time resolution is continous or multivalue."); -#endif - + if (verboseLog) { + StopWatch_Stop("Get the first 100 values from the database, and determine whether the time resolution is continous or multivalue."); + } // Get the first 100 values from the database, and determine whether the time resolution is continous or multivalue. CDBStore::Store *store = CDBFactory::getDBAdapter(srvParam->cfg)->getUniqueValuesOrderedByValue(pszDimName, 100, true, tableName.c_str()); bool dataHasBeenFoundInStore = false; @@ -252,9 +301,6 @@ int getDimsForLayer(MetadataLayer *metadataLayer) { for (size_t j = 0; j < store->size(); j++) { store->getRecord(j)->get("time")->setChar(10, 'T'); const char *isotime = store->getRecord(j)->get("time")->c_str(); -#ifdef CXMLGEN_DEBUG - // CDBDebug("isotime = %s",isotime); -#endif CT::string year, month, day, hour, minute, second; year.copy(isotime + 0, 4); tms[j].tm_year = year.toInt() - 1900; @@ -293,9 +339,9 @@ int getDimsForLayer(MetadataLayer *metadataLayer) { yearPart.printconcat("%dY", abs(tms[1].tm_year - tms[0].tm_year)); } else { isConst = false; -#ifdef CXMLGEN_DEBUG - CDBDebug("year is irregular"); -#endif + if (verboseLog) { + CDBDebug("year is irregular"); + } } } if (tms[1].tm_mon - tms[0].tm_mon != 0) { @@ -303,9 +349,9 @@ int getDimsForLayer(MetadataLayer *metadataLayer) { yearPart.printconcat("%dM", abs(tms[1].tm_mon - tms[0].tm_mon)); else { isConst = false; -#ifdef CXMLGEN_DEBUG - CDBDebug("month is irregular"); -#endif + if (verboseLog) { + CDBDebug("month is irregular"); + } } } @@ -314,12 +360,12 @@ int getDimsForLayer(MetadataLayer *metadataLayer) { yearPart.printconcat("%dD", abs(tms[1].tm_mday - tms[0].tm_mday)); else { isConst = false; -#ifdef CXMLGEN_DEBUG - CDBDebug("day irregular"); - for (size_t j = 0; j < nrTimes; j++) { - CDBDebug("Day %d = %d", j, tms[j].tm_mday); + if (verboseLog) { + CDBDebug("day irregular"); + for (size_t j = 0; j < nrTimes; j++) { + CDBDebug("Day %d = %d", j, tms[j].tm_mday); + } } -#endif } } @@ -340,9 +386,9 @@ int getDimsForLayer(MetadataLayer *metadataLayer) { if (d > 0) { if (sd != d) { isConst = false; -#ifdef CXMLGEN_DEBUG - CDBDebug("hour/min/sec is irregular %d ", j); -#endif + if (verboseLog) { + CDBDebug("hour/min/sec is irregular %d ", j); + } } } } @@ -350,13 +396,13 @@ int getDimsForLayer(MetadataLayer *metadataLayer) { // Check whether we found a time resolution if (isConst == false) { hasMultipleValues = true; -#ifdef CXMLGEN_DEBUG - CDBDebug("Not a continous time dimension, multipleValues required"); -#endif + if (verboseLog) { + CDBDebug("Not a continous time dimension, multipleValues required"); + } } else { -#ifdef CXMLGEN_DEBUG - CDBDebug("Continous time dimension, Time resolution needs to be calculated"); -#endif + if (verboseLog) { + CDBDebug("Continous time dimension, Time resolution needs to be calculated"); + } hasMultipleValues = false; } @@ -368,9 +414,9 @@ int getDimsForLayer(MetadataLayer *metadataLayer) { iso8601timeRes.concat("T"); iso8601timeRes.concat(&hourPart); } -#ifdef CXMLGEN_DEBUG - CDBDebug("Calculated a timeresolution of %s", iso8601timeRes.c_str()); -#endif + if (verboseLog) { + CDBDebug("Calculated a timeresolution of %s", iso8601timeRes.c_str()); + } metadataLayer->dataSource->cfgLayer->Dimension[i]->attr.interval.copy(iso8601timeRes.c_str()); metadataLayer->dataSource->cfgLayer->Dimension[i]->attr.units.copy("ISO8601"); } @@ -393,7 +439,6 @@ int getDimsForLayer(MetadataLayer *metadataLayer) { if (isTimeDim) { values = CDBFactory::getDBAdapter(srvParam->cfg)->getUniqueValuesOrderedByValue(pszDimName, 0, true, tableName.c_str()); } else { - // query.print("select distinct %s,dim%s from %s order by dim%s,%s",pszDimName,pszDimName,tableName.c_str(),pszDimName,pszDimName); values = CDBFactory::getDBAdapter(srvParam->cfg)->getUniqueValuesOrderedByIndex(pszDimName, 0, true, tableName.c_str()); } @@ -403,58 +448,54 @@ int getDimsForLayer(MetadataLayer *metadataLayer) { } if (values->getSize() > 0) { - // if(srvParam->requestType==REQUEST_WMS_GETCAPABILITIES) - { - - dim.serviceName.copy(metadataLayer->dataSource->cfgLayer->Dimension[i]->value.c_str()); - dim.cdfName.copy(metadataLayer->dataSource->cfgLayer->Dimension[i]->attr.name.c_str()); - - // Try to get units from the variable - dim.units.copy("NA"); - if (metadataLayer->dataSource->cfgLayer->Dimension[i]->attr.units.empty()) { - CT::string units; - try { - metadataLayer->dataSource->getDataObject(0)->cdfObject->getVariable(dim.cdfName.c_str())->getAttribute("units")->getDataAsString(&units); - dim.units.copy(&units); - } catch (int e) { - } + dim.serviceName.copy(metadataLayer->dataSource->cfgLayer->Dimension[i]->value.c_str()); + dim.cdfName.copy(metadataLayer->dataSource->cfgLayer->Dimension[i]->attr.name.c_str()); + + // Try to get units from the variable + dim.units.copy("NA"); + if (metadataLayer->dataSource->cfgLayer->Dimension[i]->attr.units.empty()) { + CT::string units; + try { + metadataLayer->dataSource->getDataObject(0)->cdfObject->getVariable(dim.cdfName.c_str())->getAttribute("units")->getDataAsString(&units); + dim.units.copy(&units); + } catch (int e) { } + } - dim.hasMultipleValues = 1; - if (isTimeDim == true) { - dim.units.copy("ISO8601"); - for (size_t j = 0; j < values->getSize(); j++) { - // 2011-01-01T22:00:01Z - // 01234567890123456789 - values->getRecord(j)->get(0)->setChar(10, 'T'); - if (values->getRecord(j)->get(0)->length() == 19) { - values->getRecord(j)->get(0)->printconcat("Z"); - } + dim.hasMultipleValues = 1; + if (isTimeDim == true) { + dim.units.copy("ISO8601"); + for (size_t j = 0; j < values->getSize(); j++) { + // 2011-01-01T22:00:01Z + // 01234567890123456789 + values->getRecord(j)->get(0)->setChar(10, 'T'); + if (values->getRecord(j)->get(0)->length() == 19) { + values->getRecord(j)->get(0)->printconcat("Z"); } - dim.units.copy("ISO8601"); } + dim.units.copy("ISO8601"); + } - if (!metadataLayer->dataSource->cfgLayer->Dimension[i]->attr.units.empty()) { - // Units are configured in the configuration file. - dim.units.copy(metadataLayer->dataSource->cfgLayer->Dimension[i]->attr.units.c_str()); - } + if (!metadataLayer->dataSource->cfgLayer->Dimension[i]->attr.units.empty()) { + // Units are configured in the configuration file. + dim.units.copy(metadataLayer->dataSource->cfgLayer->Dimension[i]->attr.units.c_str()); + } - const char *pszDefaultV = metadataLayer->dataSource->cfgLayer->Dimension[i]->attr.defaultV.c_str(); - CT::string defaultV; - if (pszDefaultV != NULL) defaultV = pszDefaultV; + const char *pszDefaultV = metadataLayer->dataSource->cfgLayer->Dimension[i]->attr.defaultV.c_str(); + CT::string defaultV; + if (pszDefaultV != NULL) defaultV = pszDefaultV; - if (defaultV.length() == 0 || defaultV.equals("max", 3)) { - dim.defaultValue.copy(values->getRecord(values->getSize() - 1)->get(0)->c_str()); - } else if (defaultV.equals("min", 3)) { - dim.defaultValue.copy(values->getRecord(0)->get(0)->c_str()); - } else { - dim.defaultValue.copy(&defaultV); - } + if (defaultV.length() == 0 || defaultV.equals("max", 3)) { + dim.defaultValue.copy(values->getRecord(values->getSize() - 1)->get(0)->c_str()); + } else if (defaultV.equals("min", 3)) { + dim.defaultValue.copy(values->getRecord(0)->get(0)->c_str()); + } else { + dim.defaultValue.copy(&defaultV); + } - dim.values.copy(values->getRecord(0)->get(0)); - for (size_t j = 1; j < values->getSize(); j++) { - dim.values.printconcat(",%s", values->getRecord(j)->get(0)->c_str()); - } + dim.values.copy(values->getRecord(0)->get(0)); + for (size_t j = 1; j < values->getSize(); j++) { + dim.values.printconcat(",%s", values->getRecord(j)->get(0)->c_str()); } } delete values; @@ -485,67 +526,42 @@ int getDimsForLayer(MetadataLayer *metadataLayer) { } delete values; - // Retrieve all values for time position - // if(srvParam->serviceType==SERVICE_WCS){ - - /* - query.print("select %s from %s",dimName,tableName.c_str()); - values = DB.query_select(query.c_str(),0); - if(values == NULL){CDBError("Query failed");DB.close();return 1;} - if(values->count>0){ - if(TimePositions!=NULL){ - delete[] TimePositions; - TimePositions=NULL; - } - TimePositions=new CT::string[values->count]; - char szTemp[32]; - for(size_t l=0;lcount;l++){ - snprintf(szTemp,31,"%s",values[l].c_str());szTemp[10]='T'; - TimePositions[l].copy(szTemp); - TimePositions[l].count=values[l].count; - } - } - delete[] values;*/ - if (metadataLayer->dataSource->cfgLayer->Dimension[i]->attr.interval.empty()) { // TODO CDBError("Dimension interval '%d' not defined", i); return 1; } - // strncpy(szInterval,metadataLayer->dataSource->cfgLayer->Dimension[i]->attr.interval.c_str(),32);szInterval[31]='\0'; + const char *pszInterval = metadataLayer->dataSource->cfgLayer->Dimension[i]->attr.interval.c_str(); - // hastimedomain = 1; - // if(srvParam->requestType==REQUEST_WMS_GETCAPABILITIES) - { - CT::string dimUnits("ISO8601"); - if (metadataLayer->dataSource->cfgLayer->Dimension[i]->attr.units.empty() == false) { - dimUnits.copy(metadataLayer->dataSource->cfgLayer->Dimension[i]->attr.units.c_str()); - } - dim.serviceName.copy(metadataLayer->dataSource->cfgLayer->Dimension[i]->value.c_str()); - dim.cdfName.copy(metadataLayer->dataSource->cfgLayer->Dimension[i]->attr.name.c_str()); - dim.units.copy(dimUnits.c_str()); - dim.hasMultipleValues = 0; - // metadataLayer->dataSource->cfgLayer->Dimension[i]->attr.defaultV.c_str() - const char *pszDefaultV = metadataLayer->dataSource->cfgLayer->Dimension[i]->attr.defaultV.c_str(); - CT::string defaultV; - if (pszDefaultV != NULL) defaultV = pszDefaultV; - if (defaultV.length() == 0 || defaultV.equals("max", 3)) { - dim.defaultValue.copy(szMaxTime); - } else if (defaultV.equals("min", 3)) { - dim.defaultValue.copy(szMinTime); - } else { - dim.defaultValue.copy(&defaultV); - } - if (dim.defaultValue.length() == 19) { - dim.defaultValue.concat("Z"); - } - CT::string minTime = szMinTime; - if (minTime.equals(szMaxTime)) { - dim.values.print("%s", szMinTime); - } else { - dim.values.print("%s/%s/%s", szMinTime, szMaxTime, pszInterval); - } + CT::string dimUnits("ISO8601"); + if (metadataLayer->dataSource->cfgLayer->Dimension[i]->attr.units.empty() == false) { + dimUnits.copy(metadataLayer->dataSource->cfgLayer->Dimension[i]->attr.units.c_str()); + } + dim.serviceName.copy(metadataLayer->dataSource->cfgLayer->Dimension[i]->value.c_str()); + dim.cdfName.copy(metadataLayer->dataSource->cfgLayer->Dimension[i]->attr.name.c_str()); + dim.units.copy(dimUnits.c_str()); + dim.hasMultipleValues = 0; + // metadataLayer->dataSource->cfgLayer->Dimension[i]->attr.defaultV.c_str() + const char *pszDefaultV = metadataLayer->dataSource->cfgLayer->Dimension[i]->attr.defaultV.c_str(); + CT::string defaultV; + if (pszDefaultV != NULL) defaultV = pszDefaultV; + if (defaultV.length() == 0 || defaultV.equals("max", 3)) { + dim.defaultValue.copy(szMaxTime); + } else if (defaultV.equals("min", 3)) { + dim.defaultValue.copy(szMinTime); + } else { + dim.defaultValue.copy(&defaultV); + } + if (dim.defaultValue.length() == 19) { + dim.defaultValue.concat("Z"); + } + + CT::string minTime = szMinTime; + if (minTime.equals(szMaxTime)) { + dim.values.print("%s", szMinTime); + } else { + dim.values.print("%s/%s/%s", szMinTime, szMaxTime, pszInterval); } } @@ -562,6 +578,8 @@ int getDimsForLayer(MetadataLayer *metadataLayer) { } metadataLayer->layerMetadata.dimList.push_back(dim); } + // Check dependencies between dimensions + checkDependenciesBetweenDims(metadataLayer); } return 0; From 95490cf130feaf9db934c595ecfbfae52a757cca Mon Sep 17 00:00:00 2001 From: Maarten Plieger Date: Mon, 23 Dec 2024 13:01:48 +0100 Subject: [PATCH 2/3] Added tests --- ...fault_time_referenced_to_forecast_time.xml | 64 +++++ tests/AdagucTests/TestWMS.py | 34 +++ ...fault_time_referenced_to_forecast_time.xml | 221 ++++++++++++++++++ 3 files changed, 319 insertions(+) create mode 100644 data/config/datasets/adaguc.tests.403_default_time_referenced_to_forecast_time.xml create mode 100644 tests/expectedoutputs/TestWMS/test_WMSGetCapabilities_403_default_time_referenced_to_forecast_time.xml diff --git a/data/config/datasets/adaguc.tests.403_default_time_referenced_to_forecast_time.xml b/data/config/datasets/adaguc.tests.403_default_time_referenced_to_forecast_time.xml new file mode 100644 index 00000000..96f0fe53 --- /dev/null +++ b/data/config/datasets/adaguc.tests.403_default_time_referenced_to_forecast_time.xml @@ -0,0 +1,64 @@ + + + + + + time_default_min + time_default_min + air-temperature-pl + + {ADAGUC_PATH}data/datasets/ha43_dini/ + temperature_wow + reference_time + + time + + + + time_default_max + time_default_max + air-temperature-pl + + {ADAGUC_PATH}data/datasets/ha43_dini/ + temperature_wow + reference_time + + time + + + + + time_default_forecast_reference_time + time_default_forecast_reference_time + air-temperature-pl + + {ADAGUC_PATH}data/datasets/ha43_dini/ + temperature_wow + reference_time + + + time + + + + + + time_default_forecast_reference_time_and_duration + time_default_forecast_reference_time_and_duration + air-temperature-pl + + {ADAGUC_PATH}data/datasets/ha43_dini/ + temperature_wow + reference_time + + time + + + + + \ No newline at end of file diff --git a/tests/AdagucTests/TestWMS.py b/tests/AdagucTests/TestWMS.py index 2f3fbe9d..7f2b3d8c 100644 --- a/tests/AdagucTests/TestWMS.py +++ b/tests/AdagucTests/TestWMS.py @@ -2598,3 +2598,37 @@ def test_WMSGetLegendGraphic_SolarTerminator(self): data.getvalue(), AdagucTestTools().readfromfile(self.expectedoutputsspath + filename)) + + + + def test_WMSGetCapabilities_403_default_time_referenced_to_forecast_time(self): + """ + See https://github.com/KNMI/adaguc-server/issues/403 + """ + AdagucTestTools().cleanTempDir() + + config = ( + ADAGUC_PATH + + "/data/config/adaguc.tests.dataset.xml," + + ADAGUC_PATH + + "/data/config/datasets/adaguc.tests.403_default_time_referenced_to_forecast_time.xml" + ) + # pylint: disable=unused-variable + status, data, headers = AdagucTestTools().runADAGUCServer( + args=["--updatedb", "--config", config], env=self.env, isCGI=False + ) + self.assertEqual(status, 0) + + filename = "test_WMSGetCapabilities_403_default_time_referenced_to_forecast_time.xml" + # pylint: disable=unused-variable + status, data, headers = AdagucTestTools().runADAGUCServer( + "dataset=adaguc.tests.403_default_time_referenced_to_forecast_time&service=WMS&request=GetCapabilities", + {"ADAGUC_CONFIG": ADAGUC_PATH + "/data/config/adaguc.tests.dataset.xml"}, + ) + AdagucTestTools().writetofile(self.testresultspath + filename, data.getvalue()) + self.assertEqual(status, 0) + self.assertTrue( + AdagucTestTools().compareGetCapabilitiesXML( + self.testresultspath + filename, self.expectedoutputsspath + filename + ) + ) diff --git a/tests/expectedoutputs/TestWMS/test_WMSGetCapabilities_403_default_time_referenced_to_forecast_time.xml b/tests/expectedoutputs/TestWMS/test_WMSGetCapabilities_403_default_time_referenced_to_forecast_time.xml new file mode 100644 index 00000000..8ca21cd4 --- /dev/null +++ b/tests/expectedoutputs/TestWMS/test_WMSGetCapabilities_403_default_time_referenced_to_forecast_time.xml @@ -0,0 +1,221 @@ + + + + WMS + adaguc.tests.403_default_time_referenced_to_forecast_time + This service demonstrates how the ADAGUC server can be used to create OGC services. + + view + infoMapAccessService + ADAGUCServer version 2.29.0, of Dec 23 2024 12:46:01 + + + + + + no conditions apply + None + 8192 + 8192 + + + + + text/xml + + + + image/png + image/png;mode=8bit + image/png;mode=8bit_noalpha + image/png;mode=24bit + image/png;mode=32bit + image/gif + image/jpeg + + + + + image/png + text/plain + text/html + text/xml + application/json + + + + + XML + INIMAGE + BLANK + + + +WMS of adaguc.tests.403_default_time_referenced_to_forecast_time +CRS:84 +EPSG:25831 +EPSG:25832 +EPSG:28992 +EPSG:3067 +EPSG:32661 +EPSG:3411 +EPSG:3412 +EPSG:3575 +EPSG:3857 +EPSG:40000 +EPSG:4258 +EPSG:4326 +EPSG:50001 +EPSG:54030 +EPSG:7399 +EPSG:900913 +PROJ4:%2Bproj%3Dob_tran%20%2Bo_proj%3Dlonglat%20%2Blon_0%3D%2D8%2E0%20%2Bo_lat_p%3D35%2E0%20%2Bo_lon_p%3D0%2E0%20%2Ba%3D6367470%20%2Be%3D0%20%2Bno_defs + + + + + + + + + + + + + + + + + + + +time_default_min +time_default_min + + -5.197559 + 19.363445 + 41.926322 + 59.916479 + + + + + + + + + + + + + + + + + + +2024-07-11T03:00:00Z/2024-07-13T17:00:00Z/PT1H +2024-07-11T02:00:00Z,2024-07-11T03:00:00Z,2024-07-11T04:00:00Z,2024-07-11T05:00:00Z +500,700,850,925 + + +time_default_max +time_default_max + + -5.197559 + 19.363445 + 41.926322 + 59.916479 + + + + + + + + + + + + + + + + + + +2024-07-11T03:00:00Z/2024-07-13T17:00:00Z/PT1H +2024-07-11T02:00:00Z,2024-07-11T03:00:00Z,2024-07-11T04:00:00Z,2024-07-11T05:00:00Z +500,700,850,925 + + +time_default_forecast_reference_time +time_default_forecast_reference_time + + -5.197559 + 19.363445 + 41.926322 + 59.916479 + + + + + + + + + + + + + + + + + + +2024-07-11T03:00:00Z/2024-07-13T17:00:00Z/PT1H +2024-07-11T02:00:00Z,2024-07-11T03:00:00Z,2024-07-11T04:00:00Z,2024-07-11T05:00:00Z +500,700,850,925 + + +time_default_forecast_reference_time_and_duration +time_default_forecast_reference_time_and_duration + + -5.197559 + 19.363445 + 41.926322 + 59.916479 + + + + + + + + + + + + + + + + + + +2024-07-11T03:00:00Z/2024-07-13T17:00:00Z/PT1H +2024-07-11T02:00:00Z,2024-07-11T03:00:00Z,2024-07-11T04:00:00Z,2024-07-11T05:00:00Z +500,700,850,925 + + + + From fbf16eb16e026dc351e22fd7b4d28bcec643e944 Mon Sep 17 00:00:00 2001 From: Maarten Plieger Date: Mon, 23 Dec 2024 13:08:30 +0100 Subject: [PATCH 3/3] Updated version and documentation --- Dockerfile | 2 +- NEWS.md | 3 +++ adagucserverEC/Definitions.h | 2 +- doc/configuration/Dimension.md | 15 ++++++++++----- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2df93d22..b30dd5f4 100755 --- a/Dockerfile +++ b/Dockerfile @@ -6,7 +6,7 @@ USER root LABEL maintainer="adaguc@knmi.nl" # Version should be same as in Definitions.h -LABEL version="2.29.0" +LABEL version="2.29.1" # Try to update image packages RUN apt-get -q -y update \ diff --git a/NEWS.md b/NEWS.md index f1d3f097..fe7c7413 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,6 @@ +**Version 2.29.1 2024-12-23** +- Default value for time dimension can now be based on default value of reference_time dimension (Issue #403) + **Version 2.29.0 2024-11-11** - Adds support for grids where the data cells are defined by lat_bnds and lon_bnds parameters describing the cell bounds. diff --git a/adagucserverEC/Definitions.h b/adagucserverEC/Definitions.h index 0ea28fd1..0ee1b13a 100755 --- a/adagucserverEC/Definitions.h +++ b/adagucserverEC/Definitions.h @@ -28,7 +28,7 @@ #ifndef Definitions_H #define Definitions_H -#define ADAGUCSERVER_VERSION "2.29.0" // Please also update in the Dockerfile to the same version +#define ADAGUCSERVER_VERSION "2.29.1" // Please also update in the Dockerfile to the same version // CConfigReaderLayerType #define CConfigReaderLayerTypeUnknown 0 diff --git a/doc/configuration/Dimension.md b/doc/configuration/Dimension.md index abde0a2c..9ce29203 100644 --- a/doc/configuration/Dimension.md +++ b/doc/configuration/Dimension.md @@ -6,9 +6,7 @@ Back to [Configuration](./Configuration.md) - name - The name of the dimension in the netcdf file - interval - Optional, the time resolution of the dataset in [ISO8601](ISO8601.md) format. -- default - The default value of the dimension in [ISO8601](ISO8601.md) - format, can also be "min" or "max" to select the first or latest - date as default. Defaults to "max". +- default - Defaults to "max". See details below - units - Override the units of the dimension - quantizeperiod - Optional, see below - quantizemethod - Optional, see below @@ -25,8 +23,15 @@ Back to [Configuration](./Configuration.md) - See [ISO8601](../info/ISO8601.md) for the time resolution specification -Time quantization ------------------ +## default value + +- The default value of the dimension can be specified as datestring in [ISO8601](ISO8601.md) format +- Can be "min" or "max" to select the first or latest +- Can be set to "forecast_reference_time" to reference the default value of the forecast_reference_time dimension. +- Can be set to "forecast_reference_time+PT1H" to reference the default value of the forecast_reference_time dimension, and it will add a ISO8601 Period to the derived value. See test [data/config/datasets/adaguc.tests.403_default_time_referenced_to_forecast_time.xml](../../data/config/datasets/adaguc.tests.403_default_time_referenced_to_forecast_time.xml) for details. + + +## Time quantization Time values received in the URL as input can be rounded to more discrete time periods. For example when noon, 12:03:53, is received as input, it