[smhi] Fix exception in aggregation function when daily forecast is empty (#10851)
* Fix exception in aggregation function when daily forecast is empty Also catch any Exception to prevent thread from crashing Signed-off-by: Anders Alfredsson <andersb86@gmail.com> * Refactor to improve robustness of calculations Improve tests to cover different forecast scenarios Signed-off-by: Anders Alfredsson <andersb86@gmail.com>
This commit is contained in:
+56
-5
@@ -13,7 +13,8 @@
|
||||
package org.openhab.binding.smhi.internal;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -24,23 +25,73 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ForecastAggregator {
|
||||
/**
|
||||
* Get the maximum value for the specified parameter for the n:th day after the forecast's reference time
|
||||
*
|
||||
* @param timeSeries
|
||||
* @param dayOffset
|
||||
* @param parameter
|
||||
* @return
|
||||
*/
|
||||
public static Optional<BigDecimal> max(TimeSeries timeSeries, int dayOffset, String parameter) {
|
||||
List<Forecast> dayForecasts = timeSeries.getDay(dayOffset);
|
||||
return dayForecasts.stream().map(forecast -> forecast.getParameter(parameter)).filter(Optional::isPresent)
|
||||
.map(Optional::get).max(BigDecimal::compareTo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the minimum value for the specified parameter for the n:th day after the forecast's reference time
|
||||
*
|
||||
* @param timeSeries
|
||||
* @param dayOffset
|
||||
* @param parameter
|
||||
* @return
|
||||
*/
|
||||
public static Optional<BigDecimal> min(TimeSeries timeSeries, int dayOffset, String parameter) {
|
||||
List<Forecast> dayForecasts = timeSeries.getDay(dayOffset);
|
||||
return dayForecasts.stream().map(forecast -> forecast.getParameter(parameter)).filter(Optional::isPresent)
|
||||
.map(Optional::get).min(BigDecimal::compareTo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the total value for the specified parameter for the n:th day after the forecast's reference time.
|
||||
* If there aren't any values for every hour, the previous value is used for each empty slot.
|
||||
*
|
||||
* @param timeSeries
|
||||
* @param dayOffset
|
||||
* @param parameter
|
||||
* @return
|
||||
*/
|
||||
public static Optional<BigDecimal> total(TimeSeries timeSeries, int dayOffset, String parameter) {
|
||||
List<Forecast> dayForecasts = timeSeries.getDay(dayOffset);
|
||||
BigDecimal sum = dayForecasts.stream().map(forecast -> forecast.getParameter(parameter))
|
||||
.filter(Optional::isPresent).map(Optional::get).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
|
||||
BigDecimal mean = sum.divide(BigDecimal.valueOf(dayForecasts.size()), RoundingMode.HALF_UP);
|
||||
return Optional.of(mean.multiply(BigDecimal.valueOf(24)));
|
||||
List<BigDecimal> values = new ArrayList<>();
|
||||
for (int i = 0; i < dayForecasts.size(); i++) {
|
||||
Forecast current = dayForecasts.get(i);
|
||||
long hours;
|
||||
if (i == 0) {
|
||||
hours = current.getValidTime().until(dayForecasts.get(i + 1).getValidTime(), ChronoUnit.HOURS);
|
||||
} else {
|
||||
hours = dayForecasts.get(i - 1).getValidTime().until(current.getValidTime(), ChronoUnit.HOURS);
|
||||
}
|
||||
values.add(current.getParameter(parameter).map(value -> value.multiply(BigDecimal.valueOf(hours)))
|
||||
.orElse(BigDecimal.ZERO));
|
||||
}
|
||||
return values.stream().reduce(BigDecimal::add);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value at 12:00 UTC for the specified parameter for the n:th day after the forecast's reference time.
|
||||
* If that time is not included (should only happen for day 0 if after 12:00), get the first value for the day
|
||||
* instead.
|
||||
*
|
||||
* @param timeSeries
|
||||
* @param dayOffset
|
||||
* @param parameter
|
||||
* @return
|
||||
*/
|
||||
public static Optional<BigDecimal> noonOrFirst(TimeSeries timeSeries, int dayOffset, String parameter) {
|
||||
List<Forecast> dayForecasts = timeSeries.getDay(dayOffset);
|
||||
return dayForecasts.stream().filter(forecast -> forecast.getValidTime().getHour() >= 12).findFirst()
|
||||
.flatMap(forecast -> forecast.getParameter(parameter));
|
||||
}
|
||||
}
|
||||
|
||||
+34
-67
@@ -63,7 +63,6 @@ public class SmhiHandler extends BaseThingHandler {
|
||||
private final HttpClient httpClient;
|
||||
private @Nullable SmhiConnector connection;
|
||||
private ZonedDateTime currentHour;
|
||||
private ZonedDateTime currentDay;
|
||||
private @Nullable TimeSeries cachedTimeSeries;
|
||||
private boolean hasLatestForecast = false;
|
||||
private @Nullable Future<?> forecastUpdater;
|
||||
@@ -73,7 +72,6 @@ public class SmhiHandler extends BaseThingHandler {
|
||||
super(thing);
|
||||
this.httpClient = httpClient;
|
||||
this.currentHour = calculateCurrentHour();
|
||||
this.currentDay = calculateCurrentDay();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -142,7 +140,7 @@ public class SmhiHandler extends BaseThingHandler {
|
||||
if (channels.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
Optional<Forecast> forecast = timeSeries.getForecast(i);
|
||||
Optional<Forecast> forecast = timeSeries.getForecast(currentHour, i);
|
||||
if (forecast.isPresent()) {
|
||||
channels.forEach(c -> {
|
||||
String id = c.getUID().getIdWithoutGroup();
|
||||
@@ -159,28 +157,10 @@ public class SmhiHandler extends BaseThingHandler {
|
||||
}
|
||||
|
||||
int dayOffset = i;
|
||||
int hourOffset = 24 * dayOffset + 12;
|
||||
Optional<Forecast> forecast = timeSeries.getForecast(currentDay, hourOffset);
|
||||
|
||||
if (forecast.isEmpty()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("No forecast yet for {}", currentDay.plusHours(hourOffset));
|
||||
}
|
||||
channels.forEach(c -> {
|
||||
updateState(c.getUID(), UnDefType.UNDEF);
|
||||
});
|
||||
} else {
|
||||
channels.forEach(c -> {
|
||||
String id = c.getUID().getIdWithoutGroup();
|
||||
Optional<BigDecimal> value;
|
||||
if (isAggregatedChannel(id)) {
|
||||
value = getAggregatedValue(id, timeSeries, dayOffset);
|
||||
} else {
|
||||
value = forecast.get().getParameter(id);
|
||||
}
|
||||
updateChannel(c, value);
|
||||
});
|
||||
}
|
||||
channels.forEach(c -> {
|
||||
String id = c.getUID().getIdWithoutGroup();
|
||||
updateChannel(c, getDayValue(id, timeSeries, dayOffset));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,18 +238,22 @@ public class SmhiHandler extends BaseThingHandler {
|
||||
* published, in that case, fetch it and update channels.
|
||||
*/
|
||||
private void waitForForecast() {
|
||||
if (isItNewHour()) {
|
||||
currentHour = calculateCurrentHour();
|
||||
currentDay = calculateCurrentDay();
|
||||
// Update channels with cached forecasts - just shift an hour forward
|
||||
TimeSeries forecast = cachedTimeSeries;
|
||||
if (forecast != null) {
|
||||
updateChannels(forecast);
|
||||
try {
|
||||
if (isItNewHour()) {
|
||||
currentHour = calculateCurrentHour();
|
||||
// Update channels with cached forecasts - just shift an hour forward
|
||||
TimeSeries forecast = cachedTimeSeries;
|
||||
if (forecast != null) {
|
||||
updateChannels(forecast);
|
||||
}
|
||||
hasLatestForecast = false;
|
||||
}
|
||||
hasLatestForecast = false;
|
||||
}
|
||||
if (!hasLatestForecast && isForecastUpdated()) {
|
||||
getUpdatedForecast();
|
||||
if (!hasLatestForecast && isForecastUpdated()) {
|
||||
getUpdatedForecast();
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
logger.warn("Unexpected exception occurred, please report to the developers: {}: {}", e.getClass(),
|
||||
e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,7 +309,7 @@ public class SmhiHandler extends BaseThingHandler {
|
||||
try {
|
||||
forecast = apiConnection.getForecast(config.latitude, config.longitude);
|
||||
} catch (SmhiException e) {
|
||||
String message = e.getCause() == null ? e.getMessage() : e.getCause().getMessage();
|
||||
String message = Optional.ofNullable(e.getCause()).orElse(e).getMessage();
|
||||
logger.debug("Failed to get new forecast: {}", message);
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, message);
|
||||
return;
|
||||
@@ -359,23 +343,10 @@ public class SmhiHandler extends BaseThingHandler {
|
||||
return ZonedDateTime.of(y, m, d, h, 0, 0, 0, ZoneOffset.UTC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current time rounded down to day
|
||||
*
|
||||
* @return A {@link ZonedDateTime} corresponding to the last even day.
|
||||
*/
|
||||
private ZonedDateTime calculateCurrentDay() {
|
||||
ZonedDateTime now = ZonedDateTime.now().withZoneSameInstant(ZoneOffset.UTC);
|
||||
int y = now.getYear();
|
||||
int m = now.getMonth().getValue();
|
||||
int d = now.getDayOfMonth();
|
||||
return ZonedDateTime.of(y, m, d, 0, 0, 0, 0, ZoneOffset.UTC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates channels based on selections in thing configuration
|
||||
*
|
||||
* @return
|
||||
* @return A List of Channels to add to the Thing
|
||||
*/
|
||||
private List<Channel> createChannels() {
|
||||
List<Channel> channels = new ArrayList<>();
|
||||
@@ -430,6 +401,7 @@ public class SmhiHandler extends BaseThingHandler {
|
||||
break;
|
||||
case WIND_DIRECTION:
|
||||
itemType += ":Angle";
|
||||
break;
|
||||
case WIND_SPEED:
|
||||
case WIND_MAX:
|
||||
case WIND_MIN:
|
||||
@@ -456,21 +428,16 @@ public class SmhiHandler extends BaseThingHandler {
|
||||
return channel;
|
||||
}
|
||||
|
||||
private boolean isAggregatedChannel(String channelId) {
|
||||
switch (channelId) {
|
||||
case TEMPERATURE_MAX:
|
||||
case TEMPERATURE_MIN:
|
||||
case WIND_MAX:
|
||||
case WIND_MIN:
|
||||
case PRECIPITATION_TOTAL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<BigDecimal> getAggregatedValue(String channelId, TimeSeries timeSeries, int dayOffset) {
|
||||
switch (channelId) {
|
||||
/**
|
||||
* Gets the value that represents the day forecast for a specified day and channel
|
||||
*
|
||||
* @param parameter The parameter to retrieve or calculate
|
||||
* @param timeSeries A TimeSeries object containing forecasts
|
||||
* @param dayOffset The number of days from the start of the TimeSeries
|
||||
* @return An Optional containing the retrieved or calculated value
|
||||
*/
|
||||
private Optional<BigDecimal> getDayValue(String parameter, TimeSeries timeSeries, int dayOffset) {
|
||||
switch (parameter) {
|
||||
case TEMPERATURE_MAX:
|
||||
return ForecastAggregator.max(timeSeries, dayOffset, TEMPERATURE);
|
||||
case TEMPERATURE_MIN:
|
||||
@@ -482,7 +449,7 @@ public class SmhiHandler extends BaseThingHandler {
|
||||
case PRECIPITATION_TOTAL:
|
||||
return ForecastAggregator.total(timeSeries, dayOffset, PRECIPITATION_MEAN);
|
||||
default:
|
||||
return Optional.empty();
|
||||
return ForecastAggregator.noonOrFirst(timeSeries, dayOffset, parameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-1
@@ -72,8 +72,14 @@ public class TimeSeries implements Iterable<Forecast> {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all Forecasts for the n:th day after the start of the TimeSeries
|
||||
*
|
||||
* @param dayOffset
|
||||
* @return
|
||||
*/
|
||||
public List<Forecast> getDay(int dayOffset) {
|
||||
ZonedDateTime day = referenceTime.plusDays(dayOffset);
|
||||
ZonedDateTime day = referenceTime.plusDays(dayOffset).plusHours(1);
|
||||
return forecasts.stream().filter(forecast -> forecast.getValidTime().getDayOfMonth() == day.getDayOfMonth())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
+238
-58
@@ -21,6 +21,7 @@ import java.math.BigDecimal;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -29,18 +30,29 @@ import org.junit.jupiter.api.Test;
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SmhiTest {
|
||||
private static final ZonedDateTime TIME = ZonedDateTime.parse("2020-12-13T08:15:00Z");
|
||||
private @NonNullByDefault({}) TimeSeries timeSeries;
|
||||
private static final ZonedDateTime TIME = ZonedDateTime.parse("2021-06-13T07:00:00Z");
|
||||
private @NonNullByDefault({}) TimeSeries timeSeries1;
|
||||
private @NonNullByDefault({}) TimeSeries timeSeries2;
|
||||
private @NonNullByDefault({}) TimeSeries timeSeries3;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
try {
|
||||
InputStream is = SmhiTest.class.getResourceAsStream("forecast.json");
|
||||
if (is == null) {
|
||||
@Nullable
|
||||
InputStream is1 = SmhiTest.class.getResourceAsStream("forecast1.json");
|
||||
@Nullable
|
||||
InputStream is2 = SmhiTest.class.getResourceAsStream("forecast2.json");
|
||||
@Nullable
|
||||
InputStream is3 = SmhiTest.class.getResourceAsStream("forecast3.json");
|
||||
if (is1 == null || is2 == null || is3 == null) {
|
||||
throw new AssertionError("Couldn't read forecast example");
|
||||
}
|
||||
String jsonString = new String(is.readAllBytes());
|
||||
timeSeries = Parser.parseTimeSeries(jsonString);
|
||||
String str1 = new String(is1.readAllBytes());
|
||||
String str2 = new String(is2.readAllBytes());
|
||||
String str3 = new String(is3.readAllBytes());
|
||||
timeSeries1 = Parser.parseTimeSeries(str1);
|
||||
timeSeries2 = Parser.parseTimeSeries(str2);
|
||||
timeSeries3 = Parser.parseTimeSeries(str3);
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError("Couldn't read forecast example");
|
||||
}
|
||||
@@ -48,64 +60,232 @@ public class SmhiTest {
|
||||
|
||||
@Test
|
||||
public void parameterTest() {
|
||||
assertNotNull(timeSeries);
|
||||
Forecast forecast = timeSeries.getForecast(TIME, 0).orElseThrow(AssertionError::new);
|
||||
assertNotNull(timeSeries1);
|
||||
Forecast forecast0 = timeSeries1.getForecast(TIME, 0).orElseThrow(AssertionError::new);
|
||||
|
||||
BigDecimal msl = forecast.getParameter(PRESSURE).orElseThrow(AssertionError::new);
|
||||
BigDecimal t = forecast.getParameter(TEMPERATURE).orElseThrow(AssertionError::new);
|
||||
BigDecimal vis = forecast.getParameter(VISIBILITY).orElseThrow(AssertionError::new);
|
||||
BigDecimal wd = forecast.getParameter(WIND_DIRECTION).orElseThrow(AssertionError::new);
|
||||
BigDecimal ws = forecast.getParameter(WIND_SPEED).orElseThrow(AssertionError::new);
|
||||
BigDecimal r = forecast.getParameter(RELATIVE_HUMIDITY).orElseThrow(AssertionError::new);
|
||||
BigDecimal tstm = forecast.getParameter(THUNDER_PROBABILITY).orElseThrow(AssertionError::new);
|
||||
BigDecimal tcc = forecast.getParameter(TOTAL_CLOUD_COVER).orElseThrow(AssertionError::new);
|
||||
BigDecimal lcc = forecast.getParameter(LOW_CLOUD_COVER).orElseThrow(AssertionError::new);
|
||||
BigDecimal mcc = forecast.getParameter(MEDIUM_CLOUD_COVER).orElseThrow(AssertionError::new);
|
||||
BigDecimal hcc = forecast.getParameter(HIGH_CLOUD_COVER).orElseThrow(AssertionError::new);
|
||||
BigDecimal gust = forecast.getParameter(GUST).orElseThrow(AssertionError::new);
|
||||
BigDecimal pmin = forecast.getParameter(PRECIPITATION_MIN).orElseThrow(AssertionError::new);
|
||||
BigDecimal pmax = forecast.getParameter(PRECIPITATION_MAX).orElseThrow(AssertionError::new);
|
||||
BigDecimal spp = forecast.getParameter(PERCENT_FROZEN).orElseThrow(AssertionError::new);
|
||||
BigDecimal pcat = forecast.getParameter(PRECIPITATION_CATEGORY).orElseThrow(AssertionError::new);
|
||||
BigDecimal pmean = forecast.getParameter(PRECIPITATION_MEAN).orElseThrow(AssertionError::new);
|
||||
BigDecimal pmedian = forecast.getParameter(PRECIPITATION_MEDIAN).orElseThrow(AssertionError::new);
|
||||
BigDecimal wsymb = forecast.getParameter(WEATHER_SYMBOL).orElseThrow(AssertionError::new);
|
||||
BigDecimal msl0 = forecast0.getParameter(PRESSURE).orElseThrow(AssertionError::new);
|
||||
BigDecimal t0 = forecast0.getParameter(TEMPERATURE).orElseThrow(AssertionError::new);
|
||||
BigDecimal vis0 = forecast0.getParameter(VISIBILITY).orElseThrow(AssertionError::new);
|
||||
BigDecimal wd0 = forecast0.getParameter(WIND_DIRECTION).orElseThrow(AssertionError::new);
|
||||
BigDecimal ws0 = forecast0.getParameter(WIND_SPEED).orElseThrow(AssertionError::new);
|
||||
BigDecimal r0 = forecast0.getParameter(RELATIVE_HUMIDITY).orElseThrow(AssertionError::new);
|
||||
BigDecimal tstm0 = forecast0.getParameter(THUNDER_PROBABILITY).orElseThrow(AssertionError::new);
|
||||
BigDecimal tcc0 = forecast0.getParameter(TOTAL_CLOUD_COVER).orElseThrow(AssertionError::new);
|
||||
BigDecimal lcc0 = forecast0.getParameter(LOW_CLOUD_COVER).orElseThrow(AssertionError::new);
|
||||
BigDecimal mcc0 = forecast0.getParameter(MEDIUM_CLOUD_COVER).orElseThrow(AssertionError::new);
|
||||
BigDecimal hcc0 = forecast0.getParameter(HIGH_CLOUD_COVER).orElseThrow(AssertionError::new);
|
||||
BigDecimal gust0 = forecast0.getParameter(GUST).orElseThrow(AssertionError::new);
|
||||
BigDecimal pmin0 = forecast0.getParameter(PRECIPITATION_MIN).orElseThrow(AssertionError::new);
|
||||
BigDecimal pmax0 = forecast0.getParameter(PRECIPITATION_MAX).orElseThrow(AssertionError::new);
|
||||
BigDecimal spp0 = forecast0.getParameter(PERCENT_FROZEN).orElseThrow(AssertionError::new);
|
||||
BigDecimal pcat0 = forecast0.getParameter(PRECIPITATION_CATEGORY).orElseThrow(AssertionError::new);
|
||||
BigDecimal pmean0 = forecast0.getParameter(PRECIPITATION_MEAN).orElseThrow(AssertionError::new);
|
||||
BigDecimal pmedian0 = forecast0.getParameter(PRECIPITATION_MEDIAN).orElseThrow(AssertionError::new);
|
||||
BigDecimal wsymb0 = forecast0.getParameter(WEATHER_SYMBOL).orElseThrow(AssertionError::new);
|
||||
|
||||
assertEquals(0, msl.compareTo(BigDecimal.valueOf(1013.7)));
|
||||
assertEquals(0, t.compareTo(BigDecimal.valueOf(3.0)));
|
||||
assertEquals(0, vis.compareTo(BigDecimal.valueOf(24.3)));
|
||||
assertEquals(0, wd.compareTo(BigDecimal.valueOf(110)));
|
||||
assertEquals(0, ws.compareTo(BigDecimal.valueOf(1.5)));
|
||||
assertEquals(0, r.compareTo(BigDecimal.valueOf(96)));
|
||||
assertEquals(0, tstm.compareTo(BigDecimal.valueOf(0)));
|
||||
assertEquals(0, tcc.compareTo(BigDecimal.valueOf(8)));
|
||||
assertEquals(0, lcc.compareTo(BigDecimal.valueOf(8)));
|
||||
assertEquals(0, mcc.compareTo(BigDecimal.valueOf(4)));
|
||||
assertEquals(0, hcc.compareTo(BigDecimal.valueOf(0)));
|
||||
assertEquals(0, gust.compareTo(BigDecimal.valueOf(3.0)));
|
||||
assertEquals(0, pmin.compareTo(BigDecimal.valueOf(0.0)));
|
||||
assertEquals(0, pmax.compareTo(BigDecimal.valueOf(0.0)));
|
||||
assertEquals(0, spp.compareTo(BigDecimal.valueOf(-9)));
|
||||
assertEquals(0, pcat.compareTo(BigDecimal.valueOf(0)));
|
||||
assertEquals(0, pmean.compareTo(BigDecimal.valueOf(0.0)));
|
||||
assertEquals(0, pmedian.compareTo(BigDecimal.valueOf(0.0)));
|
||||
assertEquals(0, wsymb.compareTo(BigDecimal.valueOf(6)));
|
||||
assertEquals(0, msl0.compareTo(BigDecimal.valueOf(1014.1)));
|
||||
assertEquals(0, t0.compareTo(BigDecimal.valueOf(18.2)));
|
||||
assertEquals(0, vis0.compareTo(BigDecimal.valueOf(28.4)));
|
||||
assertEquals(0, wd0.compareTo(BigDecimal.valueOf(313)));
|
||||
assertEquals(0, ws0.compareTo(BigDecimal.valueOf(2)));
|
||||
assertEquals(0, r0.compareTo(BigDecimal.valueOf(52)));
|
||||
assertEquals(0, tstm0.compareTo(BigDecimal.valueOf(0)));
|
||||
assertEquals(0, tcc0.compareTo(BigDecimal.valueOf(3)));
|
||||
assertEquals(0, lcc0.compareTo(BigDecimal.valueOf(0)));
|
||||
assertEquals(0, mcc0.compareTo(BigDecimal.valueOf(2)));
|
||||
assertEquals(0, hcc0.compareTo(BigDecimal.valueOf(0)));
|
||||
assertEquals(0, gust0.compareTo(BigDecimal.valueOf(6.9)));
|
||||
assertEquals(0, pmin0.compareTo(BigDecimal.valueOf(0)));
|
||||
assertEquals(0, pmax0.compareTo(BigDecimal.valueOf(0)));
|
||||
assertEquals(0, spp0.compareTo(BigDecimal.valueOf(-9)));
|
||||
assertEquals(0, pcat0.compareTo(BigDecimal.valueOf(0)));
|
||||
assertEquals(0, pmean0.compareTo(BigDecimal.valueOf(0)));
|
||||
assertEquals(0, pmedian0.compareTo(BigDecimal.valueOf(0)));
|
||||
assertEquals(0, wsymb0.compareTo(BigDecimal.valueOf(2)));
|
||||
|
||||
Forecast forecast1 = timeSeries1.getForecast(TIME.plusHours(1), 0).orElseThrow(AssertionError::new);
|
||||
|
||||
BigDecimal msl1 = forecast1.getParameter(PRESSURE).orElseThrow(AssertionError::new);
|
||||
BigDecimal t1 = forecast1.getParameter(TEMPERATURE).orElseThrow(AssertionError::new);
|
||||
BigDecimal vis1 = forecast1.getParameter(VISIBILITY).orElseThrow(AssertionError::new);
|
||||
BigDecimal wd1 = forecast1.getParameter(WIND_DIRECTION).orElseThrow(AssertionError::new);
|
||||
BigDecimal ws1 = forecast1.getParameter(WIND_SPEED).orElseThrow(AssertionError::new);
|
||||
BigDecimal r1 = forecast1.getParameter(RELATIVE_HUMIDITY).orElseThrow(AssertionError::new);
|
||||
BigDecimal tstm1 = forecast1.getParameter(THUNDER_PROBABILITY).orElseThrow(AssertionError::new);
|
||||
BigDecimal tcc1 = forecast1.getParameter(TOTAL_CLOUD_COVER).orElseThrow(AssertionError::new);
|
||||
BigDecimal lcc1 = forecast1.getParameter(LOW_CLOUD_COVER).orElseThrow(AssertionError::new);
|
||||
BigDecimal mcc1 = forecast1.getParameter(MEDIUM_CLOUD_COVER).orElseThrow(AssertionError::new);
|
||||
BigDecimal hcc1 = forecast1.getParameter(HIGH_CLOUD_COVER).orElseThrow(AssertionError::new);
|
||||
BigDecimal gust1 = forecast1.getParameter(GUST).orElseThrow(AssertionError::new);
|
||||
BigDecimal pmin1 = forecast1.getParameter(PRECIPITATION_MIN).orElseThrow(AssertionError::new);
|
||||
BigDecimal pmax1 = forecast1.getParameter(PRECIPITATION_MAX).orElseThrow(AssertionError::new);
|
||||
BigDecimal spp1 = forecast1.getParameter(PERCENT_FROZEN).orElseThrow(AssertionError::new);
|
||||
BigDecimal pcat1 = forecast1.getParameter(PRECIPITATION_CATEGORY).orElseThrow(AssertionError::new);
|
||||
BigDecimal pmean1 = forecast1.getParameter(PRECIPITATION_MEAN).orElseThrow(AssertionError::new);
|
||||
BigDecimal pmedian1 = forecast1.getParameter(PRECIPITATION_MEDIAN).orElseThrow(AssertionError::new);
|
||||
BigDecimal wsymb1 = forecast1.getParameter(WEATHER_SYMBOL).orElseThrow(AssertionError::new);
|
||||
|
||||
assertEquals(0, msl1.compareTo(BigDecimal.valueOf(1014.5)));
|
||||
assertEquals(0, t1.compareTo(BigDecimal.valueOf(19.2)));
|
||||
assertEquals(0, vis1.compareTo(BigDecimal.valueOf(30.3)));
|
||||
assertEquals(0, wd1.compareTo(BigDecimal.valueOf(307)));
|
||||
assertEquals(0, ws1.compareTo(BigDecimal.valueOf(2.5)));
|
||||
assertEquals(0, r1.compareTo(BigDecimal.valueOf(48)));
|
||||
assertEquals(0, tstm1.compareTo(BigDecimal.valueOf(0)));
|
||||
assertEquals(0, tcc1.compareTo(BigDecimal.valueOf(4)));
|
||||
assertEquals(0, lcc1.compareTo(BigDecimal.valueOf(1)));
|
||||
assertEquals(0, mcc1.compareTo(BigDecimal.valueOf(3)));
|
||||
assertEquals(0, hcc1.compareTo(BigDecimal.valueOf(0)));
|
||||
assertEquals(0, gust1.compareTo(BigDecimal.valueOf(7.9)));
|
||||
assertEquals(0, pmin1.compareTo(BigDecimal.valueOf(0)));
|
||||
assertEquals(0, pmax1.compareTo(BigDecimal.valueOf(0)));
|
||||
assertEquals(0, spp1.compareTo(BigDecimal.valueOf(-9)));
|
||||
assertEquals(0, pcat1.compareTo(BigDecimal.valueOf(0)));
|
||||
assertEquals(0, pmean1.compareTo(BigDecimal.valueOf(0)));
|
||||
assertEquals(0, pmedian1.compareTo(BigDecimal.valueOf(0)));
|
||||
assertEquals(0, wsymb1.compareTo(BigDecimal.valueOf(3)));
|
||||
|
||||
Forecast forecast2 = timeSeries1.getForecast(TIME, 1).orElseThrow(AssertionError::new);
|
||||
|
||||
BigDecimal msl2 = forecast2.getParameter(PRESSURE).orElseThrow(AssertionError::new);
|
||||
BigDecimal t2 = forecast2.getParameter(TEMPERATURE).orElseThrow(AssertionError::new);
|
||||
BigDecimal vis2 = forecast2.getParameter(VISIBILITY).orElseThrow(AssertionError::new);
|
||||
BigDecimal wd2 = forecast2.getParameter(WIND_DIRECTION).orElseThrow(AssertionError::new);
|
||||
BigDecimal ws2 = forecast2.getParameter(WIND_SPEED).orElseThrow(AssertionError::new);
|
||||
BigDecimal r2 = forecast2.getParameter(RELATIVE_HUMIDITY).orElseThrow(AssertionError::new);
|
||||
BigDecimal tstm2 = forecast2.getParameter(THUNDER_PROBABILITY).orElseThrow(AssertionError::new);
|
||||
BigDecimal tcc2 = forecast2.getParameter(TOTAL_CLOUD_COVER).orElseThrow(AssertionError::new);
|
||||
BigDecimal lcc2 = forecast2.getParameter(LOW_CLOUD_COVER).orElseThrow(AssertionError::new);
|
||||
BigDecimal mcc2 = forecast2.getParameter(MEDIUM_CLOUD_COVER).orElseThrow(AssertionError::new);
|
||||
BigDecimal hcc2 = forecast2.getParameter(HIGH_CLOUD_COVER).orElseThrow(AssertionError::new);
|
||||
BigDecimal gust2 = forecast2.getParameter(GUST).orElseThrow(AssertionError::new);
|
||||
BigDecimal pmin2 = forecast2.getParameter(PRECIPITATION_MIN).orElseThrow(AssertionError::new);
|
||||
BigDecimal pmax2 = forecast2.getParameter(PRECIPITATION_MAX).orElseThrow(AssertionError::new);
|
||||
BigDecimal spp2 = forecast2.getParameter(PERCENT_FROZEN).orElseThrow(AssertionError::new);
|
||||
BigDecimal pcat2 = forecast2.getParameter(PRECIPITATION_CATEGORY).orElseThrow(AssertionError::new);
|
||||
BigDecimal pmean2 = forecast2.getParameter(PRECIPITATION_MEAN).orElseThrow(AssertionError::new);
|
||||
BigDecimal pmedian2 = forecast2.getParameter(PRECIPITATION_MEDIAN).orElseThrow(AssertionError::new);
|
||||
BigDecimal wsymb2 = forecast2.getParameter(WEATHER_SYMBOL).orElseThrow(AssertionError::new);
|
||||
|
||||
assertEquals(0, msl2.compareTo(BigDecimal.valueOf(1014.5)));
|
||||
assertEquals(0, t2.compareTo(BigDecimal.valueOf(19.2)));
|
||||
assertEquals(0, vis2.compareTo(BigDecimal.valueOf(30.3)));
|
||||
assertEquals(0, wd2.compareTo(BigDecimal.valueOf(307)));
|
||||
assertEquals(0, ws2.compareTo(BigDecimal.valueOf(2.5)));
|
||||
assertEquals(0, r2.compareTo(BigDecimal.valueOf(48)));
|
||||
assertEquals(0, tstm2.compareTo(BigDecimal.valueOf(0)));
|
||||
assertEquals(0, tcc2.compareTo(BigDecimal.valueOf(4)));
|
||||
assertEquals(0, lcc2.compareTo(BigDecimal.valueOf(1)));
|
||||
assertEquals(0, mcc2.compareTo(BigDecimal.valueOf(3)));
|
||||
assertEquals(0, hcc2.compareTo(BigDecimal.valueOf(0)));
|
||||
assertEquals(0, gust2.compareTo(BigDecimal.valueOf(7.9)));
|
||||
assertEquals(0, pmin2.compareTo(BigDecimal.valueOf(0)));
|
||||
assertEquals(0, pmax2.compareTo(BigDecimal.valueOf(0)));
|
||||
assertEquals(0, spp2.compareTo(BigDecimal.valueOf(-9)));
|
||||
assertEquals(0, pcat2.compareTo(BigDecimal.valueOf(0)));
|
||||
assertEquals(0, pmean2.compareTo(BigDecimal.valueOf(0)));
|
||||
assertEquals(0, pmedian2.compareTo(BigDecimal.valueOf(0)));
|
||||
assertEquals(0, wsymb2.compareTo(BigDecimal.valueOf(3)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void aggregationsTest() {
|
||||
assertNotNull(timeSeries);
|
||||
BigDecimal maxTemp = ForecastAggregator.max(timeSeries, 5, TEMPERATURE).orElseThrow(AssertionError::new);
|
||||
BigDecimal minTemp = ForecastAggregator.min(timeSeries, 5, TEMPERATURE).orElseThrow(AssertionError::new);
|
||||
BigDecimal maxWind = ForecastAggregator.max(timeSeries, 5, WIND_SPEED).orElseThrow(AssertionError::new);
|
||||
BigDecimal minWind = ForecastAggregator.min(timeSeries, 5, WIND_SPEED).orElseThrow(AssertionError::new);
|
||||
BigDecimal totalPrecip = ForecastAggregator.total(timeSeries, 5, PRECIPITATION_MEAN)
|
||||
public void forecastAggregatorTest() {
|
||||
assertNotNull(timeSeries1);
|
||||
assertNotNull(timeSeries2);
|
||||
BigDecimal maxTempT1F0 = ForecastAggregator.max(timeSeries1, 0, TEMPERATURE).orElseThrow(AssertionError::new);
|
||||
BigDecimal minTempT1F0 = ForecastAggregator.min(timeSeries1, 0, TEMPERATURE).orElseThrow(AssertionError::new);
|
||||
BigDecimal maxWindT1F0 = ForecastAggregator.max(timeSeries1, 0, WIND_SPEED).orElseThrow(AssertionError::new);
|
||||
BigDecimal minWindT1F0 = ForecastAggregator.min(timeSeries1, 0, WIND_SPEED).orElseThrow(AssertionError::new);
|
||||
BigDecimal totalPrecipT1F0 = ForecastAggregator.total(timeSeries1, 0, PRECIPITATION_MEAN)
|
||||
.orElseThrow(AssertionError::new);
|
||||
BigDecimal noonPressureT1F0 = ForecastAggregator.noonOrFirst(timeSeries1, 0, PRESSURE)
|
||||
.orElseThrow(AssertionError::new);
|
||||
|
||||
assertEquals(0, maxTemp.compareTo(BigDecimal.valueOf(7.5)));
|
||||
assertEquals(0, minTemp.compareTo(BigDecimal.valueOf(4.2)));
|
||||
assertEquals(0, maxWind.compareTo(BigDecimal.valueOf(4.4)));
|
||||
assertEquals(0, minWind.compareTo(BigDecimal.valueOf(3.7)));
|
||||
assertEquals(0, totalPrecip.compareTo(BigDecimal.valueOf(2.4)));
|
||||
assertEquals(0, maxTempT1F0.compareTo(BigDecimal.valueOf(20.8)));
|
||||
assertEquals(0, minTempT1F0.compareTo(BigDecimal.valueOf(12.2)));
|
||||
assertEquals(0, maxWindT1F0.compareTo(BigDecimal.valueOf(4)));
|
||||
assertEquals(0, minWindT1F0.compareTo(BigDecimal.valueOf(0.6)));
|
||||
assertEquals(0, totalPrecipT1F0.compareTo(BigDecimal.valueOf(0)));
|
||||
assertEquals(0, noonPressureT1F0.compareTo(BigDecimal.valueOf(1015.6)));
|
||||
|
||||
BigDecimal maxTempT1F9 = ForecastAggregator.max(timeSeries1, 9, TEMPERATURE).orElseThrow(AssertionError::new);
|
||||
BigDecimal minTempT1F9 = ForecastAggregator.min(timeSeries1, 9, TEMPERATURE).orElseThrow(AssertionError::new);
|
||||
BigDecimal maxWindT1F9 = ForecastAggregator.max(timeSeries1, 9, WIND_SPEED).orElseThrow(AssertionError::new);
|
||||
BigDecimal minWindT1F9 = ForecastAggregator.min(timeSeries1, 9, WIND_SPEED).orElseThrow(AssertionError::new);
|
||||
BigDecimal totalPrecipT1F9 = ForecastAggregator.total(timeSeries1, 9, PRECIPITATION_MEAN)
|
||||
.orElseThrow(AssertionError::new);
|
||||
BigDecimal noonPressureT1F9 = ForecastAggregator.noonOrFirst(timeSeries1, 9, PRESSURE)
|
||||
.orElseThrow(AssertionError::new);
|
||||
|
||||
assertEquals(0, maxTempT1F9.compareTo(BigDecimal.valueOf(21.5)));
|
||||
assertEquals(0, minTempT1F9.compareTo(BigDecimal.valueOf(14.6)));
|
||||
assertEquals(0, maxWindT1F9.compareTo(BigDecimal.valueOf(1.6)));
|
||||
assertEquals(0, minWindT1F9.compareTo(BigDecimal.valueOf(1.4)));
|
||||
assertEquals(0, totalPrecipT1F9.compareTo(BigDecimal.valueOf(3.6)));
|
||||
assertEquals(0, noonPressureT1F9.compareTo(BigDecimal.valueOf(1016.2)));
|
||||
|
||||
BigDecimal maxTempT2F0 = ForecastAggregator.max(timeSeries2, 0, TEMPERATURE).orElseThrow(AssertionError::new);
|
||||
BigDecimal minTempT2F0 = ForecastAggregator.min(timeSeries2, 0, TEMPERATURE).orElseThrow(AssertionError::new);
|
||||
BigDecimal maxWindT2F0 = ForecastAggregator.max(timeSeries2, 0, WIND_SPEED).orElseThrow(AssertionError::new);
|
||||
BigDecimal minWindT2F0 = ForecastAggregator.min(timeSeries2, 0, WIND_SPEED).orElseThrow(AssertionError::new);
|
||||
BigDecimal totalPrecipT2F0 = ForecastAggregator.total(timeSeries2, 0, PRECIPITATION_MEAN)
|
||||
.orElseThrow(AssertionError::new);
|
||||
BigDecimal noonPressureT2F0 = ForecastAggregator.noonOrFirst(timeSeries2, 0, PRESSURE)
|
||||
.orElseThrow(AssertionError::new);
|
||||
|
||||
assertEquals(0, maxTempT2F0.compareTo(BigDecimal.valueOf(22.5)));
|
||||
assertEquals(0, minTempT2F0.compareTo(BigDecimal.valueOf(9.7)));
|
||||
assertEquals(0, maxWindT2F0.compareTo(BigDecimal.valueOf(5.7)));
|
||||
assertEquals(0, minWindT2F0.compareTo(BigDecimal.valueOf(2)));
|
||||
assertEquals(0, totalPrecipT2F0.compareTo(BigDecimal.valueOf(0.3)));
|
||||
assertEquals(0, noonPressureT2F0.compareTo(BigDecimal.valueOf(1013.7)));
|
||||
|
||||
BigDecimal maxTempT2F9 = ForecastAggregator.max(timeSeries2, 9, TEMPERATURE).orElseThrow(AssertionError::new);
|
||||
BigDecimal minTempT2F9 = ForecastAggregator.min(timeSeries2, 9, TEMPERATURE).orElseThrow(AssertionError::new);
|
||||
BigDecimal maxWindT2F9 = ForecastAggregator.max(timeSeries2, 9, WIND_SPEED).orElseThrow(AssertionError::new);
|
||||
BigDecimal minWindT2F9 = ForecastAggregator.min(timeSeries2, 9, WIND_SPEED).orElseThrow(AssertionError::new);
|
||||
BigDecimal totalPrecipT2F9 = ForecastAggregator.total(timeSeries2, 9, PRECIPITATION_MEAN)
|
||||
.orElseThrow(AssertionError::new);
|
||||
BigDecimal noonPressureT2F9 = ForecastAggregator.noonOrFirst(timeSeries2, 9, PRESSURE)
|
||||
.orElseThrow(AssertionError::new);
|
||||
|
||||
assertEquals(0, maxTempT2F9.compareTo(BigDecimal.valueOf(22.4)));
|
||||
assertEquals(0, minTempT2F9.compareTo(BigDecimal.valueOf(15.2)));
|
||||
assertEquals(0, maxWindT2F9.compareTo(BigDecimal.valueOf(1.3)));
|
||||
assertEquals(0, minWindT2F9.compareTo(BigDecimal.valueOf(0.7)));
|
||||
assertEquals(0, totalPrecipT2F9.compareTo(BigDecimal.valueOf(2.4)));
|
||||
assertEquals(0, noonPressureT2F9.compareTo(BigDecimal.valueOf(1014.6)));
|
||||
|
||||
BigDecimal maxTempT3F0 = ForecastAggregator.max(timeSeries3, 0, TEMPERATURE).orElseThrow(AssertionError::new);
|
||||
BigDecimal minTempT3F0 = ForecastAggregator.min(timeSeries3, 0, TEMPERATURE).orElseThrow(AssertionError::new);
|
||||
BigDecimal maxWindT3F0 = ForecastAggregator.max(timeSeries3, 0, WIND_SPEED).orElseThrow(AssertionError::new);
|
||||
BigDecimal minWindT3F0 = ForecastAggregator.min(timeSeries3, 0, WIND_SPEED).orElseThrow(AssertionError::new);
|
||||
BigDecimal totalPrecipT3F0 = ForecastAggregator.total(timeSeries3, 0, PRECIPITATION_MEAN)
|
||||
.orElseThrow(AssertionError::new);
|
||||
BigDecimal noonPressureT3F0 = ForecastAggregator.noonOrFirst(timeSeries3, 0, PRESSURE)
|
||||
.orElseThrow(AssertionError::new);
|
||||
|
||||
assertEquals(0, maxTempT3F0.compareTo(BigDecimal.valueOf(18.6)));
|
||||
assertEquals(0, minTempT3F0.compareTo(BigDecimal.valueOf(14.1)));
|
||||
assertEquals(0, maxWindT3F0.compareTo(BigDecimal.valueOf(6)));
|
||||
assertEquals(0, minWindT3F0.compareTo(BigDecimal.valueOf(4.9)));
|
||||
assertEquals(0, totalPrecipT3F0.compareTo(BigDecimal.valueOf(0.5)));
|
||||
assertEquals(0, noonPressureT3F0.compareTo(BigDecimal.valueOf(1012.6)));
|
||||
|
||||
BigDecimal maxTempT3F9 = ForecastAggregator.max(timeSeries3, 9, TEMPERATURE).orElseThrow(AssertionError::new);
|
||||
BigDecimal minTempT3F9 = ForecastAggregator.min(timeSeries3, 9, TEMPERATURE).orElseThrow(AssertionError::new);
|
||||
BigDecimal maxWindT3F9 = ForecastAggregator.max(timeSeries3, 9, WIND_SPEED).orElseThrow(AssertionError::new);
|
||||
BigDecimal minWindT3F9 = ForecastAggregator.min(timeSeries3, 9, WIND_SPEED).orElseThrow(AssertionError::new);
|
||||
BigDecimal totalPrecipT3F9 = ForecastAggregator.total(timeSeries3, 9, PRECIPITATION_MEAN)
|
||||
.orElseThrow(AssertionError::new);
|
||||
BigDecimal noonPressureT3F9 = ForecastAggregator.noonOrFirst(timeSeries3, 9, PRESSURE)
|
||||
.orElseThrow(AssertionError::new);
|
||||
|
||||
assertEquals(0, maxTempT3F9.compareTo(BigDecimal.valueOf(22.6)));
|
||||
assertEquals(0, minTempT3F9.compareTo(BigDecimal.valueOf(15.5)));
|
||||
assertEquals(0, maxWindT3F9.compareTo(BigDecimal.valueOf(1)));
|
||||
assertEquals(0, minWindT3F9.compareTo(BigDecimal.valueOf(0.9)));
|
||||
assertEquals(0, totalPrecipT3F9.compareTo(BigDecimal.valueOf(3.6)));
|
||||
assertEquals(0, noonPressureT3F9.compareTo(BigDecimal.valueOf(1016.6)));
|
||||
}
|
||||
}
|
||||
|
||||
-1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user