| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- package com.usky.vpp.util;
- import com.usky.vpp.service.VppTsdbQueryService;
- import java.math.BigDecimal;
- import java.math.RoundingMode;
- import java.time.LocalDate;
- import java.time.LocalDateTime;
- import java.time.LocalTime;
- import java.time.format.DateTimeFormatter;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.LinkedHashSet;
- import java.util.List;
- import java.util.Map;
- import java.util.TreeMap;
- /**
- * IntervalDataReport 明日预测曲线(15 分钟整点,按量测点类型均值/累加)。
- */
- public final class VppUnIntervalDataHelper {
- public static final int SLOT_MINUTES = VppUnMomentDataHelper.WINDOW_MINUTES;
- private static final DateTimeFormatter TIME_KEY_FMT = DateTimeFormatter.ofPattern("HH:mm");
- private VppUnIntervalDataHelper() {
- }
- public static LocalDate resolveForecastDate() {
- return LocalDate.now().plusDays(1);
- }
- public static List<LocalDateTime> buildDayQuarterHourSlots(LocalDate forecastDate) {
- List<LocalDateTime> slots = new ArrayList<>();
- if (forecastDate == null) {
- return slots;
- }
- LocalDateTime cursor = forecastDate.atStartOfDay();
- LocalDateTime dayEnd = forecastDate.plusDays(1).atStartOfDay();
- while (cursor.isBefore(dayEnd)) {
- slots.add(cursor);
- cursor = cursor.plusMinutes(SLOT_MINUTES);
- }
- return slots;
- }
- /**
- * 基于典型历史日预测 forecastDate 全天 96 个 15 分钟点。
- */
- public static List<Map<String, Object>> buildForecastCurveValues(VppTsdbQueryService tsdbQueryService,
- List<String> deviceUuids,
- List<LocalDate> referenceDates,
- LocalDate forecastDate,
- VppUnRegisterMetricDefinitions.RegisterMetric registerMetric) {
- List<LocalDateTime> slots = buildDayQuarterHourSlots(forecastDate);
- if (slots.isEmpty()) {
- return Collections.emptyList();
- }
- if (tsdbQueryService == null || deviceUuids == null || deviceUuids.isEmpty()
- || referenceDates == null || referenceDates.isEmpty() || registerMetric == null) {
- return buildZeroCurve(slots);
- }
- List<String> tsdbMetrics = VppUnMomentDataHelper.resolveTsdbMetrics(registerMetric);
- if (tsdbMetrics.isEmpty()) {
- return buildZeroCurve(slots);
- }
- List<String> distinctUuids = new ArrayList<>(new LinkedHashSet<>(deviceUuids));
- if (VppUnMomentDataHelper.resolveAggregationMode(registerMetric)
- == VppUnMomentDataHelper.AggregationMode.AVERAGE) {
- return buildAverageForecastCurve(tsdbQueryService, distinctUuids, referenceDates, slots, tsdbMetrics);
- }
- return buildAccumulativeForecastCurve(tsdbQueryService, distinctUuids, referenceDates, slots, tsdbMetrics);
- }
- private static List<Map<String, Object>> buildAverageForecastCurve(
- VppTsdbQueryService tsdbQueryService,
- List<String> deviceUuids,
- List<LocalDate> referenceDates,
- List<LocalDateTime> slots,
- List<String> tsdbMetrics) {
- Map<String, BigDecimal> avgByTime = tsdbQueryService.queryBaselineAvgByTimePoint(
- deviceUuids,
- referenceDates,
- LocalTime.MIN,
- LocalTime.of(23, 59, 59),
- tsdbMetrics,
- SLOT_MINUTES,
- null);
- List<Map<String, Object>> values = new ArrayList<>(slots.size());
- for (LocalDateTime slot : slots) {
- String timeKey = slot.format(TIME_KEY_FMT);
- BigDecimal value = avgByTime != null ? avgByTime.get(timeKey) : null;
- values.add(VppUnMessageBuilder.buildIntervalCurveValue(scale(value), slot, "good"));
- }
- return values;
- }
- private static List<Map<String, Object>> buildAccumulativeForecastCurve(
- VppTsdbQueryService tsdbQueryService,
- List<String> deviceUuids,
- List<LocalDate> referenceDates,
- List<LocalDateTime> slots,
- List<String> tsdbMetrics) {
- Map<String, List<BigDecimal>> samplesByTimeKey = new TreeMap<>();
- for (LocalDate referenceDate : referenceDates) {
- LocalDateTime dayStart = referenceDate.atStartOfDay();
- LocalDateTime dayEnd = referenceDate.plusDays(1).atStartOfDay();
- Map<String, Map<String, TreeMap<LocalDateTime, BigDecimal>>> history =
- tsdbQueryService.queryDeviceMetricHistory(deviceUuids, dayStart, dayEnd, tsdbMetrics);
- if (history == null || history.isEmpty()) {
- continue;
- }
- for (LocalDateTime slot : slots) {
- LocalDateTime slotStart = LocalDateTime.of(referenceDate, slot.toLocalTime());
- LocalDateTime slotEnd = slotStart.plusMinutes(SLOT_MINUTES);
- LocalDateTime endExclusive = slotEnd.plusSeconds(1);
- BigDecimal slotTotal = BigDecimal.ZERO;
- for (String deviceUuid : deviceUuids) {
- Map<String, TreeMap<LocalDateTime, BigDecimal>> metricMap = history.get(deviceUuid);
- if (metricMap == null || metricMap.isEmpty()) {
- continue;
- }
- TreeMap<LocalDateTime, BigDecimal> series = pickSeries(metricMap, tsdbMetrics);
- BigDecimal usage = VppEnergyUsageHelper.calcUsage(series, slotStart, endExclusive);
- if (usage != null) {
- slotTotal = slotTotal.add(usage);
- }
- }
- samplesByTimeKey.computeIfAbsent(slot.format(TIME_KEY_FMT), key -> new ArrayList<>())
- .add(slotTotal);
- }
- }
- List<Map<String, Object>> values = new ArrayList<>(slots.size());
- for (LocalDateTime slot : slots) {
- List<BigDecimal> samples = samplesByTimeKey.get(slot.format(TIME_KEY_FMT));
- values.add(VppUnMessageBuilder.buildIntervalCurveValue(
- scale(average(samples)), slot, "good"));
- }
- return values;
- }
- private static List<Map<String, Object>> buildZeroCurve(List<LocalDateTime> slots) {
- List<Map<String, Object>> values = new ArrayList<>(slots.size());
- for (LocalDateTime slot : slots) {
- values.add(VppUnMessageBuilder.buildIntervalCurveValue(BigDecimal.ZERO, slot, "good"));
- }
- return values;
- }
- private static TreeMap<LocalDateTime, BigDecimal> pickSeries(Map<String, TreeMap<LocalDateTime, BigDecimal>> metricMap,
- List<String> preferredMetrics) {
- if (metricMap == null || metricMap.isEmpty()) {
- return null;
- }
- if (preferredMetrics != null) {
- for (String metric : preferredMetrics) {
- TreeMap<LocalDateTime, BigDecimal> series = metricMap.get(metric);
- if (series != null && !series.isEmpty()) {
- return series;
- }
- }
- }
- for (TreeMap<LocalDateTime, BigDecimal> series : metricMap.values()) {
- if (series != null && !series.isEmpty()) {
- return series;
- }
- }
- return null;
- }
- private static BigDecimal average(List<BigDecimal> values) {
- if (values == null || values.isEmpty()) {
- return BigDecimal.ZERO;
- }
- BigDecimal sum = BigDecimal.ZERO;
- int count = 0;
- for (BigDecimal value : values) {
- if (value != null) {
- sum = sum.add(value);
- count++;
- }
- }
- if (count == 0) {
- return BigDecimal.ZERO;
- }
- return sum.divide(BigDecimal.valueOf(count), 6, RoundingMode.HALF_UP);
- }
- private static BigDecimal scale(BigDecimal value) {
- if (value == null) {
- return BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
- }
- return value.setScale(2, RoundingMode.HALF_UP);
- }
- }
|