diff --git a/CMakeLists.txt b/CMakeLists.txt index c6cd2847..2d4472ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,6 +50,7 @@ add_executable(geojsondump ./adagucserverEC/geojsondump.cpp) add_test(testhclasses hclasses/testhclasses) add_test(testadagucserver adagucserverEC/testadagucserver) +add_test(testtimeutils adagucserverEC/testtimeutils) target_link_libraries(adagucserver adagucserverEC hclasses CCDFDataModel) target_link_libraries(h5ncdump adagucserverEC hclasses CCDFDataModel) diff --git a/adagucserverEC/CMakeLists.txt b/adagucserverEC/CMakeLists.txt index 69b234c7..a9b86652 100644 --- a/adagucserverEC/CMakeLists.txt +++ b/adagucserverEC/CMakeLists.txt @@ -196,6 +196,9 @@ add_library( Types/ProjectionStore.h Types/ProjectionStore.cpp testadagucserver.cpp + testtimeutils.cpp + timeutils.cpp + timeutils.h ) target_include_directories(adagucserverEC PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${Cairo_INCLUDE_DIRS} ${FREETYPE_INCLUDE_DIRS} ${PostgreSQL_INCLUDE_DIRS} ${GDAL_INCLUDE_DIRS} ${PROJ_INCLUDE_DIR}) @@ -204,3 +207,7 @@ target_link_libraries(adagucserverEC CCDFDataModel hclasses ${NetCDF_LIBRARIES} # Build unit test executable add_executable(testadagucserver testadagucserver.cpp) target_link_libraries(testadagucserver PRIVATE adagucserverEC CCDFDataModel hclasses CppUnitLite) + +# Build unit tests for timeutils +add_executable(testtimeutils testtimeutils.cpp) +target_link_libraries(testtimeutils PRIVATE adagucserverEC hclasses CppUnitLite) \ No newline at end of file diff --git a/adagucserverEC/CXMLGen.cpp b/adagucserverEC/CXMLGen.cpp index ebd21a80..cc48f0cd 100644 --- a/adagucserverEC/CXMLGen.cpp +++ b/adagucserverEC/CXMLGen.cpp @@ -25,10 +25,12 @@ #include #include +#include #include #include "CXMLGen.h" #include "CDBFactory.h" #include "LayerTypeLiveUpdate/LayerTypeLiveUpdate.h" +#include "timeutils.h" #include #include "utils/LayerMetadataStore.h" #include "utils/XMLGenUtils.h" @@ -775,6 +777,79 @@ int CXMLGen::getWCS_1_0_0_Capabilities(CT::string *XMLDoc, std::vectorlayerMetadata.dimList.size()) { + return; + } + XMLDoc->concat(" \n" + " \n" + " dimensions\n" + " \n"); + // Dims + for (size_t d = 0; d < layer->layerMetadata.dimList.size(); d++) { + LayerMetadataDim *dim = &layer->layerMetadata.dimList[d]; + CT::string min, max, duration; + CT::string *valueSplit; + std::vector valuesVector; + + // Case of min/max(/duration), for time dimension + valueSplit = dim->values.splitToArray("/"); + if (valueSplit->count >= 2) { + min = valueSplit[0]; + max = valueSplit[1]; + // Third value is the interval duration + if (valueSplit->count == 3) { + duration = valueSplit[2]; + } + } else { + // General case of a list of values (of any type) + valueSplit = dim->values.splitToArray(","); + valuesVector = std::vector(valueSplit, valueSplit + valueSplit->count); + std::sort(valuesVector.begin(), valuesVector.end(), multiTypeSort); + min = valuesVector[0]; + max = valuesVector.back(); + } + + XMLDoc->printconcat(" \n" + " \n" + " %s\n" + " \n", + dim->cdfName.c_str(), dim->cdfName.c_str()); + if (valueSplit->count >= 2) { + XMLDoc->printconcat(" \n" + " \n" + " %s\n" + " %s\n", + min.c_str(), max.c_str()); + // Precalculate the interval in the case of time (no interval if fewer than 4 values) + if ((dim->cdfName.indexOf("time") != -1) && duration.length() > 0) { + XMLDoc->printconcat(" %s\n", duration.c_str()); // .c_str()); + } + XMLDoc->printconcat(" \n"); + // Print all possible values if there is a relatively small number, for other dimensions + if ((valueSplit->count <= 100) && (dim->cdfName.indexOf("time") == -1)) { + for (size_t i = 0; i < valueSplit->count; i++) { + XMLDoc->printconcat(" %s\n", valuesVector[i].c_str()); + } + } + XMLDoc->printconcat(" \n"); + } + XMLDoc->printconcat(" \n" + " \n"); + delete[] valueSplit; + } + + XMLDoc->concat(" \n" + " \n"); +} + int CXMLGen::getWCS_1_0_0_DescribeCoverage(CT::string *XMLDoc, std::vector *metadataLayerList) { XMLDoc->copy("\n" @@ -902,22 +977,9 @@ int CXMLGen::getWCS_1_0_0_DescribeCoverage(CT::string *XMLDoc, std::vectorconcat(" \n"); } - XMLDoc->concat(" \n" - " \n" - " \n" - " bands\n" - " \n" - " \n" - " \n" - " bands\n" - " \n" - " \n" - " 1\n" - " \n" - " \n" - " \n" - " \n" - " \n"); + XMLDoc->concat(" \n"); + // Generate the XML code for RangeSet, including dimensions (AxisDescriptions) + generateWCSRangeSet(XMLDoc, layer); // Supported CRSs XMLDoc->concat(" \n"); diff --git a/adagucserverEC/testtimeutils.cpp b/adagucserverEC/testtimeutils.cpp new file mode 100644 index 00000000..ccae3f69 --- /dev/null +++ b/adagucserverEC/testtimeutils.cpp @@ -0,0 +1,103 @@ +/****************************************************************************** + * + * Copyright 2024, Royal Netherlands Meteorological Institute (KNMI) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#include "CDebugger.h" +#include "CppUnitLite/TestHarness.h" +#include "CTString.h" +#include "timeutils.h" + +TEST(CalculateTimeInterval, TimeUtils) { + CTime::Date start = {}; + start.minute = 30; + start.hour = 15; + start.day = 29; + start.month = 8; + start.year = 2024; + start.second = 0.0; + + CTime::Date end = {}; + end.second = 45.0; + end.minute = 45; + end.hour = 16; + end.day = 29; + end.month = 8; + end.year = 2025; + + TimeInterval expected = {1, 0, 0, 1, 15, 45}; + TimeInterval result = calculateTimeInterval(start, end); + + CHECK(result.years == expected.years); + CHECK(result.months == expected.months); + CHECK(result.days == expected.days); + CHECK(result.hours == expected.hours); + CHECK(result.minutes == expected.minutes); + CHECK(result.seconds == expected.seconds); +} + +TEST(ToISO8601Interval, TimeUtils) { + TimeInterval interval = {1, 2, 10, 5, 30, 45}; + CT::string expected("P1Y2M10DT5H30M45S"); + + CT::string result = toISO8601Interval(interval); + CHECK(result == expected); +} + +TEST(ToSeconds, TimeUtils) { + TimeInterval interval = {0, 1, 0, 1, 0, 20}; // 1 month, 1 hour, 20 seconds + long expected = 2595620; + + long result = interval.toSeconds(); + CHECK(result == expected); +} + +TEST(EstimateISO8601Duration, TimeUtils) { + // Most straightforward case + std::vector timestamps = {"2024-07-29T15:30:45Z", "2024-07-29T16:30:45Z", "2024-07-29T17:30:45Z", "2024-07-29T18:30:45Z"}; + CT::string expected("PT1H"); + CT::string result = estimateISO8601Duration(timestamps); + std::cout << "Result: " << result << "\n"; + CHECK(result == expected); + + // Case with one timestep missing + std::vector timestamps_with_gap = {"2024-07-29T15:30:45Z", "2024-07-29T16:30:45Z", "2024-07-29T18:30:45Z", "2024-07-29T19:30:45Z", + "2024-07-29T20:30:45Z", "2024-07-29T21:30:45Z", "2024-07-29T22:30:45Z", "2024-07-29T23:30:45Z"}; + CT::string expected_with_gap("PT1H"); + CT::string result_with_gap = estimateISO8601Duration(timestamps_with_gap); + CHECK(result_with_gap == expected_with_gap); + + // Case in February of a leap year + std::vector leap_year_timestamps = {"2024-02-28T23:30:45Z", "2024-02-29T00:30:45Z", "2024-02-29T01:30:45Z", "2024-02-29T02:30:45Z"}; + CT::string expected_leap_year("PT1H"); + CT::string result_leap_year = estimateISO8601Duration(leap_year_timestamps); + CHECK(result_leap_year == expected_leap_year); + + // Case of a complex interval (5 days and 10 hours) + std::vector complex_interval_timestamps = {"2024-07-01T08:00:00Z", "2024-07-06T18:00:00Z", "2024-07-12T04:00:00Z", "2024-07-17T14:00:00Z", "2024-07-23T00:00:00Z"}; + CT::string expected_complex_interval("P5DT10H"); + CT::string result_complex_interval = estimateISO8601Duration(complex_interval_timestamps); + CHECK(result_complex_interval == expected_complex_interval); +} + +int main() { + TestResult tr; + TestRegistry::runAllTests(tr); + if (tr.failureCount != 0) { + return 1; + } + return 0; +} diff --git a/adagucserverEC/timeutils.cpp b/adagucserverEC/timeutils.cpp new file mode 100644 index 00000000..955fb892 --- /dev/null +++ b/adagucserverEC/timeutils.cpp @@ -0,0 +1,157 @@ +/****************************************************************************** + * + * Copyright 2024, Royal Netherlands Meteorological Institute (KNMI) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#include +#include "timeutils.h" + +TimeInterval calculateTimeInterval(const CTime::Date &start, const CTime::Date &end) { + TimeInterval interval = {0, 0, 0, 0, 0, 0}; + + interval.seconds = int(end.second - start.second); + interval.minutes = end.minute - start.minute; + interval.hours = end.hour - start.hour; + interval.days = end.day - start.day; + interval.months = end.month - start.month; + interval.years = end.year - start.year; + + // Adjust number of minutes if there are negative seconds, + // meaning there were less than 60 seconds between timestamps. + if (interval.seconds < 0) { + interval.seconds += 60.0; + interval.minutes--; + } + // Adjust number of hours if there are negative minutes, + // meaning there were less than 60 minutes between timestamps. + if (interval.minutes < 0) { + interval.minutes += 60; + interval.hours--; + } + // Adjust number of days if there are negative hours, + // meaning there were less than 24 hours between timestamps. + if (interval.hours < 0) { + interval.hours += 24; + interval.days--; + } + // Adjust number of days and months using month length + // and leap year calculations, also adjust in case of + // negative days. + if (interval.days < 0) { + // Take month length into consideration (month 1 being January and 12 December) + static const int daysInMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + int previousMonth = (end.month == 1) ? 12 : end.month - 1; + int year = (end.month == 1) ? end.year - 1 : end.year; + + // Adjust for leap years, using the following rules: + // - In general, a year is a leap year if divisible by 4 + // - In general, end-of-century years (divisible by 100) are NOT + // - But if divisible by 400, it IS a leap year + int daysPrevMonth = daysInMonth[previousMonth - 1]; + if (previousMonth == 2 && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)) { + daysPrevMonth = 29; + } + interval.days += daysPrevMonth; + interval.months--; + } + if (interval.months < 0) { + interval.months += 12; + interval.years--; + } + + return interval; +} + +CT::string toISO8601Interval(const TimeInterval &interval) { + // Start with the period 'P' + CT::string result("P"); + + // Append years, months, or days if present + if (interval.years > 0) { + result.printconcat("%dY", interval.years); + } + if (interval.months > 0) { + result.printconcat("%dM", interval.months); + } + if (interval.days > 0) { + result.printconcat("%dD", interval.days); + } + + // Add hour part T if there are hours, minutes, or seconds + if (interval.hours > 0 || interval.minutes > 0 || interval.seconds > 0) { + result += "T"; + + if (interval.hours > 0) { + result.printconcat("%dH", interval.hours); + } + if (interval.minutes > 0) { + result.printconcat("%dM", interval.minutes); + } + if (interval.seconds > 0) { + result.printconcat("%dS", interval.seconds); + } + } + return result; +} + +// Heuristic estimation of duration in ISO8601 format, given an array of timestamps +// Checks that a consistent interval is (generally found), with room for inaccuracies (holes in data) +// controlled by the threshold argument. +CT::string estimateISO8601Duration(const std::vector ×tamps, double threshold) { + // Size considered too small to find a pattern + if (timestamps.size() < 4) return CT::string(""); + + std::vector intervals; + CTime ctime; + ctime.init("seconds since 1970", NULL); + + // Parse all timestamps into tm structs + std::vector parsedTimes; + for (const auto ×tamp : timestamps) { + parsedTimes.push_back(ctime.ISOStringToDate(timestamp.c_str())); + } + + // Calculate intervals between consecutive timestamps + for (size_t i = 1; i < parsedTimes.size(); ++i) { + intervals.push_back(calculateTimeInterval(parsedTimes[i - 1], parsedTimes[i])); + } + + TimeInterval smallestInterval = *std::min_element(intervals.begin(), intervals.end()); + + // Count occurrences of each interval in terms of total seconds + std::map intervalFrequency; + for (const auto &interval : intervals) { + intervalFrequency[interval]++; + } + + // Sort each pair by number of occurrences + const std::pair &mostFrequentIntervalInfo = + *std::max_element(intervalFrequency.begin(), intervalFrequency.end(), [](const std::pair &a, const std::pair &b) { return a.second < b.second; }); + + TimeInterval mostFrequentInterval = mostFrequentIntervalInfo.first; + + // If the smallest interval is not the most frequent, we do not have a regular interval + if (!(smallestInterval == mostFrequentInterval)) return ""; + + // Otherwise, it is possible we have some missing data. Check if frequency is over threshold + if ((double(mostFrequentIntervalInfo.second) / double(timestamps.size() - 1)) >= threshold) { + // We return the interval corresponding to this estimation + return toISO8601Interval(mostFrequentInterval); + } + + // No estimation possible + return ""; +} diff --git a/adagucserverEC/timeutils.h b/adagucserverEC/timeutils.h new file mode 100644 index 00000000..11cf0dfb --- /dev/null +++ b/adagucserverEC/timeutils.h @@ -0,0 +1,59 @@ +/****************************************************************************** + * + * Copyright 2024, Royal Netherlands Meteorological Institute (KNMI) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#include "CTString.h" +#include "CTime.h" +#include +#include + +// Type to represent the relative interval between two timestamps +struct TimeInterval { + int years; + int months; + int days; + int hours; + int minutes; + int seconds; + + // Function to convert the interval to approximate total seconds + long long toSeconds() const { return seconds + minutes * 60 + hours * 3600 + days * 86400 + months * 2592000 + years * 31536000; } + + // < operator based on total seconds + bool operator<(const TimeInterval &other) const { return this->toSeconds() < other.toSeconds(); }; + + // Equality operator + bool operator==(const TimeInterval &other) const { + return years == other.years && months == other.months && days == other.days && hours == other.hours && minutes == other.minutes && seconds == other.seconds; + } + + std::string toString() const { + std::ostringstream oss; + if (years > 0) oss << years << " year(s) "; + if (months > 0) oss << months << " month(s) "; + if (days > 0) oss << days << " day(s) "; + if (hours > 0) oss << hours << " hour(s) "; + if (minutes > 0) oss << minutes << " minute(s) "; + if (seconds > 0 || (years == 0 && months == 0 && days == 0 && hours == 0 && minutes == 0)) oss << seconds << " second(s)"; + + return oss.str(); + } +}; + +struct TimeInterval calculateTimeInterval(const CTime::Date &start, const CTime::Date &end); +CT::string toISO8601Interval(const TimeInterval &interval); +CT::string estimateISO8601Duration(const std::vector ×tamps, double threshold = 0.8); diff --git a/adagucserverEC/utils/XMLGenUtils.cpp b/adagucserverEC/utils/XMLGenUtils.cpp index 5b29ce9c..e4926896 100644 --- a/adagucserverEC/utils/XMLGenUtils.cpp +++ b/adagucserverEC/utils/XMLGenUtils.cpp @@ -5,6 +5,7 @@ #include #include #include "LayerUtils.h" +#include int populateMetadataLayerStruct(MetadataLayer *metadataLayer, bool readFromDB) { metadataLayer->readFromDb = readFromDB; @@ -834,3 +835,32 @@ int getFileNameForLayer(MetadataLayer *metadataLayer) { return 0; } + +// Function to parse a string to double if numeric +double parseNumeric(std::string const &str, bool &isNumeric) { + auto result = double(); + auto i = std::istringstream(str); + i >> result; + isNumeric = !i.fail() && i.eof(); + return result; +} + +// Sort values that can either be numeric of a string +bool multiTypeSort(const CT::string &a, const CT::string &b) { + // Try to convert strings to numbers + float aNum, bNum; + bool isANum, isBNum; + + isANum = false; + aNum = parseNumeric(a.c_str(), isANum); + + isBNum = false; + bNum = parseNumeric(b.c_str(), isBNum); + + // Do numerical comparison or alphabetical comparison according to type + if (isANum && isBNum) { + return aNum < bNum; + } else { + return a < b; + } +} diff --git a/adagucserverEC/utils/XMLGenUtils.h b/adagucserverEC/utils/XMLGenUtils.h index de97d2b5..85aab7c5 100644 --- a/adagucserverEC/utils/XMLGenUtils.h +++ b/adagucserverEC/utils/XMLGenUtils.h @@ -12,4 +12,5 @@ bool compareDim(const LayerMetadataDim &p1, const LayerMetadataDim &p2); int populateMetadataLayerStruct(MetadataLayer *metadataLayer, bool readFromDb); int getTitleForLayer(MetadataLayer *metadataLayer); int getFileNameForLayer(MetadataLayer *metadataLayer); +bool multiTypeSort(const CT::string &a, const CT::string &b); #endif \ No newline at end of file diff --git a/data/datasets/large_number_timesteps/210_2day_timesteps_5_heights.nc b/data/datasets/large_number_timesteps/210_2day_timesteps_5_heights.nc new file mode 100644 index 00000000..8b7790b6 Binary files /dev/null and b/data/datasets/large_number_timesteps/210_2day_timesteps_5_heights.nc differ diff --git a/data/datasets/large_number_timesteps/210_daily_timesteps.nc b/data/datasets/large_number_timesteps/210_daily_timesteps.nc new file mode 100644 index 00000000..c05f195f Binary files /dev/null and b/data/datasets/large_number_timesteps/210_daily_timesteps.nc differ diff --git a/data/datasets/large_number_timesteps/210_random_timesteps.nc b/data/datasets/large_number_timesteps/210_random_timesteps.nc new file mode 100644 index 00000000..1383373b Binary files /dev/null and b/data/datasets/large_number_timesteps/210_random_timesteps.nc differ diff --git a/data/datasets/large_number_timesteps/99_2day_timesteps.nc b/data/datasets/large_number_timesteps/99_2day_timesteps.nc new file mode 100644 index 00000000..fc8f7844 Binary files /dev/null and b/data/datasets/large_number_timesteps/99_2day_timesteps.nc differ diff --git a/python/lib/adaguc/AdagucTestTools.py b/python/lib/adaguc/AdagucTestTools.py index 8fc7622c..2e8678d0 100644 --- a/python/lib/adaguc/AdagucTestTools.py +++ b/python/lib/adaguc/AdagucTestTools.py @@ -324,6 +324,20 @@ def removeBBOX(root): removeBBOX(obj1) removeBBOX(obj2) + # Remove contents of problem envelopes EPSG:28992 and EPSG:7399 because they are inconsistent + def removeGmlEnvelope(root, epsg_code): + xpath_query = f".//gml:Envelope[@srsName='EPSG:{epsg_code}']" + envelopes = root.xpath( + xpath_query, namespaces={"gml": "http://www.opengis.net/gml"}) + for envelope in envelopes: + for child in envelope.getchildren(): + envelope.remove(child) + + removeGmlEnvelope(obj1, "28992") + removeGmlEnvelope(obj2, "28992") + removeGmlEnvelope(obj1, "7399") + removeGmlEnvelope(obj2, "7399") + result = etree.tostring(obj1) expect = etree.tostring(obj2) diff --git a/requirements.in b/requirements.in index 8ecf8bab..f1748d70 100644 --- a/requirements.in +++ b/requirements.in @@ -15,7 +15,7 @@ cachetools~=5.3 cftime~=1.6 chardet~=5.2 defusedxml~=0.7.1 -fastapi~=0.109.1 +fastapi~=0.115.2 geojson-pydantic~=1.0 gunicorn~=22.0 httpx~=0.26.0 diff --git a/requirements.txt b/requirements.txt index c63e797e..72ff83ef 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ # -# This file is autogenerated by pip-compile with Python 3.10 +# This file is autogenerated by pip-compile with Python 3.11 # by the following command: # # pip-compile --no-emit-index-url @@ -18,8 +18,6 @@ asgi-logger==0.1.0 # via -r requirements.in asgiref==3.8.1 # via asgi-logger -async-timeout==4.0.3 - # via redis brotli==1.1.0 # via # -r requirements.in @@ -52,9 +50,7 @@ defusedxml==0.7.1 # via -r requirements.in edr-pydantic==0.3.0 # via -r requirements.in -exceptiongroup==1.2.2 - # via anyio -fastapi==0.109.2 +fastapi==0.115.2 # via -r requirements.in geojson-pydantic==1.1.1 # via -r requirements.in @@ -128,18 +124,15 @@ sniffio==1.3.1 # via # anyio # httpx -starlette==0.36.3 +starlette==0.40.0 # via # brotli-asgi # fastapi typing-extensions==4.12.2 # via - # anyio - # asgiref # fastapi # pydantic # pydantic-core - # uvicorn tzlocal==5.2 # via apscheduler urllib3==2.2.3 diff --git a/tests/AdagucTests/TestWCS.py b/tests/AdagucTests/TestWCS.py index 05b6e79e..bc3be4c6 100644 --- a/tests/AdagucTests/TestWCS.py +++ b/tests/AdagucTests/TestWCS.py @@ -14,6 +14,7 @@ from netCDF4 import Dataset import tempfile from adaguc.AdagucTestTools import AdagucTestTools +import difflib ADAGUC_PATH = os.environ['ADAGUC_PATH'] @@ -56,6 +57,104 @@ def test_WCSDescribeCoverage_Actuele10mindata(self): self.assertTrue(AdagucTestTools().compareGetCapabilitiesXML( self.testresultspath + filename, self.expectedoutputsspath + filename)) + + def test_WCSDescribeCoverage_Multidimdata(self): + """ + Check if WCS DescribeCoverage shows information for multidimensional data + """ + AdagucTestTools().cleanTempDir() + # This file has the following dimensions: lon,lat,member,height, and time. + filename = "test_WCSDescribeCoverage_Multidimdata.xml" + status, data, headers = AdagucTestTools().runADAGUCServer( + "source=netcdf_5dims/netcdf_5dims_seq2/nc_5D_20170101001500-20170101002500.nc&SERVICE=WCS&request=describecoverage&coverage=data", + env=self.env, + maxLogFileSize=16384 + ) # Silence log flood warning, datafile has lots of variables, each giving log output + AdagucTestTools().writetofile(self.testresultspath + filename, + data.getvalue()) + self.assertEqual(status, 0) + self.assertTrue(AdagucTestTools().compareGetCapabilitiesXML( + self.testresultspath + filename, + self.expectedoutputsspath + filename)) + + def test_WCSDescribeCoverage_Multidimdata_large_daily(self): + """ + Check if WCS DescribeCoverage shows information for multidimensional data, with more than 200 equally spaced timestamps + """ + AdagucTestTools().cleanTempDir() + # This file has the following dimensions: lon,lat,member,height, and time. + filename = "test_WCSDescribeCoverage_Multidimdata_large_daily.xml" + status, data, headers = AdagucTestTools().runADAGUCServer( + "source=large_number_timesteps/210_daily_timesteps.nc&SERVICE=WCS&request=describecoverage&coverage=data", + env=self.env, + maxLogFileSize=16384 + ) # Silence log flood warning, datafile has lots of variables, each giving log output + AdagucTestTools().writetofile(self.testresultspath + filename, + data.getvalue()) + self.assertEqual(status, 0) + self.assertTrue(AdagucTestTools().compareGetCapabilitiesXML( + self.testresultspath + filename, + self.expectedoutputsspath + filename)) + + def test_WCSDescribeCoverage_Multidimdata_large_2day_height(self): + """ + Check if WCS DescribeCoverage shows information for multidimensional data, with more than 200 equally spaced timestamps + and one extra dimension (height) + """ + AdagucTestTools().cleanTempDir() + # This file has the following dimensions: lon,lat,member,height, and time. + filename = "test_WCSDescribeCoverage_Multidimdata_large_2day_height.xml" + status, data, headers = AdagucTestTools().runADAGUCServer( + "source=large_number_timesteps/210_2day_timesteps_5_heights.nc&SERVICE=WCS&request=describecoverage&coverage=data", + env=self.env, + maxLogFileSize=16384 + ) # Silence log flood warning, datafile has lots of variables, each giving log output + AdagucTestTools().writetofile(self.testresultspath + filename, + data.getvalue()) + self.assertEqual(status, 0) + self.assertTrue(AdagucTestTools().compareGetCapabilitiesXML( + self.testresultspath + filename, + self.expectedoutputsspath + filename)) + + def test_WCSDescribeCoverage_Multidimdata_99_timesteps(self): + """ + Check if WCS DescribeCoverage shows information for multidimensional data, with 190 equally spaced timestamps + """ + AdagucTestTools().cleanTempDir() + # This file has the following dimensions: lon,lat,member,height, and time. + filename = "test_WCSDescribeCoverage_Multidimdata_99_timesteps.xml" + status, data, headers = AdagucTestTools().runADAGUCServer( + "source=large_number_timesteps/99_2day_timesteps.nc&SERVICE=WCS&request=describecoverage&coverage=data", + env=self.env, + maxLogFileSize=16384 + ) # Silence log flood warning, datafile has lots of variables, each giving log output + AdagucTestTools().writetofile(self.testresultspath + filename, + data.getvalue()) + self.assertEqual(status, 0) + self.assertTrue(AdagucTestTools().compareGetCapabilitiesXML( + self.testresultspath + filename, + self.expectedoutputsspath + filename)) + + def test_WCSDescribeCoverage_Multidimdata_large_random(self): + """ + Check if WCS DescribeCoverage shows information for multidimensional data, with more than 200 randomly spaced timestamps + """ + AdagucTestTools().cleanTempDir() + # This file has the following dimensions: lon,lat,member,height, and time. + filename = "test_WCSDescribeCoverage_Multidimdata_large_random.xml" + status, data, headers = AdagucTestTools().runADAGUCServer( + "source=large_number_timesteps%2F210_random_timesteps.nc&&service=WCS&REQUEST=DescribeCoverage&COVERAGE=data", + env=self.env, + maxLogFileSize=16384, + showLog=True + ) # Silence log flood warning, datafile has lots of variables, each giving log output + AdagucTestTools().writetofile(self.testresultspath + filename, + data.getvalue()) + self.assertEqual(status, 0) + self.assertTrue(AdagucTestTools().compareGetCapabilitiesXML( + self.testresultspath + filename, + self.expectedoutputsspath + filename)) + def test_WCSGetCoverageAAIGRID_testdatanc(self): """ Check if WCS GetCoverage for testdata.nc as AAIGRID file is OK diff --git a/tests/expectedoutputs/TestWCS/test_WCSDescribeCoverage_Multidimdata.xml b/tests/expectedoutputs/TestWCS/test_WCSDescribeCoverage_Multidimdata.xml new file mode 100644 index 00000000..0ed214f4 --- /dev/null +++ b/tests/expectedoutputs/TestWCS/test_WCSDescribeCoverage_Multidimdata.xml @@ -0,0 +1,201 @@ + + + + data + data + + km + + -180.494446 -90.488892 + 179.505554 89.511108 + + + + + -180.494446 -90.488892 + 179.505554 89.511108 + + + -15931605.907041 -19720315.591565 + 17051580.684528 19828593.536145 + + + -14709787.414601 -19720736.728277 + 17177711.901099 47405035.658741 + + + -352494887.244074 -527708138.497395 + 319428390.883462 521690003.576207 + + + -15931605.907041 -19720315.591565 + 17051580.684528 19828593.536145 + + + -407173329.856895 -406795071.401436 + 411420024.012517 411546161.390658 + + + -399240949.703125 -399607437.540235 + 399487065.269510 398879979.546019 + + + -2868126705.493384 -2870740092.047709 + 2869855924.003487 2865475278.583282 + + + -12712149.336113 -12731583.256617 + 12735505.704073 12723911.899582 + + + -19201993.871211 -22228632.557364 + 19982466.888021 34805382.412607 + + + -411643188.990840 -411262647.285147 + 411891372.245993 412018271.016759 + + + -180.494446 -90.488892 + 179.505554 89.511108 + + + -180.494446 -90.488892 + 179.505554 89.511108 + + + -2000000.000000 -2000000.000000 + 10000000.000000 8500000.000000 + + + -16294244.470419 -8493172.970167 + 16956530.805045 8610630.466538 + + + -17284159.484400 -8898366.230070 + 17986681.325950 9020047.848074 + + + -19201993.871211 -22228632.557364 + 19982466.888021 34805382.412607 + + + + + 0 0 + 359 179 + + + x + y + + -180.494446 89.511108 + + 1.000000 0 + 0 -1.000000 + + + + 2017-01-01T00:15:00Z + 2017-01-01T00:20:00Z + 2017-01-01T00:25:00Z + + + + + dimensions + + + + time + + + + 2017-01-01T00:15:00Z + 2017-01-01T00:25:00Z + + + + + + + member + + + + member1 + member6 + + member1 + member2 + member3 + member4 + member5 + member6 + + + + + + height + + + + 1000 + 9000 + + 1000 + 2000 + 3000 + 4000 + 5000 + 6000 + 7000 + 8000 + 9000 + + + + + + + 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 + EPSG:4326 + + + GeoTIFF + AAIGRID + netcdf + NetCDF3 + NetCDF4 + aaigrid + geotiff + + + nearest neighbor + + + diff --git a/tests/expectedoutputs/TestWCS/test_WCSDescribeCoverage_Multidimdata_99_timesteps.xml b/tests/expectedoutputs/TestWCS/test_WCSDescribeCoverage_Multidimdata_99_timesteps.xml new file mode 100644 index 00000000..6dee8bad --- /dev/null +++ b/tests/expectedoutputs/TestWCS/test_WCSDescribeCoverage_Multidimdata_99_timesteps.xml @@ -0,0 +1,170 @@ + + + + data + data + + + + -177.500000 -92.500000 + 182.500000 87.500000 + + 2024-01-01T00:00:00Z + 2024-07-15T00:00:00Z + P2D + + + + + + -177.500000 -92.500000 + 182.500000 87.500000 + + + -16130665.820500 -19940662.730257 + 16773561.425558 19609055.102676 + + + -16036501.605628 -19940645.777523 + 16923493.804105 60690754.770073 + + + -472960753.832483 -309441675.885504 + 848274888.059136 305071541.647454 + + + -16130665.820500 -19940662.730257 + 16773561.425558 19609055.102676 + + + -956875261.313672 -956583178.620243 + 959123209.982084 959999102.204602 + + + -934752295.351214 -933897657.529952 + 935322198.568163 935607193.582759 + + + -561309613.991027 -560796725.035447 + 560283992.310811 561138633.645077 + + + -12736546.916317 -12717148.538095 + 12728786.383025 12740427.774036 + + + -19759209.615806 -27654657.553919 + 19425251.143426 24395894.014051 + + + -964663240.758221 -964369394.990184 + 962900613.664068 963781792.962376 + + + -177.500000 -92.500000 + 182.500000 87.500000 + + + -177.500000 -92.500000 + 182.500000 87.500000 + + + -2000000.000000 -2000000.000000 + 10000000.000000 8500000.000000 + + + -16769347.747524 -8576525.559211 + 16485922.151792 8537587.027768 + + + -17789120.971417 -8980925.065185 + 17488459.771900 8942711.608087 + + + -19759209.615806 -27654657.553919 + 19425251.143426 24395894.014051 + + + + + 0 0 + 71 35 + + + x + y + + -177.500000 -92.500000 + + 5.000000 0 + 0 5.000000 + + + + + 2024-01-01T00:00:00Z + 2024-07-15T00:00:00Z + P2D + + + + + + dimensions + + + + time + + + + 2024-01-01T00:00:00Z + 2024-07-15T00:00:00Z + P2D + + + + + + + + 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 + EPSG:4326 + + + GeoTIFF + AAIGRID + netcdf + NetCDF3 + NetCDF4 + aaigrid + geotiff + + + nearest neighbor + + + diff --git a/tests/expectedoutputs/TestWCS/test_WCSDescribeCoverage_Multidimdata_large_2day_height.xml b/tests/expectedoutputs/TestWCS/test_WCSDescribeCoverage_Multidimdata_large_2day_height.xml new file mode 100644 index 00000000..5badc64e --- /dev/null +++ b/tests/expectedoutputs/TestWCS/test_WCSDescribeCoverage_Multidimdata_large_2day_height.xml @@ -0,0 +1,187 @@ + + + + data + data + + + + -175.000000 -95.000000 + 185.000000 85.000000 + + 2024-01-01T00:00:00Z + 2024-07-15T00:00:00Z + P2D + + + + + + -175.000000 -95.000000 + 185.000000 85.000000 + + + -15525733.593319 -19664133.594210 + 17120498.212243 19885331.913357 + + + -15446685.388670 -19663523.006985 + 16446685.388670 19885128.053335 + + + -288940224.722197 -561625982.106351 + 266207703.868375 1005853853.334681 + + + -15525733.593319 -19664133.594210 + 17120498.212243 19885331.913357 + + + -476720074.926217 -477304033.059373 + 481304033.059373 480720074.926217 + + + -467744480.581090 -467459543.281553 + 466605078.535150 467459543.281553 + + + -280152792.512996 -280152792.512996 + 280494531.893237 280494531.893237 + + + -12735668.795456 -12735668.795456 + 12720152.344808 12720152.344808 + + + -19480910.888823 -23232576.780082 + 19703549.870409 19971868.880409 + + + -481609733.326174 -482197216.357518 + 482197216.357518 481609733.326174 + + + -175.000000 -95.000000 + 185.000000 85.000000 + + + -175.000000 -95.000000 + 185.000000 85.000000 + + + -2000000.000000 -2000000.000000 + 10000000.000000 8500000.000000 + + + -16532317.502283 -8516243.829905 + 16721258.273737 8419013.706324 + + + -17537334.096874 -8921410.650524 + 17737760.772267 8824978.852257 + + + -19480910.888823 -23232576.780082 + 19703549.870409 19971868.880409 + + + + + 0 0 + 35 17 + + + x + y + + -175.000000 -95.000000 + + 10.000000 0 + 0 10.000000 + + + + + 2024-01-01T00:00:00Z + 2024-07-15T00:00:00Z + P2D + + + + + + dimensions + + + + time + + + + 2024-01-01T00:00:00Z + 2024-07-15T00:00:00Z + P2D + + + + + + + height + + + + 0 + 4 + + 0 + 1 + 2 + 3 + 4 + + + + + + + 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 + EPSG:4326 + + + GeoTIFF + AAIGRID + netcdf + NetCDF3 + NetCDF4 + aaigrid + geotiff + + + nearest neighbor + + + diff --git a/tests/expectedoutputs/TestWCS/test_WCSDescribeCoverage_Multidimdata_large_daily.xml b/tests/expectedoutputs/TestWCS/test_WCSDescribeCoverage_Multidimdata_large_daily.xml new file mode 100644 index 00000000..98791c54 --- /dev/null +++ b/tests/expectedoutputs/TestWCS/test_WCSDescribeCoverage_Multidimdata_large_daily.xml @@ -0,0 +1,170 @@ + + + + data + data + + + + -177.500000 -92.500000 + 182.500000 87.500000 + + 2024-01-01T00:00:00Z + 2024-07-28T00:00:00Z + P1D + + + + + + -177.500000 -92.500000 + 182.500000 87.500000 + + + -16130665.820500 -19940662.730257 + 16773561.425558 19609055.102676 + + + -16036501.605628 -19940645.777523 + 16923493.804105 60690754.770073 + + + -472960753.832483 -309441675.885504 + 848274888.059136 305071541.647454 + + + -16130665.820500 -19940662.730257 + 16773561.425558 19609055.102676 + + + -956875261.313672 -956583178.620243 + 959123209.982084 959999102.204602 + + + -934752295.351214 -933897657.529952 + 935322198.568163 935607193.582759 + + + -561309613.991027 -560796725.035447 + 560283992.310811 561138633.645077 + + + -12736546.916317 -12717148.538095 + 12728786.383025 12740427.774036 + + + -19759209.615806 -27654657.553919 + 19425251.143426 24395894.014051 + + + -964663240.758221 -964369394.990184 + 962900613.664068 963781792.962376 + + + -177.500000 -92.500000 + 182.500000 87.500000 + + + -177.500000 -92.500000 + 182.500000 87.500000 + + + -2000000.000000 -2000000.000000 + 10000000.000000 8500000.000000 + + + -16769347.747524 -8576525.559211 + 16485922.151792 8537587.027768 + + + -17789120.971417 -8980925.065185 + 17488459.771900 8942711.608087 + + + -19759209.615806 -27654657.553919 + 19425251.143426 24395894.014051 + + + + + 0 0 + 71 35 + + + x + y + + -177.500000 -92.500000 + + 5.000000 0 + 0 5.000000 + + + + + 2024-01-01T00:00:00Z + 2024-07-28T00:00:00Z + P1D + + + + + + dimensions + + + + time + + + + 2024-01-01T00:00:00Z + 2024-07-28T00:00:00Z + P1D + + + + + + + + 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 + EPSG:4326 + + + GeoTIFF + AAIGRID + netcdf + NetCDF3 + NetCDF4 + aaigrid + geotiff + + + nearest neighbor + + + diff --git a/tests/expectedoutputs/TestWCS/test_WCSDescribeCoverage_Multidimdata_large_random.xml b/tests/expectedoutputs/TestWCS/test_WCSDescribeCoverage_Multidimdata_large_random.xml new file mode 100644 index 00000000..fdf0b9d2 --- /dev/null +++ b/tests/expectedoutputs/TestWCS/test_WCSDescribeCoverage_Multidimdata_large_random.xml @@ -0,0 +1,369 @@ + + + + data + data + + + + -177.500000 -92.500000 + 182.500000 87.500000 + + + + + -177.500000 -92.500000 + 182.500000 87.500000 + + + -16130665.820500 -19940662.730257 + 16773561.425558 19609055.102676 + + + -16036501.605628 -19940645.777523 + 16923493.804105 60690754.770073 + + + -472960753.832483 -309441675.885504 + 848274888.059136 305071541.647454 + + + -16130665.820500 -19940662.730257 + 16773561.425558 19609055.102676 + + + -956875261.313672 -956583178.620243 + 959123209.982084 959999102.204602 + + + -934752295.351214 -933897657.529952 + 935322198.568163 935607193.582759 + + + -561309613.991027 -560796725.035447 + 560283992.310811 561138633.645077 + + + -12736546.916317 -12717148.538095 + 12728786.383025 12740427.774036 + + + -19759209.615806 -27654657.553919 + 19425251.143426 24395894.014051 + + + -964663240.758221 -964369394.990184 + 962900613.664068 963781792.962376 + + + -177.500000 -92.500000 + 182.500000 87.500000 + + + -177.500000 -92.500000 + 182.500000 87.500000 + + + -2000000.000000 -2000000.000000 + 10000000.000000 8500000.000000 + + + -16769347.747524 -8576525.559211 + 16485922.151792 8537587.027768 + + + -17789120.971417 -8980925.065185 + 17488459.771900 8942711.608087 + + + -19759209.615806 -27654657.553919 + 19425251.143426 24395894.014051 + + + + + 0 0 + 71 35 + + + x + y + + -177.500000 -92.500000 + + 5.000000 0 + 0 5.000000 + + + + 2023-12-31T19:58:17Z + 2023-12-31T22:59:38Z + 2024-01-01T00:00:00Z + 2024-01-01T00:22:29Z + 2024-01-01T01:04:33Z + 2024-01-01T01:55:23Z + 2024-01-01T03:35:39Z + 2024-01-01T04:22:02Z + 2024-01-01T04:44:09Z + 2024-01-01T05:33:41Z + 2024-01-01T06:48:15Z + 2024-01-01T07:18:25Z + 2024-01-01T12:08:55Z + 2024-01-01T17:58:10Z + 2024-01-01T21:15:02Z + 2024-01-02T02:58:07Z + 2024-01-02T04:11:55Z + 2024-01-02T06:04:17Z + 2024-01-02T06:26:45Z + 2024-01-02T12:20:09Z + 2024-01-02T14:05:01Z + 2024-01-02T20:08:18Z + 2024-01-02T22:01:38Z + 2024-01-03T01:07:16Z + 2024-01-03T13:01:59Z + 2024-01-03T21:15:33Z + 2024-01-04T04:28:03Z + 2024-01-04T08:31:01Z + 2024-01-04T19:13:47Z + 2024-01-04T22:17:18Z + 2024-01-04T22:26:31Z + 2024-01-05T01:03:40Z + 2024-01-05T05:06:22Z + 2024-01-05T10:25:47Z + 2024-01-05T11:28:13Z + 2024-01-05T11:35:18Z + 2024-01-05T20:27:31Z + 2024-01-05T22:20:09Z + 2024-01-06T06:36:26Z + 2024-01-06T14:14:29Z + 2024-01-06T15:54:37Z + 2024-01-06T18:11:12Z + 2024-01-06T19:28:33Z + 2024-01-06T19:41:13Z + 2024-01-07T02:00:43Z + 2024-01-07T02:25:24Z + 2024-01-07T04:29:18Z + 2024-01-07T07:24:59Z + 2024-01-07T08:30:55Z + 2024-01-07T12:42:22Z + 2024-01-07T16:36:13Z + 2024-01-07T17:54:37Z + 2024-01-08T02:06:08Z + 2024-01-08T04:45:10Z + 2024-01-08T05:31:24Z + 2024-01-08T09:29:18Z + 2024-01-08T16:38:43Z + 2024-01-08T18:54:05Z + 2024-01-09T01:33:12Z + 2024-01-09T02:02:09Z + 2024-01-09T07:25:14Z + 2024-01-09T08:53:07Z + 2024-01-09T17:17:43Z + 2024-01-09T20:38:48Z + 2024-01-10T01:50:27Z + 2024-01-10T03:02:00Z + 2024-01-10T10:19:00Z + 2024-01-10T15:28:29Z + 2024-01-10T18:01:05Z + 2024-01-10T19:15:25Z + 2024-01-10T19:21:28Z + 2024-01-10T19:51:27Z + 2024-01-10T20:30:02Z + 2024-01-10T20:33:32Z + 2024-01-10T21:33:48Z + 2024-01-10T21:56:36Z + 2024-01-10T22:10:26Z + 2024-01-10T22:39:11Z + 2024-01-11T00:14:36Z + 2024-01-11T02:32:50Z + 2024-01-11T04:21:43Z + 2024-01-11T04:43:27Z + 2024-01-11T06:26:18Z + 2024-01-11T06:54:39Z + 2024-01-11T07:18:32Z + 2024-01-11T07:48:28Z + 2024-01-11T08:42:31Z + 2024-01-11T08:45:09Z + 2024-01-11T16:11:56Z + 2024-01-12T03:50:22Z + 2024-01-12T06:38:32Z + 2024-01-12T06:47:52Z + 2024-01-12T08:12:32Z + 2024-01-12T11:49:09Z + 2024-01-12T13:18:51Z + 2024-01-12T16:58:23Z + 2024-01-12T19:25:32Z + 2024-01-12T21:44:00Z + 2024-01-12T21:48:52Z + 2024-01-12T22:37:33Z + 2024-01-13T06:16:38Z + 2024-01-13T07:31:52Z + 2024-01-13T08:51:07Z + 2024-01-13T15:07:40Z + 2024-01-13T15:28:39Z + 2024-01-13T15:42:23Z + 2024-01-13T16:24:33Z + 2024-01-13T16:45:24Z + 2024-01-14T01:21:24Z + 2024-01-14T02:14:01Z + 2024-01-14T02:34:10Z + 2024-01-14T03:34:34Z + 2024-01-14T08:11:00Z + 2024-01-14T08:58:28Z + 2024-01-14T11:40:01Z + 2024-01-14T12:14:33Z + 2024-01-14T13:02:41Z + 2024-01-14T19:14:08Z + 2024-01-15T06:48:19Z + 2024-01-15T17:30:44Z + 2024-01-15T22:22:47Z + 2024-01-16T01:17:38Z + 2024-01-16T13:06:39Z + 2024-01-16T14:12:04Z + 2024-01-16T14:41:39Z + 2024-01-16T15:10:10Z + 2024-01-16T15:21:40Z + 2024-01-16T16:10:55Z + 2024-01-16T20:05:15Z + 2024-01-16T21:20:07Z + 2024-01-16T22:36:44Z + 2024-01-16T23:14:04Z + 2024-01-17T02:07:21Z + 2024-01-17T02:08:57Z + 2024-01-17T02:33:54Z + 2024-01-17T06:28:57Z + 2024-01-17T06:30:40Z + 2024-01-17T09:10:58Z + 2024-01-17T11:50:36Z + 2024-01-17T12:06:03Z + 2024-01-17T14:36:09Z + 2024-01-17T15:17:01Z + 2024-01-17T15:37:42Z + 2024-01-17T15:39:43Z + 2024-01-17T16:37:33Z + 2024-01-17T18:28:01Z + 2024-01-17T21:56:30Z + 2024-01-18T00:57:10Z + 2024-01-18T03:46:48Z + 2024-01-18T07:00:10Z + 2024-01-18T08:33:13Z + 2024-01-18T14:09:10Z + 2024-01-18T20:55:21Z + 2024-01-18T22:19:54Z + 2024-01-19T08:06:11Z + 2024-01-19T09:52:10Z + 2024-01-19T10:00:31Z + 2024-01-19T10:28:11Z + 2024-01-19T11:27:51Z + 2024-01-19T17:56:58Z + 2024-01-19T21:40:57Z + 2024-01-20T03:50:48Z + 2024-01-20T05:31:14Z + 2024-01-20T16:03:30Z + 2024-01-20T23:59:02Z + 2024-01-21T06:53:44Z + 2024-01-21T10:42:53Z + 2024-01-21T14:33:51Z + 2024-01-21T15:57:27Z + 2024-01-21T16:00:03Z + 2024-01-21T17:33:38Z + 2024-01-21T21:28:16Z + 2024-01-21T23:39:49Z + 2024-01-22T01:48:35Z + 2024-01-22T05:59:05Z + 2024-01-22T11:09:57Z + 2024-01-22T11:18:44Z + 2024-01-22T12:59:34Z + 2024-01-22T13:11:23Z + 2024-01-22T14:10:01Z + 2024-01-22T14:53:29Z + 2024-01-22T23:22:37Z + 2024-01-23T03:21:45Z + 2024-01-23T05:08:18Z + 2024-01-23T08:14:35Z + 2024-01-23T09:58:01Z + 2024-01-23T10:49:24Z + 2024-01-23T14:49:55Z + 2024-01-23T14:59:27Z + 2024-01-23T19:48:12Z + 2024-01-23T21:13:31Z + 2024-01-23T22:30:02Z + 2024-01-24T01:01:02Z + 2024-01-24T02:04:08Z + 2024-01-24T05:01:18Z + 2024-01-24T06:12:37Z + 2024-01-24T06:21:46Z + 2024-01-24T07:00:24Z + 2024-01-24T07:34:57Z + 2024-01-24T07:39:03Z + 2024-01-24T10:32:54Z + 2024-01-24T16:40:13Z + 2024-01-24T21:48:14Z + 2024-01-24T22:09:20Z + 2024-01-24T22:41:08Z + 2024-01-25T04:37:46Z + 2024-01-25T07:03:42Z + 2024-01-25T15:44:55Z + 2024-01-25T16:13:03Z + 2024-01-25T20:58:34Z + + + + + dimensions + + + + time + + + + 2023-12-31T19:58:17Z + 2024-01-25T20:58:34Z + + + + + + + + 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 + EPSG:4326 + + + GeoTIFF + AAIGRID + netcdf + NetCDF3 + NetCDF4 + aaigrid + geotiff + + + nearest neighbor + + + diff --git a/tests/expectedoutputs/TestWCS/test_WCSDescribeCoverage_testdatanc.xml b/tests/expectedoutputs/TestWCS/test_WCSDescribeCoverage_testdatanc.xml index c4485c4e..c37a06f3 100644 --- a/tests/expectedoutputs/TestWCS/test_WCSDescribeCoverage_testdatanc.xml +++ b/tests/expectedoutputs/TestWCS/test_WCSDescribeCoverage_testdatanc.xml @@ -108,15 +108,12 @@ - bands - + dimensions + - bands - - - 1 - + time + @@ -255,15 +252,12 @@ - bands - + dimensions + - bands - - - 1 - + time + @@ -402,15 +396,12 @@ - bands - + dimensions + - bands - - - 1 - + time +