mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-05-07 12:00:05 -05:00
Added unit testing for timequantizer and improved quantizer solver
This commit is contained in:
@@ -113,22 +113,26 @@ bool TimeQuantizer::quantize(Time& t, bool clamp) {
|
||||
double error = 0.0;
|
||||
const int iterationLimit = 50;
|
||||
int iterations = 0;
|
||||
int lastIncr = 0;
|
||||
int lastDecr = 0;
|
||||
|
||||
if (_timerange.includes(unquantizedStr)) {
|
||||
DateTime quantized = DateTime(_timerange.start());
|
||||
doFirstApproximation(quantized, unquantized, _resolutionValue, _resolutionUnit);
|
||||
error = diff(quantized, unquantized);
|
||||
while (error > _resolution) {
|
||||
while (error > (_resolution * 0.7) || error < 0) {
|
||||
if (error > 0) {
|
||||
quantized.increment(static_cast<int>(_resolutionValue), _resolutionUnit,
|
||||
error, _resolution);
|
||||
lastIncr = quantized.increment(static_cast<int>(_resolutionValue),
|
||||
_resolutionUnit, error, _resolution);
|
||||
}
|
||||
else {
|
||||
quantized.decrement(static_cast<int>(_resolutionValue), _resolutionUnit,
|
||||
error, _resolution);
|
||||
else if (error < 0) {
|
||||
lastDecr = quantized.decrement(static_cast<int>(_resolutionValue),
|
||||
_resolutionUnit, error, _resolution);
|
||||
}
|
||||
error = diff(quantized, unquantized);
|
||||
if (++iterations > iterationLimit) {
|
||||
bool hasSettled = (lastIncr == 1 && lastDecr == 1);
|
||||
iterations++;
|
||||
if (hasSettled || iterations > iterationLimit) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -156,6 +160,10 @@ void TimeQuantizer::doFirstApproximation(DateTime& quantized, DateTime& unQ,
|
||||
double minYearsToAdjust;
|
||||
double minIncrementsToAdjust;
|
||||
bool isSimMonthPastQuantizedMonth;
|
||||
double error = 0.0;
|
||||
int originalHour, originalMinute, originalSecond;
|
||||
Time testDay;
|
||||
double addToTime;
|
||||
|
||||
switch (unit) {
|
||||
case 'y':
|
||||
@@ -171,18 +179,22 @@ void TimeQuantizer::doFirstApproximation(DateTime& quantized, DateTime& unQ,
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
if (unQ.month() > 1) {
|
||||
quantized.setYear(unQ.year());
|
||||
quantized.setMonth(unQ.month() - 1);
|
||||
}
|
||||
else {
|
||||
quantized.setYear(unQ.year() - 1);
|
||||
quantized.setMonth(12);
|
||||
}
|
||||
error = diff(quantized, unQ);
|
||||
error /= 86400;
|
||||
originalHour = quantized.hour();
|
||||
originalMinute = quantized.minute();
|
||||
originalSecond = quantized.second();
|
||||
addToTime = std::round(error) * 86400;
|
||||
testDay.setTime(quantized.J2000() + addToTime);
|
||||
quantized.setTime(testDay.ISO8601());
|
||||
quantized.setHour(originalHour);
|
||||
quantized.setMinute(originalMinute);
|
||||
quantized.setSecond(originalSecond);
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
quantized = unQ;
|
||||
quantized.setMinute(0);
|
||||
quantized.setSecond(0);
|
||||
if (unQ.hour() >= 12) {
|
||||
quantized.setHour(0);
|
||||
@@ -194,6 +206,7 @@ void TimeQuantizer::doFirstApproximation(DateTime& quantized, DateTime& unQ,
|
||||
|
||||
case 'm':
|
||||
quantized = unQ;
|
||||
quantized.setMinute(0);
|
||||
quantized.setSecond(0);
|
||||
if (quantized.hour() > 0) {
|
||||
quantized.decrementOnce(1, 'h');
|
||||
@@ -270,14 +283,19 @@ void DateTime::operator= (DateTime& src) {
|
||||
_second = src.second();
|
||||
}
|
||||
|
||||
void DateTime::increment(int value, char unit, double error, double resolution) {
|
||||
int DateTime::increment(int value, char unit, double error, double resolution) {
|
||||
unsigned int nIncrements = std::abs(static_cast<int>(error / resolution));
|
||||
if (nIncrements == 0) {
|
||||
nIncrements = 1;
|
||||
}
|
||||
for (unsigned int i = 0; i < nIncrements; ++i) {
|
||||
incrementOnce(value, unit);
|
||||
}
|
||||
return nIncrements;
|
||||
}
|
||||
|
||||
void DateTime::incrementOnce(int value, char unit) {
|
||||
bool inBounds = true;
|
||||
switch (unit) {
|
||||
case 'm':
|
||||
if (singleIncrement(_minute, value, 0, 59))
|
||||
@@ -295,7 +313,9 @@ void DateTime::incrementOnce(int value, char unit) {
|
||||
//fall-through...
|
||||
|
||||
case 'M':
|
||||
if (singleIncrement(_month, value, 1, 12))
|
||||
inBounds = singleIncrement(_month, value, 1, 12);
|
||||
_day = std::clamp(_day, 1, monthSize(_month, _year));
|
||||
if (inBounds)
|
||||
break;
|
||||
//fall-through...
|
||||
|
||||
@@ -316,14 +336,19 @@ bool DateTime::singleIncrement(int& oper, int& val, int min, int max) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void DateTime::decrement(int value, char unit, double error, double resolution) {
|
||||
int DateTime::decrement(int value, char unit, double error, double resolution) {
|
||||
unsigned int nDecrements = std::abs(static_cast<int>(error / resolution));
|
||||
for (unsigned int i = 0; i < nDecrements; ++i) {
|
||||
incrementOnce(value, unit);
|
||||
if (nDecrements == 0) {
|
||||
nDecrements = 1;
|
||||
}
|
||||
for (unsigned int i = 0; i < nDecrements; ++i) {
|
||||
decrementOnce(value, unit);
|
||||
}
|
||||
return nDecrements;
|
||||
}
|
||||
|
||||
void DateTime::decrementOnce(int value, char unit) {
|
||||
bool inBounds = true;
|
||||
switch (unit) {
|
||||
case 'm':
|
||||
if (singleDecrement(_minute, value, 0, 59))
|
||||
@@ -336,17 +361,22 @@ void DateTime::decrementOnce(int value, char unit) {
|
||||
//fall-through...
|
||||
|
||||
case 'd':
|
||||
if (singleDecrement(_day, value, 1, monthSize(_month, _year)))
|
||||
if (singleDecrement(_day, value, 1,
|
||||
monthSize(_month == 1 ? 12 : _month - 1, _year)))
|
||||
{
|
||||
break;
|
||||
}
|
||||
//fall-through...
|
||||
|
||||
case 'M':
|
||||
if (singleDecrement(_minute, value, 1, 12))
|
||||
inBounds = singleDecrement(_month, value, 1, 12);
|
||||
_day = std::clamp(_day, 1, monthSize(_month, _year));
|
||||
if (inBounds)
|
||||
break;
|
||||
//fall-through...
|
||||
|
||||
case 'Y':
|
||||
_year += value;
|
||||
_year -= value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,9 +74,9 @@ public:
|
||||
void setMinute(int);
|
||||
void setSecond(int);
|
||||
|
||||
void increment(int value, char unit, double error, double resolution);
|
||||
int increment(int value, char unit, double error, double resolution);
|
||||
void incrementOnce(int value, char unit);
|
||||
void decrement(int value, char unit, double error, double resolution);
|
||||
int decrement(int value, char unit, double error, double resolution);
|
||||
void decrementOnce(int value, char unit);
|
||||
|
||||
private:
|
||||
|
||||
@@ -76,6 +76,7 @@
|
||||
#include <test_concurrentqueue.inl>
|
||||
#include <test_lrucache.inl>
|
||||
#include <test_gdalwms.inl>
|
||||
#include <test_timequantizer.inl>
|
||||
#endif
|
||||
|
||||
#ifdef OPENSPACE_MODULE_ISWA_ENABLED
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2019 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include <openspace/util/time.h>
|
||||
#include "modules/globebrowsing/src/timequantizer.h"
|
||||
#include <openspace/util/spicemanager.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include "SpiceUsr.h"
|
||||
#include "SpiceZpr.h"
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
class TimeQuantizerTest : public testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
openspace::SpiceManager::initialize();
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
openspace::SpiceManager::deinitialize();
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
//global constants
|
||||
#define FILLEN 128
|
||||
#define TYPLEN 32
|
||||
#define SRCLEN 128
|
||||
|
||||
namespace spicemanager_constants {
|
||||
const int nrMetaKernels = 9;
|
||||
SpiceInt which, handle, count = 0;
|
||||
char file[FILLEN], filtyp[TYPLEN], source[SRCLEN];
|
||||
double abs_error = 0.00001;
|
||||
} // namespace spicemanager_constants
|
||||
|
||||
#define LSK "C:\\Users\\OpenSpace\\Desktop\\profiles\\OpenSpace\\tests\\SpiceTest\\spicekernels\\naif0008.tls"
|
||||
|
||||
int loadLSKKernel() {
|
||||
int kernelID = openspace::SpiceManager::ref().loadKernel(
|
||||
std::string(LSK)
|
||||
);
|
||||
EXPECT_EQ(1, kernelID) << "loadKernel did not return proper id";
|
||||
return kernelID;
|
||||
}
|
||||
|
||||
static void singleTimeTest(openspace::Time& t,
|
||||
openspace::globebrowsing::TimeQuantizer& tq, bool clamp,
|
||||
const std::string& input, const std::string& expected)
|
||||
{
|
||||
t.setTime(input);
|
||||
tq.quantize(t, clamp);
|
||||
EXPECT_EQ(t.ISO8601(), expected);
|
||||
}
|
||||
|
||||
TEST_F(TimeQuantizerTest, Basic) {
|
||||
loadLSKKernel();
|
||||
// naif0008.tls is a text file, check if loaded.
|
||||
SpiceBoolean found;
|
||||
kdata_c(
|
||||
0,
|
||||
"text",
|
||||
FILLEN,
|
||||
TYPLEN,
|
||||
SRCLEN,
|
||||
spicemanager_constants::file,
|
||||
spicemanager_constants::filtyp,
|
||||
spicemanager_constants::source,
|
||||
&spicemanager_constants::handle,
|
||||
&found
|
||||
);
|
||||
|
||||
ASSERT_TRUE(found == SPICETRUE) << "Kernel not loaded";
|
||||
using namespace openspace::globebrowsing;
|
||||
|
||||
TimeQuantizer t1;
|
||||
openspace::Time testT;
|
||||
|
||||
t1.setStartEndRange("2019-12-09T00:00:00", "2020-03-01T00:00:00");
|
||||
t1.setResolution("1d");
|
||||
|
||||
singleTimeTest(testT, t1, true, "2020-01-07T05:15:45", "2020-01-07T00:00:00.000");
|
||||
singleTimeTest(testT, t1, true, "2020-01-07T00:00:00", "2020-01-07T00:00:00.000");
|
||||
singleTimeTest(testT, t1, true, "2020-01-07T00:00:01", "2020-01-07T00:00:00.000");
|
||||
singleTimeTest(testT, t1, true, "2020-01-06T23:59:59", "2020-01-06T00:00:00.000");
|
||||
singleTimeTest(testT, t1, true, "2020-01-31T23:59:59", "2020-01-31T00:00:00.000");
|
||||
singleTimeTest(testT, t1, true, "2020-02-01T00:00:00", "2020-02-01T00:00:00.000");
|
||||
singleTimeTest(testT, t1, false, "2020-02-01T00:00:00", "2020-02-01T00:00:00.000");
|
||||
singleTimeTest(testT, t1, true, "2020-02-29T00:00:02", "2020-02-29T00:00:00.000");
|
||||
singleTimeTest(testT, t1, true, "2020-01-01T00:00:00", "2020-01-01T00:00:00.000");
|
||||
singleTimeTest(testT, t1, true, "2020-03-02T14:00:00", "2020-03-01T00:00:00.000");
|
||||
singleTimeTest(testT, t1, true, "2019-12-15T14:00:00", "2019-12-15T00:00:00.000");
|
||||
singleTimeTest(testT, t1, true, "2019-12-08T23:59:00", "2019-12-09T00:00:00.000");
|
||||
singleTimeTest(testT, t1, true, "2019-12-05T14:29:00", "2019-12-09T00:00:00.000");
|
||||
|
||||
t1.setStartEndRange("2017-01-28T08:00:00", "2020-09-01T08:00:00");
|
||||
t1.setResolution("1M");
|
||||
|
||||
singleTimeTest(testT, t1, true, "2017-03-03T05:15:45", "2017-02-28T08:00:00.000");
|
||||
singleTimeTest(testT, t1, true, "2017-03-29T08:15:45", "2017-03-28T08:00:00.000");
|
||||
|
||||
t1.setStartEndRange("2016-01-17T08:00:00", "2020-09-01T08:00:00");
|
||||
t1.setResolution("2M");
|
||||
|
||||
singleTimeTest(testT, t1, true, "2016-01-27T05:15:45", "2016-01-17T08:00:00.000");
|
||||
singleTimeTest(testT, t1, true, "2016-03-16T08:15:45", "2016-01-17T08:00:00.000");
|
||||
singleTimeTest(testT, t1, true, "2016-03-17T18:00:02", "2016-03-17T08:00:00.000");
|
||||
singleTimeTest(testT, t1, true, "2016-05-18T08:00:02", "2016-05-17T08:00:00.000");
|
||||
singleTimeTest(testT, t1, true, "2016-11-17T10:15:45", "2016-11-17T08:00:00.000");
|
||||
singleTimeTest(testT, t1, true, "2017-01-18T05:15:45", "2017-01-17T08:00:00.000");
|
||||
|
||||
t1.setResolution("3M");
|
||||
|
||||
singleTimeTest(testT, t1, true, "2016-04-16T05:15:45", "2016-01-17T08:00:00.000");
|
||||
singleTimeTest(testT, t1, true, "2016-07-27T05:15:45", "2016-07-17T08:00:00.000");
|
||||
singleTimeTest(testT, t1, true, "2017-10-17T08:01:00", "2017-10-17T08:00:00.000");
|
||||
|
||||
t1.setStartEndRange("2016-05-29T03:00:00", "2021-09-01T08:00:00");
|
||||
t1.setResolution("6M");
|
||||
|
||||
singleTimeTest(testT, t1, true, "2016-11-29T03:00:05", "2016-11-29T03:00:00.000");
|
||||
singleTimeTest(testT, t1, true, "2017-05-29T04:15:45", "2017-05-29T03:00:00.000");
|
||||
singleTimeTest(testT, t1, true, "2017-10-17T08:01:00", "2017-05-29T03:00:00.000");
|
||||
|
||||
t1.setStartEndRange("2016-05-29T03:00:00", "2021-09-01T08:00:00");
|
||||
t1.setResolution("4d");
|
||||
|
||||
singleTimeTest(testT, t1, true, "2016-06-02T03:00:00", "2016-06-02T03:00:00.000");
|
||||
singleTimeTest(testT, t1, true, "2016-06-02T03:00:01", "2016-06-02T03:00:00.000");
|
||||
singleTimeTest(testT, t1, true, "2016-07-04T13:00:00", "2016-07-04T03:00:00.000");
|
||||
singleTimeTest(testT, t1, true, "2016-07-08T03:00:00", "2016-07-08T03:00:00.000");
|
||||
|
||||
t1.setStartEndRange("2019-02-21T03:00:00", "2021-09-01T08:00:00");
|
||||
t1.setResolution("11d");
|
||||
|
||||
singleTimeTest(testT, t1, true, "2020-03-01T03:30:00", "2020-03-01T03:00:00.000");
|
||||
singleTimeTest(testT, t1, true, "2019-03-04T03:00:02", "2019-03-04T03:00:00.000");
|
||||
|
||||
t1.setStartEndRange("2019-02-21T00:00:00", "2021-09-01T00:00:00");
|
||||
t1.setResolution("2h");
|
||||
|
||||
singleTimeTest(testT, t1, true, "2019-02-28T16:10:00", "2019-02-28T16:00:00.000");
|
||||
singleTimeTest(testT, t1, true, "2019-02-28T22:00:00", "2019-02-28T22:00:00.000");
|
||||
|
||||
t1.setResolution("3h");
|
||||
|
||||
singleTimeTest(testT, t1, true, "2019-02-28T21:10:00", "2019-02-28T21:00:00.000");
|
||||
singleTimeTest(testT, t1, true, "2019-02-28T12:00:00", "2019-02-28T12:00:00.000");
|
||||
|
||||
t1.setStartEndRange("2019-02-21T00:00:00", "2021-09-01T00:00:00");
|
||||
t1.setResolution("30m");
|
||||
|
||||
singleTimeTest(testT, t1, true, "2019-02-27T16:40:00", "2019-02-27T16:30:00.000");
|
||||
singleTimeTest(testT, t1, true, "2019-02-28T22:00:00", "2019-02-28T22:00:00.000");
|
||||
singleTimeTest(testT, t1, true, "2019-02-28T22:30:01", "2019-02-28T22:30:00.000");
|
||||
singleTimeTest(testT, t1, true, "2019-02-28T21:29:59", "2019-02-28T21:00:00.000");
|
||||
singleTimeTest(testT, t1, true, "2019-02-28T22:59:59", "2019-02-28T22:30:00.000");
|
||||
|
||||
t1.setResolution("15m");
|
||||
|
||||
singleTimeTest(testT, t1, true, "2019-02-28T16:40:00", "2019-02-28T16:30:00.000");
|
||||
singleTimeTest(testT, t1, true, "2019-02-28T22:00:00", "2019-02-28T22:00:00.000");
|
||||
singleTimeTest(testT, t1, true, "2019-02-28T22:30:01", "2019-02-28T22:30:00.000");
|
||||
singleTimeTest(testT, t1, true, "2019-02-28T22:15:01", "2019-02-28T22:15:00.000");
|
||||
singleTimeTest(testT, t1, true, "2019-02-28T22:29:59", "2019-02-28T22:15:00.000");
|
||||
singleTimeTest(testT, t1, true, "2019-02-28T22:59:59", "2019-02-28T22:45:00.000");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user