|
@@ -0,0 +1,562 @@
|
|
|
+package com.jiayue.ipfcst.console.service;
|
|
|
+
|
|
|
+import cn.hutool.core.date.DateTime;
|
|
|
+import cn.hutool.core.date.DateUtil;
|
|
|
+import com.jiayue.ipfcst.common.core.exception.BusinessException;
|
|
|
+import com.jiayue.ipfcst.common.core.util.CommonUtil;
|
|
|
+import com.jiayue.ipfcst.common.core.util.DateMomentUtil;
|
|
|
+import com.jiayue.ipfcst.common.core.util.DateTimeUtil;
|
|
|
+import com.jiayue.ipfcst.common.data.constant.enums.ElectricFieldTypeEnum;
|
|
|
+import com.jiayue.ipfcst.common.data.constant.enums.PredictionModelEnum;
|
|
|
+import com.jiayue.ipfcst.common.data.entity.*;
|
|
|
+import com.jiayue.ipfcst.common.data.repository.*;
|
|
|
+import com.jiayue.ipfcst.common.data.service.BaseService;
|
|
|
+import com.sun.istack.internal.NotNull;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.commons.lang.time.DateFormatUtils;
|
|
|
+import org.apache.commons.lang.time.DateUtils;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Propagation;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 超短期功率预测业务
|
|
|
+ *
|
|
|
+ * @author xsl
|
|
|
+ * @version 3.0
|
|
|
+ * @since 2020/4/22 18:24
|
|
|
+ */
|
|
|
+@Service
|
|
|
+@Slf4j
|
|
|
+public class ForecastPowerUltraShortTermOneService extends BaseService {
|
|
|
+ @Autowired
|
|
|
+ ElectricFieldService electricFieldService;
|
|
|
+ @Autowired
|
|
|
+ ForecastPowerShortTermOneRepository forecastPowerShortTermOneRepository;
|
|
|
+ @Autowired
|
|
|
+ SysParameterService sysParameterService;
|
|
|
+ @Autowired
|
|
|
+ PowerStationStatusDataRepository powerStationStatusDataRepository;
|
|
|
+ @Autowired
|
|
|
+ ForecastPowerUltraShortTermOneRepository forecastPowerUltraShortTermOneRepository;
|
|
|
+ @Autowired
|
|
|
+ ForecastPowerUltraShortTermOneHisRepository forecastPowerUltraShortTermOneHisRepository;
|
|
|
+ @Autowired
|
|
|
+ ManualInterventionService manualInterventionService;
|
|
|
+ @Autowired
|
|
|
+ ForecastPowerShortTermOneService forecastPowerShortTermOneService;
|
|
|
+ @Autowired
|
|
|
+ ManualInterventionRatioService manualInterventionRatioService;
|
|
|
+
|
|
|
+// @Autowired
|
|
|
+// UltraShortTermCoefficientRepository ultraShortTermCoefficientRepository;
|
|
|
+// @Autowired
|
|
|
+// RepairPlanRepository repairPlanRepository;
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成超短期预测功率,自动更新覆盖预测功率
|
|
|
+ *
|
|
|
+ * @param startTime 开始时间
|
|
|
+ * @param endTime 结束时间
|
|
|
+ */
|
|
|
+ @Transactional(propagation = Propagation.REQUIRED)
|
|
|
+ public void buildForecastPowerUltraShortTerm(@NotNull final Long startTime, @NotNull final Long endTime) {
|
|
|
+ this.getForecastPowerUltraShortTerm(startTime, endTime);
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 获取超短期预测功率,当数据库中超短期预测记录不足查询所需时,进行本地化计算,用于上报专用
|
|
|
+ *
|
|
|
+ * @param startTime 开始时间
|
|
|
+ * @param endTime 结束时间
|
|
|
+ * @return 预测功率结果集
|
|
|
+ */
|
|
|
+ @SuppressWarnings("WeakerAccess")
|
|
|
+ @Transactional(propagation = Propagation.REQUIRED)
|
|
|
+ public List<ForecastPowerUltraShortTermOneHis> getForecastPowerUltraShortTerm(@NotNull final Long startTime, @NotNull final Long endTime) {
|
|
|
+ log.info("开始获取超短期实时预测功率" + DateFormatUtils.format(startTime, "yyyy-MM-dd HH:mm:ss") + " 至 " + DateFormatUtils.format(endTime, "yyyy-MM-dd HH:mm:ss"));
|
|
|
+
|
|
|
+ Long monentTime = 0L;
|
|
|
+ try {
|
|
|
+ monentTime = DateMomentUtil.getMomentTime(new Date().getTime(), 1, 15 * 60 * 1000L);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("获取当前时刻错误",e);
|
|
|
+ }
|
|
|
+ //为了保证回传和超短期数据一直,当数据库中有预测数据时,直接返回数据
|
|
|
+ List<ForecastPowerUltraShortTermOneHis> byForecastTimeBetweenAndGenDate = this.forecastPowerUltraShortTermOneHisRepository.findByForecastTimeBetweenAndGenDate(startTime, endTime, new Date(monentTime));
|
|
|
+
|
|
|
+
|
|
|
+ int moment = DateMomentUtil.getIntervalMoment(startTime, endTime,15*60*1000l);
|
|
|
+
|
|
|
+
|
|
|
+ if (byForecastTimeBetweenAndGenDate.size() >= moment) {
|
|
|
+ return byForecastTimeBetweenAndGenDate;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // 查询场站信息
|
|
|
+ ElectricField electricFieldInfo = electricFieldService.get();
|
|
|
+ // 查询预测时间点对应的开机容量
|
|
|
+ Map<Long, BigDecimal> openCapacityMap = null;
|
|
|
+ try {
|
|
|
+ openCapacityMap = super.queryOpenCapacity(startTime, endTime, electricFieldInfo.getCapacity());
|
|
|
+ } catch (BusinessException e) {
|
|
|
+ log.error("预测数据生成获取开机容量出错:" + CommonUtil.printStackTraceToString(e));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ List<ForecastPowerUltraShortTermOne> forecastPowerUltraShortTermList = new ArrayList<>();
|
|
|
+ List<ForecastPowerUltraShortTermOne> tempList = this.forecastPowerUltraShortTermOneRepository.findByForecastTimeBetween(startTime, endTime);
|
|
|
+ for (ForecastPowerUltraShortTermOne f:tempList){
|
|
|
+ if (Integer.parseInt(DateFormatUtils.format(f.getForecastTime(),"mm"))%15==0){
|
|
|
+ forecastPowerUltraShortTermList.add(f);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Long momentTime = 15 * 60 * 1000L; // 15分钟一个时刻
|
|
|
+ Integer moments = Math.toIntExact((endTime - startTime) / momentTime + 1);
|
|
|
+ log.info("获取所需记录数:" + moments);
|
|
|
+
|
|
|
+ if (moments > forecastPowerUltraShortTermList.size()) {
|
|
|
+ Map<Long, List<ForecastPowerUltraShortTermOne>> forecastPowerShortTermsMap = forecastPowerUltraShortTermList.stream().collect(Collectors.groupingBy(ForecastPowerUltraShortTermOne::getForecastTime));
|
|
|
+ for (Long tempTime = startTime; tempTime <= endTime; tempTime = tempTime + momentTime) {
|
|
|
+ if (forecastPowerShortTermsMap.get(tempTime) == null) {
|
|
|
+ log.info("文件超短期缺点:"+tempTime+" forecastPowerShortTermsMap里个数:"+forecastPowerShortTermsMap.size());
|
|
|
+ BigDecimal tempValue;
|
|
|
+ if (ElectricFieldTypeEnum.E1.equals(electricFieldInfo.getElectricFieldTypeEnum())) {
|
|
|
+ if (DateTimeUtil.checkInSunriseAndSunset(startTime, electricFieldInfo.getLongitude().doubleValue(), electricFieldInfo.getLatitude().doubleValue())) {
|
|
|
+ tempValue = new BigDecimal(CommonUtil.getRandom(1, 70) / 100.0d);
|
|
|
+ } else {
|
|
|
+ // 日升日落
|
|
|
+ tempValue = BigDecimal.ZERO;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ tempValue = new BigDecimal(CommonUtil.getRandom(1, 70) / 100.0d);
|
|
|
+ }
|
|
|
+ tempValue = tempValue.multiply(electricFieldInfo.getCapacity()).setScale(2, BigDecimal.ROUND_HALF_UP);
|
|
|
+ ForecastPowerUltraShortTermOne forecastPowerUltraShortTerm = new ForecastPowerUltraShortTermOne();
|
|
|
+ forecastPowerUltraShortTerm.setGenDate(new Date(monentTime));
|
|
|
+ forecastPowerUltraShortTerm.setForecastTime(tempTime);
|
|
|
+ forecastPowerUltraShortTerm.setFpValue(tempValue);
|
|
|
+ forecastPowerUltraShortTerm.setPredictionModelEnum(PredictionModelEnum.E4);
|
|
|
+ forecastPowerUltraShortTerm.setCoefficientValue(new BigDecimal(-0.99).setScale(2,BigDecimal.ROUND_HALF_UP));
|
|
|
+ forecastPowerUltraShortTerm.setDifferenceValue(new BigDecimal(-0.99).setScale(2,BigDecimal.ROUND_HALF_UP));
|
|
|
+ // 保存超短期实时预测记录
|
|
|
+ this.forecastPowerUltraShortTermOneRepository.save(forecastPowerUltraShortTerm);
|
|
|
+ forecastPowerUltraShortTermList.add(forecastPowerUltraShortTerm);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ log.info("生成超短期实时预测功率记录数:" + forecastPowerUltraShortTermList.size());
|
|
|
+ // 按预测时刻升序
|
|
|
+ forecastPowerUltraShortTermList.sort(Comparator.comparing(ForecastPowerUltraShortTermOne::getForecastTime));
|
|
|
+
|
|
|
+// int qn_yth = sysParameterService.getTranSysParameter("qn_yth", "0");
|
|
|
+//
|
|
|
+// if(qn_yth != 0){
|
|
|
+// //一体化消减
|
|
|
+// List<RepairPlan> list = repairPlanRepository.findAll();
|
|
|
+// if(list.size()>0){
|
|
|
+// log.info("===========执行一体化对超短期上报数据调整(消减容量)");
|
|
|
+// for (int i = 0; i < forecastPowerUltraShortTermList.size(); i++) {
|
|
|
+// ForecastPowerUltraShortTerm forecastPowerUltraShortTerm = forecastPowerUltraShortTermList.get(i);
|
|
|
+// List<RepairPlan> collect = list.stream().filter(r -> r.getStartTime().getTime() <= forecastPowerUltraShortTerm.getForecastTime() && forecastPowerUltraShortTerm.getForecastTime() < r.getEndTime().getTime()).collect(Collectors.toList());
|
|
|
+// if(collect.size()>0){
|
|
|
+//
|
|
|
+// BigDecimal capacityCurtailment = collect.get(0).getCapacityCurtailment();
|
|
|
+// BigDecimal fpValue = forecastPowerUltraShortTermList.get(i).getFpValue();
|
|
|
+//
|
|
|
+// //消减后的容量
|
|
|
+// BigDecimal subtract = fpValue.subtract(capacityCurtailment);
|
|
|
+// if(subtract.compareTo(new BigDecimal(0)) <= 0){
|
|
|
+// subtract = new BigDecimal(0);
|
|
|
+// }
|
|
|
+// forecastPowerUltraShortTermList.get(i).setFpValue(subtract);
|
|
|
+// log.info("一体化对超短期上报数据调整=》时间:{};消减容量为:{};调整前:{};调整后:{}", DateFormatUtils.format(forecastPowerUltraShortTermList.get(i).getForecastTime(),"yyyy-MM-dd HH:mm"),capacityCurtailment, fpValue, subtract);
|
|
|
+// }
|
|
|
+//
|
|
|
+// }
|
|
|
+// log.info("===========结束一体化对超短期上报数据调整(消减容量)");
|
|
|
+// }
|
|
|
+//
|
|
|
+//
|
|
|
+//
|
|
|
+// List<UltraShortTermCoefficient> ultraShortTermCoefficientList = ultraShortTermCoefficientRepository.findByParseTimeBetween(new Date(startTime-2*15*60*1000l), new Date(startTime-15*60*1000l));
|
|
|
+//
|
|
|
+// if(ultraShortTermCoefficientList.size()>0){
|
|
|
+// log.info("===========执行一体化对超短期上报数据调整(系数)");
|
|
|
+// for (int i = 0; i < forecastPowerUltraShortTermList.size(); i++) {
|
|
|
+// ForecastPowerUltraShortTerm forecastPowerUltraShortTerm = forecastPowerUltraShortTermList.get(i);
|
|
|
+// List<UltraShortTermCoefficient> collect = ultraShortTermCoefficientList.stream().filter(u -> u.getTime().getTime() == forecastPowerUltraShortTerm.getForecastTime()).collect(Collectors.toList());
|
|
|
+//
|
|
|
+// if(collect.size()>0){
|
|
|
+// BigDecimal coefficient = collect.get(0).getCoefficient();
|
|
|
+// BigDecimal fpValue = forecastPowerUltraShortTermList.get(i).getFpValue();
|
|
|
+// BigDecimal coefficientAfter = fpValue.multiply(coefficient).setScale(2,BigDecimal.ROUND_DOWN);
|
|
|
+//
|
|
|
+// forecastPowerUltraShortTermList.get(i).setFpValue(coefficientAfter);
|
|
|
+// log.info("一体化对超短期上报数据调整=》时间:{};系数为:{};调整前:{};调整后:{}", DateFormatUtils.format(forecastPowerUltraShortTermList.get(i).getForecastTime(),"yyyy-MM-dd HH:mm"),coefficient, fpValue, coefficientAfter);
|
|
|
+// }
|
|
|
+// }
|
|
|
+// log.info("===========结束一体化对超短期上报数据调整(系数)");
|
|
|
+// }
|
|
|
+// }
|
|
|
+//
|
|
|
+//
|
|
|
+
|
|
|
+
|
|
|
+ // 处理超短期历史记录
|
|
|
+ List<ForecastPowerUltraShortTermOneHis> forecastPowerUltraShortTermHiss = new ArrayList<>();
|
|
|
+
|
|
|
+ ForecastPowerUltraShortTermOneHis forecastPowerUltraShortTermHis;
|
|
|
+ int n = 1;
|
|
|
+ // 生成超短期历史数据
|
|
|
+ BigDecimal openCapacity;
|
|
|
+ //生成数据
|
|
|
+ for (ForecastPowerUltraShortTermOne forecastPowerUltraShortTerm : forecastPowerUltraShortTermList) {
|
|
|
+ forecastPowerUltraShortTermHis = new ForecastPowerUltraShortTermOneHis();
|
|
|
+ openCapacity = openCapacityMap.get(forecastPowerUltraShortTerm.getForecastTime());
|
|
|
+ forecastPowerUltraShortTermHis.setForecastTime(forecastPowerUltraShortTerm.getForecastTime());
|
|
|
+ forecastPowerUltraShortTermHis.setSuCapacity(openCapacity);
|
|
|
+ forecastPowerUltraShortTermHis.setCapacity(electricFieldInfo.getCapacity());
|
|
|
+ forecastPowerUltraShortTermHis.setForecastHowLongAgo(n++);
|
|
|
+ forecastPowerUltraShortTermHis.setTheoryValue(forecastPowerUltraShortTerm.getFpValue());
|
|
|
+ // 预测可用功率=预测*(开机容量/装机容量)
|
|
|
+ BigDecimal fpValue = forecastPowerUltraShortTerm.getFpValue().multiply(openCapacity)
|
|
|
+ .divide(electricFieldInfo.getCapacity(), 2, BigDecimal.ROUND_HALF_UP);
|
|
|
+ forecastPowerUltraShortTermHis.setAbleValue(fpValue);
|
|
|
+ forecastPowerUltraShortTermHis.setPredictionModelEnum(forecastPowerUltraShortTerm.getPredictionModelEnum());
|
|
|
+ forecastPowerUltraShortTermHis.setDifferenceValue(forecastPowerUltraShortTerm.getDifferenceValue());
|
|
|
+ forecastPowerUltraShortTermHis.setCoefficientValue(forecastPowerUltraShortTerm.getCoefficientValue());
|
|
|
+ forecastPowerUltraShortTermHis.setGenDate(new Date(monentTime));
|
|
|
+ forecastPowerUltraShortTermHiss.add(forecastPowerUltraShortTermHis);
|
|
|
+ }
|
|
|
+// List<ForecastPowerUltraShortTermHis> forecastPowerUltraShortTermHiss = forecastPowerUltraShortTermHiss1.stream().filter(t -> t.getForecastHowLongAgo() <=16).collect(Collectors.toList());
|
|
|
+ // 获取实际功率替换超短期点位参数
|
|
|
+ Integer replacePoint = 0;
|
|
|
+ String realpower_replace_cdq = sysParameterService.getSysParameter("realpower_replace_cdq", "0");
|
|
|
+ replacePoint = Integer.valueOf(realpower_replace_cdq);
|
|
|
+ if (replacePoint <= forecastPowerUltraShortTermHiss.size() && replacePoint > 0) {
|
|
|
+ Long pre5Time = 0l;
|
|
|
+ Date systemDate = new Date();
|
|
|
+ try {
|
|
|
+ // 获取前5分钟时刻
|
|
|
+ pre5Time = DateMomentUtil.getMomentTime(systemDate.getTime() - 5 * 60 * 1000, 1, 5 * 60 * 1000L);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("超短期数据用实际功率替换生成时刻步长错误", e);
|
|
|
+ pre5Time = DateMomentUtil.getDayStartTime(systemDate.getTime());
|
|
|
+ }
|
|
|
+ List<PowerStationStatusData> realPowerList = powerStationStatusDataRepository.findByTimeBetween(new Date(pre5Time), new Date(pre5Time + 5 * 60 * 1000));
|
|
|
+ if (realPowerList.size() > 0) {
|
|
|
+ // 按时间降序排列
|
|
|
+ realPowerList.sort(Comparator.comparing(PowerStationStatusData::getTime).reversed());
|
|
|
+ // 获取最后一条最新的实际功率
|
|
|
+ PowerStationStatusData realPower = realPowerList.get(0);
|
|
|
+ // 将实际功率替换到对应的超短期点位上
|
|
|
+ ForecastPowerUltraShortTermOneHis d = forecastPowerUltraShortTermHiss.get(replacePoint - 1);
|
|
|
+ if (realPower.getRealValue().compareTo(new BigDecimal(0)) != -1) {
|
|
|
+ d.setAbleValue(realPower.getRealValue());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //-----------------------------------------------------开始进行人工干预数值的判断----------------------------------------------------
|
|
|
+ //-----------------------------------------------------点位判断开始----------------------------------------------------
|
|
|
+ List<ManualInterventionData> manualInterventionDataList = manualInterventionService.queryManualIntervention(startTime, endTime, "1");
|
|
|
+ manualInterventionDataList.sort(Comparator.comparing(ManualInterventionData::getInterveneTime));
|
|
|
+ Map<Long, BigDecimal> mMap = new HashMap<>();
|
|
|
+ int flag = 0;
|
|
|
+ if (manualInterventionDataList.size() > 0) {
|
|
|
+ for (ManualInterventionData manualInterventionData : manualInterventionDataList) {
|
|
|
+ mMap.put(manualInterventionData.getInterveneTime(), manualInterventionData.getInterveneData());
|
|
|
+ }
|
|
|
+ for (ForecastPowerUltraShortTermOneHis forecastPowerUltraShortTermHis1 : forecastPowerUltraShortTermHiss) {
|
|
|
+ BigDecimal ma = mMap.get(forecastPowerUltraShortTermHis1.getForecastTime());
|
|
|
+ if (ma != null) {
|
|
|
+ forecastPowerUltraShortTermHis1.setAbleValue(ma.setScale(2, BigDecimal.ROUND_HALF_UP));
|
|
|
+ forecastPowerUltraShortTermHis1.setTheoryValue(ma.setScale(2, BigDecimal.ROUND_HALF_UP));
|
|
|
+ forecastPowerUltraShortTermHis1.setGenDate(new Date(monentTime));
|
|
|
+ forecastPowerUltraShortTermHis1.setPredictionModelEnum(PredictionModelEnum.E6);
|
|
|
+ forecastPowerUltraShortTermHiss.set(flag, forecastPowerUltraShortTermHis1);
|
|
|
+ }
|
|
|
+ flag++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //-----------------------------------------------------点位判断结束----------------------------------------------------
|
|
|
+ //-----------------------------------------------------系数判断开始----------------------------------------------------
|
|
|
+ //获取今日凌晨00:00
|
|
|
+ long mStartTime = DateUtil.beginOfDay(DateTime.now()).getTime();
|
|
|
+ long mEndTime = mStartTime + 24*60*60*1000l - 1000;
|
|
|
+ List<ManualInterventionRatioData> manualInterventionRatioDataList = manualInterventionRatioService.queryManualInterventionRatio(mStartTime, mEndTime, "1");
|
|
|
+
|
|
|
+ //如果有人工干预系数设置记录
|
|
|
+ if(manualInterventionRatioDataList.size() > 0){
|
|
|
+ //循环所有记录
|
|
|
+ for(ManualInterventionRatioData manualInterventionRatioData :manualInterventionRatioDataList){
|
|
|
+ for (Long tempTime = manualInterventionRatioData.getInterveneStartTime(); tempTime <= manualInterventionRatioData.getInterveneEndTime(); tempTime = tempTime + 15 * 60 * 1000L) {
|
|
|
+ //循环所有超短期的值
|
|
|
+ int mrflag = 0;
|
|
|
+ for (ForecastPowerUltraShortTermOneHis forecastPowerUltraShortTermHis1 : forecastPowerUltraShortTermHiss) {
|
|
|
+ //如果该时间设置了系数则数值*系数
|
|
|
+ if(forecastPowerUltraShortTermHis1.getForecastTime().equals(tempTime)){
|
|
|
+ BigDecimal ableValue = forecastPowerUltraShortTermHis1.getAbleValue().multiply(new BigDecimal(manualInterventionRatioData.getRatio().toString())).setScale(2, BigDecimal.ROUND_HALF_UP);
|
|
|
+ //如果计算后的数据大于装机容量 则ableValue=装机容量
|
|
|
+ if((ableValue).compareTo(new BigDecimal(electricFieldInfo.getCapacity().toString())) > 0){
|
|
|
+ ableValue = new BigDecimal(electricFieldInfo.getCapacity().toString());
|
|
|
+ }
|
|
|
+ forecastPowerUltraShortTermHis1.setAbleValue(ableValue);
|
|
|
+ forecastPowerUltraShortTermHis1.setTheoryValue(ableValue);
|
|
|
+ forecastPowerUltraShortTermHis1.setGenDate(new Date(monentTime));
|
|
|
+ forecastPowerUltraShortTermHis1.setPredictionModelEnum(PredictionModelEnum.E10);
|
|
|
+ forecastPowerUltraShortTermHiss.set(mrflag, forecastPowerUltraShortTermHis1);
|
|
|
+ }
|
|
|
+ mrflag++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //-----------------------------------------------------系数判断结束----------------------------------------------------
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ String lowerPredictionLimit = super.getSysParameter("LowerPredictionLimit", "0");
|
|
|
+ BigDecimal lpl = new BigDecimal(lowerPredictionLimit);
|
|
|
+
|
|
|
+ forecastPowerUltraShortTermHiss.forEach(s->{
|
|
|
+ if(s.getAbleValue().compareTo(lpl)==-1){
|
|
|
+ s.setAbleValue(lpl);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ // 获取当前时刻标记时间
|
|
|
+// Long nowMomentTime;
|
|
|
+// try {
|
|
|
+// nowMomentTime = DateMomentUtil.getMomentTime(System.currentTimeMillis(), 1, 15 * 60 * 1000L);
|
|
|
+// } catch (Exception e) {
|
|
|
+// log.error("时刻步长错误", e);
|
|
|
+// nowMomentTime = DateMomentUtil.getDayStartTime(System.currentTimeMillis());
|
|
|
+// }
|
|
|
+
|
|
|
+ //-----------------------------------------------------浙江光伏负偏差---------------------------------------------------
|
|
|
+
|
|
|
+ try {
|
|
|
+ String negative_deviation = super.getSysParameter("negative_deviation", "0");
|
|
|
+ if (electricFieldInfo.getProvinceEnum().toString().equals("E33")&&electricFieldInfo.getElectricFieldTypeEnum().toString().equals("E1")&&!negative_deviation.equals("0")&&!negative_deviation.equals("")){
|
|
|
+ int mrflag = 0;
|
|
|
+ for (ForecastPowerUltraShortTermOneHis f : forecastPowerUltraShortTermHiss) {
|
|
|
+ f.setAbleValue(f.getAbleValue().subtract(new BigDecimal(negative_deviation)));
|
|
|
+ f.setTheoryValue(f.getTheoryValue().subtract(new BigDecimal(negative_deviation)));
|
|
|
+ f.setGenDate(new Date());
|
|
|
+ f.setPredictionModelEnum(PredictionModelEnum.E10);
|
|
|
+ forecastPowerUltraShortTermHiss.set(mrflag, f);
|
|
|
+ mrflag++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }catch (Exception e){
|
|
|
+ e.printStackTrace();
|
|
|
+ log.info("负偏差计算错误,请检查negative_deviation参数是否为数字");
|
|
|
+ }
|
|
|
+ //-----------------------------------------------------浙江光伏负偏差---------------------------------------------------
|
|
|
+ //-----------------------------------------------------人工干预数据判断结束----------------------------------------------------
|
|
|
+ // 删除当前时刻标记时间生成的超短期历史记录
|
|
|
+ this.forecastPowerUltraShortTermOneHisRepository.deleteNowMoment(startTime, endTime, new Date(monentTime));
|
|
|
+ // 保存超短期历史记录
|
|
|
+ this.forecastPowerUltraShortTermOneHisRepository.saveAll(forecastPowerUltraShortTermHiss);
|
|
|
+ return forecastPowerUltraShortTermHiss;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 执行超短期预测
|
|
|
+ */
|
|
|
+ @Transactional(propagation = Propagation.REQUIRED, rollbackFor = RuntimeException.class)
|
|
|
+ public void executeForecast() {
|
|
|
+ // 根据场站类型执行相应超短期预测
|
|
|
+ try {
|
|
|
+ // 获取查询时间,从当前时间所处时间点标记时间开始查询,截至到96个时间点对应的标记时间
|
|
|
+ String cdqUpMin = super.getSysParameter("CDQ_UP_MIN", "0");
|
|
|
+ Long calTime = DateMomentUtil.getMomentTime(System.currentTimeMillis() + Integer.parseInt(cdqUpMin) * 1000 * 60, 1, 15 * 60 * 1000L);
|
|
|
+ Long startTime = calTime + 15 * 1000 * 60L;
|
|
|
+ String llcdq_point = super.getSysParameter("FILE_LLCDQ_POINT", "16");
|
|
|
+ Integer forecastPoints = Integer.parseInt(llcdq_point);
|
|
|
+ Integer forecastMinutes = forecastPoints * 15;
|
|
|
+ // 结束时间增加15分钟为了防止文件先生成,实时表中最后一个时间点没有点位的问题
|
|
|
+ Long endTime = DateUtils.addMinutes(new Date(startTime), forecastMinutes).getTime();
|
|
|
+
|
|
|
+ // 查询该时间段内的短期预测功率
|
|
|
+ List<ForecastPowerShortTermOne> forecastPowerShortTermList = this.forecastPowerShortTermOneRepository.findByForecastTimeBetween(startTime, endTime);
|
|
|
+
|
|
|
+ Map<Long, List<ForecastPowerShortTermOne>> forecastPowerShortTermsMap =
|
|
|
+ forecastPowerShortTermList.stream().collect(Collectors.groupingBy(ForecastPowerShortTermOne::getForecastTime));
|
|
|
+ // 查询场站信息
|
|
|
+ ElectricField electricField = this.getElectricField();
|
|
|
+ Map<Long, BigDecimal> openCapacityMap = null;
|
|
|
+ try {
|
|
|
+ openCapacityMap = super.queryOpenCapacity(startTime, endTime, electricField.getCapacity());
|
|
|
+ } catch (BusinessException e) {
|
|
|
+ log.error("预测数据生成获取开机容量出错:" + CommonUtil.printStackTraceToString(e));
|
|
|
+ }
|
|
|
+ List<ForecastPowerShortTermOne> addForecastPowerShortTermList = new ArrayList<>();
|
|
|
+ // 判断短期数据是否缺点
|
|
|
+ for (Long tempTime = startTime; tempTime <= endTime; tempTime = tempTime + 15 * 60 * 1000L) {
|
|
|
+ if (forecastPowerShortTermsMap.get(tempTime) == null) {
|
|
|
+ // 缺失时间点
|
|
|
+ ForecastPowerShortTermOne forecastPowerShortTerms = null;
|
|
|
+ if (ElectricFieldTypeEnum.E1.compareTo(electricField.getElectricFieldTypeEnum()) == 0) {
|
|
|
+ forecastPowerShortTerms = forecastPowerShortTermOneService.generateSolarPowerShortTerm(tempTime, openCapacityMap.get(tempTime), electricField);
|
|
|
+ } else {
|
|
|
+ forecastPowerShortTerms = forecastPowerShortTermOneService.generateWindPowerShortTerm(tempTime, openCapacityMap.get(tempTime));
|
|
|
+ }
|
|
|
+ addForecastPowerShortTermList.add(forecastPowerShortTerms);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!addForecastPowerShortTermList.isEmpty()) {
|
|
|
+ // 保存短期预测
|
|
|
+ this.forecastPowerShortTermOneRepository.saveAll(addForecastPowerShortTermList);
|
|
|
+ // 将补齐的预测功率追加到查询预测功率结果集中
|
|
|
+ forecastPowerShortTermList.addAll(addForecastPowerShortTermList);
|
|
|
+ }
|
|
|
+ forecastPowerShortTermList.sort(Comparator.comparing(ForecastPowerShortTermOne::getForecastTime));
|
|
|
+
|
|
|
+ if (ElectricFieldTypeEnum.E1.compareTo(electricField.getElectricFieldTypeEnum()) == 0) {
|
|
|
+ // 光伏电站
|
|
|
+ this.executeForecastForlight(forecastPowerShortTermList, electricField.getCapacity());
|
|
|
+ } else if (ElectricFieldTypeEnum.E2.compareTo(electricField.getElectricFieldTypeEnum()) == 0) {
|
|
|
+ // 风力电场
|
|
|
+ this.executeForecastForWind(forecastPowerShortTermList, electricField.getCapacity());
|
|
|
+ } else {
|
|
|
+ log.error("场站类型非法!");
|
|
|
+ }
|
|
|
+ } catch (BusinessException e) {
|
|
|
+ log.error("获取场站信息出错!", e);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("系统运行错误!", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 执行风电场超短期预测
|
|
|
+ *
|
|
|
+ * @param forecastPowerShortTermList 短期预测结果集
|
|
|
+ * @param capacity 装机容量
|
|
|
+ */
|
|
|
+ private List<ForecastPowerUltraShortTermOne> executeForecastForWind(final List<ForecastPowerShortTermOne> forecastPowerShortTermList, final BigDecimal capacity) {
|
|
|
+ List<ForecastPowerUltraShortTermOne> forecastPowerUltraShortTermList = new ArrayList<>();
|
|
|
+ ForecastPowerUltraShortTermOne forecastPowerUltraShortTerm;
|
|
|
+ //获取系统参数cdqjsfs,超短期计算方式,0为默认乘系数的方式,1为根据可用功率计算的方式
|
|
|
+ String cdqjsfs = electricFieldService.getSysParameter("cdqjsfs", "1");
|
|
|
+ log.info("参数cdqjsfs值为:" + cdqjsfs + ",超短期计算方式,0为默认乘系数的方式,1为根据可用功率计算的方式。");
|
|
|
+ BigDecimal stPower, ustPower,ustPowers;
|
|
|
+ // 查询当前时间点标记时间前10分钟的可用功率
|
|
|
+ Date currentTime = new Date(System.currentTimeMillis());
|
|
|
+ Date startTime = DateUtils.addMinutes(currentTime, -10);
|
|
|
+ Date endTime = DateUtils.addMinutes(currentTime, 1);
|
|
|
+ List<PowerStationStatusData> powerStationStatusDataList = this.powerStationStatusDataRepository.findByTimeBetween(startTime, endTime);
|
|
|
+ List<PowerStationStatusData> filterList = powerStationStatusDataList.stream().filter(t -> t.getAbleValue().compareTo(new BigDecimal("-1")) == 1).collect(Collectors.toList());
|
|
|
+ String coe = super.getSysParameter("CDQ_COE", "1.05");
|
|
|
+
|
|
|
+ Long monentTime = 0L;
|
|
|
+ try {
|
|
|
+ monentTime = DateMomentUtil.getMomentTime(new Date().getTime(), 1, 15 * 60 * 1000L);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("获取当前时刻错误",e);
|
|
|
+ }
|
|
|
+ if (filterList.size() > 0) {
|
|
|
+ // 获取当前时刻对应的短期
|
|
|
+ List<ForecastPowerShortTermOne> currentForecastPowerShortTermList;
|
|
|
+ BigDecimal currentForecastPowerValue = BigDecimal.ZERO;
|
|
|
+ try {
|
|
|
+ Long currentMoment = DateMomentUtil.getMomentTime(currentTime.getTime(), 1, 15 * 60 * 1000L);
|
|
|
+ currentForecastPowerShortTermList = this.forecastPowerShortTermOneRepository.findByForecastTimeBetween(currentMoment, currentMoment);
|
|
|
+ if (currentForecastPowerShortTermList.size()>0){
|
|
|
+ currentForecastPowerValue = currentForecastPowerShortTermList.get(0).getFpValue();
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ // 当前时间没有对应的短期,用实际功率最近的一个替换
|
|
|
+ filterList.sort(Comparator.comparing(PowerStationStatusData::getTime).reversed());
|
|
|
+ currentForecastPowerValue = filterList.get(0).getAbleValue();
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+
|
|
|
+ BigDecimal sumAbleValue = filterList.stream().map(PowerStationStatusData::getAbleValue)
|
|
|
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
+ BigDecimal averageAbleValue = sumAbleValue.divide(new BigDecimal(filterList.size()), 2, BigDecimal.ROUND_HALF_UP);
|
|
|
+ //可用-短期差值
|
|
|
+ BigDecimal deviationValue = averageAbleValue.subtract(currentForecastPowerValue);
|
|
|
+ for (int i = 0; i < forecastPowerShortTermList.size(); i++) {
|
|
|
+ forecastPowerUltraShortTerm = new ForecastPowerUltraShortTermOne();
|
|
|
+ forecastPowerUltraShortTerm.setForecastTime(forecastPowerShortTermList.get(i).getForecastTime());
|
|
|
+ forecastPowerUltraShortTerm.setGenDate(new Date(monentTime));
|
|
|
+ //短期
|
|
|
+ stPower = forecastPowerShortTermList.get(i).getFpValue();
|
|
|
+ //短期*系数
|
|
|
+ ustPowers = stPower.multiply(new BigDecimal(coe)).setScale(2, BigDecimal.ROUND_HALF_UP);
|
|
|
+ // 如果短期预测小于等于0,则超短期为0
|
|
|
+ if (stPower.doubleValue() <= 0) {
|
|
|
+ forecastPowerUltraShortTerm.setFpValue(BigDecimal.ZERO);
|
|
|
+ forecastPowerUltraShortTerm.setDifferenceValue(BigDecimal.ZERO);
|
|
|
+ forecastPowerUltraShortTerm.setCoefficientValue(BigDecimal.ZERO);
|
|
|
+ forecastPowerUltraShortTerm.setPredictionModelEnum(PredictionModelEnum.E4);
|
|
|
+ } else {
|
|
|
+ BigDecimal xzjdq = deviationValue.add(stPower).setScale(2, BigDecimal.ROUND_HALF_UP);
|
|
|
+ String cdqjsfsZbxz = electricFieldService.getSysParameter("cdqjsfsZbxz", "0.4");
|
|
|
+ log.debug("参数cdqjsfsZbxz值为:" + cdqjsfsZbxz + ",超短期计算方式,可用和短期的差值加短期占比。");
|
|
|
+ String cdqjsfsZbdq = electricFieldService.getSysParameter("cdqjsfsZbdq", "0.6");
|
|
|
+ log.debug("参数cdqjsfsZbdq值为:" + cdqjsfsZbdq + ",超短期计算方式,短期占比。");
|
|
|
+ ustPower = xzjdq.multiply(new BigDecimal(cdqjsfsZbxz)).setScale(2, BigDecimal.ROUND_HALF_UP).add(stPower.multiply(new BigDecimal(cdqjsfsZbdq)).setScale(2, BigDecimal.ROUND_HALF_UP));
|
|
|
+ if (ustPower.doubleValue() > capacity.doubleValue()) {
|
|
|
+ // 如果超短期结果超出装机容量,则超短期结果为装机容量
|
|
|
+ forecastPowerUltraShortTerm.setFpValue(capacity);
|
|
|
+ } else if (ustPower.doubleValue() < 0) {
|
|
|
+ // 如果超短期结果小于0,则超短期结果为0
|
|
|
+ forecastPowerUltraShortTerm.setFpValue(BigDecimal.ZERO);
|
|
|
+ }else{
|
|
|
+ if(cdqjsfs.equals("1")){
|
|
|
+ forecastPowerUltraShortTerm.setFpValue(ustPower);
|
|
|
+ forecastPowerUltraShortTerm.setPredictionModelEnum(PredictionModelEnum.E5);
|
|
|
+ }else{
|
|
|
+ forecastPowerUltraShortTerm.setFpValue(ustPowers);
|
|
|
+ forecastPowerUltraShortTerm.setPredictionModelEnum(PredictionModelEnum.E9);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ forecastPowerUltraShortTerm.setDifferenceValue(ustPower);
|
|
|
+ forecastPowerUltraShortTerm.setCoefficientValue(ustPowers);
|
|
|
+ }
|
|
|
+
|
|
|
+ forecastPowerUltraShortTermList.add(forecastPowerUltraShortTerm);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ log.info("库中没有可用,本次可用计算数据采用短期*系数的方式生成数据");
|
|
|
+
|
|
|
+ // 短期乘以系数
|
|
|
+ for (int i = 0; i < forecastPowerShortTermList.size(); i++) {
|
|
|
+ stPower = forecastPowerShortTermList.get(i).getFpValue();
|
|
|
+ ustPower = stPower.multiply(new BigDecimal(coe)).setScale(2, BigDecimal.ROUND_HALF_UP);
|
|
|
+ forecastPowerUltraShortTerm = new ForecastPowerUltraShortTermOne();
|
|
|
+ forecastPowerUltraShortTerm.setForecastTime(forecastPowerShortTermList.get(i).getForecastTime());
|
|
|
+ forecastPowerUltraShortTerm.setPredictionModelEnum(PredictionModelEnum.E9);
|
|
|
+ forecastPowerUltraShortTerm.setCoefficientValue(ustPower);
|
|
|
+ forecastPowerUltraShortTerm.setDifferenceValue(new BigDecimal(-0.99).setScale(2,BigDecimal.ROUND_HALF_UP));
|
|
|
+ forecastPowerUltraShortTerm.setFpValue(ustPower);
|
|
|
+ forecastPowerUltraShortTerm.setGenDate(new Date(monentTime));
|
|
|
+ forecastPowerUltraShortTermList.add(forecastPowerUltraShortTerm);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 保存超短期预测结果
|
|
|
+ this.forecastPowerUltraShortTermOneRepository.deleteByForecastTimeBetween(forecastPowerUltraShortTermList.get(0).getForecastTime(), forecastPowerUltraShortTermList.get(forecastPowerShortTermList.size()-1).getForecastTime());
|
|
|
+ this.forecastPowerUltraShortTermOneRepository.saveAll(forecastPowerUltraShortTermList);
|
|
|
+
|
|
|
+ return forecastPowerUltraShortTermList;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void executeForecastForlight(final List<ForecastPowerShortTermOne> forecastPowerShortTermList, final BigDecimal capacity) {
|
|
|
+ // 暂时光超短期预测方法=风超短期预测方法
|
|
|
+ this.executeForecastForWind(forecastPowerShortTermList, capacity);
|
|
|
+ }
|
|
|
+
|
|
|
+}
|