mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[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:
parent
c21c468cac
commit
c9933454db
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user