Forráskód Böngészése

新增超短期计算

xusl 3 éve
szülő
commit
611b9a2a94

+ 138 - 0
ipfcst-common/ipfcst-common-data/src/main/java/com/jiayue/ipfcst/common/data/abst/equipmentstatus/AbstractEquipmentStatusData.java

@@ -0,0 +1,138 @@
+package com.jiayue.ipfcst.common.data.abst.equipmentstatus;
+
+import lombok.Data;
+import org.hibernate.annotations.GenericGenerator;
+import org.springframework.core.annotation.Order;
+
+import javax.persistence.*;
+import javax.validation.constraints.Digits;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 设备数据
+ *
+ * @author zzy
+ * @version 1.0
+ * @since 2019/8/19 14:28
+ */
+
+@Data
+@MappedSuperclass
+public class AbstractEquipmentStatusData implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+
+    @Id
+    @Order(1)
+    @GeneratedValue(strategy = GenerationType.AUTO, generator = "myid")
+    @GenericGenerator(name = "myid", strategy = "com.jiayue.ipfcst.common.data.entity.id.CustomIDGenerator")
+    private Integer id;
+
+    /**
+     * 设备编号
+     */
+    @Column
+    private Integer equipmentNo;
+
+    /**
+     * 状态
+     * 状态值为0代表运行,1代表故障,2代表待机,3代表检修
+     */
+    @Column
+    private Integer status = 0;
+
+
+    /**
+     * 时间
+     */
+    @Temporal(TemporalType.TIMESTAMP)
+    @Column
+    private Date time;
+
+
+    /**
+     * 备用字段1
+     */
+    @Order(200)
+    @Digits(integer = 5, fraction = 2)
+    @Column
+    private BigDecimal data1 = new BigDecimal(-99);
+
+    /**
+     * 备用字段2
+     */
+    @Order(201)
+    @Digits(integer = 5, fraction = 2)
+    @Column
+    private BigDecimal data2 = new BigDecimal(-99);
+
+    /**
+     * 备用字段3
+     */
+    @Order(202)
+    @Digits(integer = 5, fraction = 2)
+    @Column
+    private BigDecimal data3 = new BigDecimal(-99);
+
+    /**
+     * 备用字段4
+     */
+    @Order(203)
+    @Digits(integer = 5, fraction = 2)
+    @Column
+    private BigDecimal data4 = new BigDecimal(-99);
+
+    /**
+     * 备用字段5
+     */
+    @Order(204)
+    @Digits(integer = 5, fraction = 2)
+    @Column
+    private BigDecimal data5 = new BigDecimal(-99);
+
+    /**
+     * 备用字段6
+     */
+    @Order(205)
+    @Digits(integer = 5, fraction = 2)
+    @Column
+    private BigDecimal data6 = new BigDecimal(-99);
+
+    /**
+     * 备用字段7
+     */
+    @Order(206)
+    @Digits(integer = 5, fraction = 2)
+    @Column
+    private BigDecimal data7 = new BigDecimal(-99);
+
+    /**
+     * 备用字段8
+     */
+    @Order(207)
+    @Digits(integer = 5, fraction = 2)
+    @Column
+    private BigDecimal data8 = new BigDecimal(-99);
+
+
+    /**
+     * 备用字段9
+     */
+    @Order(208)
+    @Digits(integer = 5, fraction = 2)
+    @Column
+    private BigDecimal data9 = new BigDecimal(-99);
+
+    /**
+     * 备用字段10
+     */
+    @Order(209)
+    @Digits(integer = 5, fraction = 2)
+    @Column
+    private BigDecimal data10 = new BigDecimal(-99);
+
+
+}

+ 186 - 0
ipfcst-common/ipfcst-common-data/src/main/java/com/jiayue/ipfcst/common/data/entity/PowerStationStatusData.java

@@ -0,0 +1,186 @@
+package com.jiayue.ipfcst.common.data.entity;
+
+import com.jiayue.ipfcst.common.data.abst.equipmentstatus.AbstractEquipmentStatusData;
+import lombok.Data;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.validation.constraints.Digits;
+import java.math.BigDecimal;
+
+/**
+ * 场站功率状态抽象实体
+ *
+ * @author zzy
+ * @version 1.0
+ * @since 2019/8/2 9:34
+ */
+@Entity
+@Data
+public class PowerStationStatusData extends AbstractEquipmentStatusData {
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 时间
+	 */
+  /*  @Id
+    @Temporal(TemporalType.TIMESTAMP)
+    @Column
+    private Date time;*/
+
+	@Column
+	String stationCode;
+
+	/**
+	 * 人工判断是否限电
+	 * 0  以系统判断结果为准
+	 * 1 限电
+	 * 2 不限电
+	 */
+	@Column
+	Integer isRationingByManualControl;
+	/**
+	 * 系统自动判断是否限电
+	 */
+	@Column
+	Boolean isRationingByAutoControl;
+	/**
+	 * 实际功率(MW)
+	 */
+	@Digits(integer = 10, fraction = 2)
+	@Column
+	private BigDecimal realValue = new BigDecimal(-99);
+	/**
+	 * 可用功率(MW)
+	 */
+	@Digits(integer = 10, fraction = 2)
+	@Column
+	private BigDecimal ableValue = new BigDecimal(-99);
+	/**
+	 * 理论功率(MW)
+	 */
+	@Digits(integer = 10, fraction = 2)
+	@Column
+	private BigDecimal theoryValue = new BigDecimal(-99);
+	/**
+	 * 样板机参照功率(MW)  理论
+	 */
+	@Digits(integer = 10, fraction = 2)
+	@Column
+	private BigDecimal referencePowerBySample = new BigDecimal(-99);
+	/**
+	 * 测风/光法 参照功率(MW) 理论
+	 */
+	@Digits(integer = 10, fraction = 2)
+	@Column
+	private BigDecimal referencePowerByMeasuring = new BigDecimal(-99);
+	/**
+	 * 样板机法功率(MW) 可用
+	 */
+	@Digits(integer = 10, fraction = 2)
+	@Column
+	private BigDecimal ablePowerBySample = new BigDecimal(-99);
+	/**
+	 * 测风/光法 (MW) 可用
+	 */
+	@Digits(integer = 10, fraction = 2)
+	@Column
+	private BigDecimal ablePowerByMeasuring = new BigDecimal(-99);
+	/**
+	 * 样板机法的异常值
+	 */
+	@Digits(integer = 10, fraction = 2)
+	@Column
+	private BigDecimal abnormalOfSample = new BigDecimal(-99);
+	/**
+	 * 测风光法的异常值
+	 */
+	@Digits(integer = 10, fraction = 2)
+	@Column
+	private BigDecimal abnormalOfMeasuring = new BigDecimal(-99);
+	/**
+	 * 开机容量(MW)
+	 */
+	@Digits(integer = 10, fraction = 2)
+	@Column
+	private BigDecimal openCapacity = new BigDecimal(-99);
+	/**
+	 * 装机容量(MW)
+	 */
+	@Digits(integer = 10, fraction = 2)
+	@Column
+	private BigDecimal capacity = new BigDecimal(-99);
+	/**
+	 * 站内受阻功率(MW)
+	 */
+	@Digits(integer = 10, fraction = 2)
+	@Column
+	private BigDecimal onSiteObstructed = new BigDecimal(-99);
+	/**
+	 * 日发电量(MW)
+	 */
+	@Digits(integer = 10, fraction = 2)
+	@Column
+	private BigDecimal dailyOutPut = new BigDecimal(-99);
+	/**
+	 * 日上网电量(MW)
+	 * Power Grid  电网
+	 */
+	@Digits(integer = 10, fraction = 2)
+	@Column
+	private BigDecimal dailyGridOutPut = new BigDecimal(-99);
+	/**
+	 * 站外受阻功率(MW)
+	 */
+	@Digits(integer = 10, fraction = 2)
+	@Column
+	private BigDecimal offSiteObstructed = new BigDecimal(-99);
+	/**
+	 * 并网设备数(个)
+	 */
+	@Column
+	private Integer onGridNum;
+
+	public void setAbleValue(BigDecimal ableValue) {
+		if (ableValue == null) {
+			this.ableValue = null;
+			return;
+		}
+		if (this.openCapacity == null || this.openCapacity.compareTo(BigDecimal.valueOf(-99)) == 0) {
+			this.ableValue = ableValue;
+		} else {
+			if (this.openCapacity.compareTo(ableValue) < 0) {
+				this.ableValue = this.openCapacity;
+			} else {
+				this.ableValue = ableValue;
+			}
+		}
+		if (this.capacity == null || this.capacity.compareTo(BigDecimal.valueOf(-99)) == 0) {
+			this.ableValue = ableValue;
+		} else {
+			if (this.capacity.compareTo(ableValue) < 0) {
+				this.ableValue = this.capacity;
+			} else {
+				this.ableValue = ableValue;
+			}
+		}
+	}
+
+	public void setTheoryValue(BigDecimal theoryValue) {
+		if (theoryValue == null) {
+			this.theoryValue = null;
+			return;
+		}
+		if (this.capacity.compareTo(BigDecimal.valueOf(-99)) == 0) {
+			this.theoryValue = theoryValue;
+		} else {
+			if (this.capacity.compareTo(theoryValue) < 0) {
+				this.theoryValue = this.capacity;
+			} else {
+				this.theoryValue = theoryValue;
+			}
+		}
+	}
+
+}

+ 64 - 0
ipfcst-common/ipfcst-common-data/src/main/java/com/jiayue/ipfcst/common/data/repository/ForecastPowerUltraShortTermHisRepository.java

@@ -0,0 +1,64 @@
+package com.jiayue.ipfcst.common.data.repository;
+
+
+import com.jiayue.ipfcst.common.data.entity.ForecastPowerUltraShortTermHis;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 上报超短期预测数据实体
+ *
+ * @author zzy
+ * @version 1.0
+ * @since 2019/8/2 12:53
+ */
+public interface ForecastPowerUltraShortTermHisRepository extends BaseRepository<ForecastPowerUltraShortTermHis, Integer> {
+
+	/**
+	 * 根据时间段删除当前时刻生成的超短期历史期数据
+	 *
+	 * @param startTime 开始时间
+	 * @param endTime   结束时间
+	 */
+	@Modifying
+	@Query(value = "delete from ForecastPowerUltraShortTermHis t where t.forecastTime >= ?1 and t.forecastTime<= ?2 and t.genDate = ?3 and t.stationCode= ?4")
+	void deleteNowMoment(Long startTime, Long endTime, Date nowMomentTime,String stationCode);
+
+	/**
+	 * 根据提前多久,开始结束时间查询历史超短期 yh
+	 *
+	 * @param startTime 开始时间
+	 * @param endTime   结束时间
+	 * @param ago       提前多久预测
+	 * @return 结果集
+	 */
+	List<ForecastPowerUltraShortTermHis> findByForecastTimeBetweenAndForecastHowLongAgo(Long startTime, Long endTime, Integer ago);
+	/**
+	 * 根据提前多久,时间查询历史超短期 yh
+	 *
+	 * @param queryTime 时间
+	 * @param ago       提前多久预测
+	 * @return 结果集
+	 */
+	ForecastPowerUltraShortTermHis findByForecastTimeAndForecastHowLongAgo(Long queryTime, Integer ago);
+	/**
+	 * 根据预测时间查询历史超短期 yh
+	 *
+	 * @param queryTime 时间
+
+	 * @return 结果集
+	 */
+	List<ForecastPowerUltraShortTermHis> findByForecastTime(Long queryTime);
+	/**
+	 * 根据提前多久,开始结束时间查询历史超短期 yh
+	 *
+	 * @param startTime 开始时间
+	 * @param endTime   结束时间
+	 * @return 结果集
+	 */
+	List<ForecastPowerUltraShortTermHis> findByForecastTimeBetween(Long startTime, Long endTime);
+
+}

+ 34 - 0
ipfcst-common/ipfcst-common-data/src/main/java/com/jiayue/ipfcst/common/data/repository/ForecastPowerUltraShortTermRepository.java

@@ -0,0 +1,34 @@
+package com.jiayue.ipfcst.common.data.repository;
+
+
+import com.jiayue.ipfcst.common.data.entity.ForecastPowerUltraShortTerm;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 实时超短期预测数据实体
+ *
+ * @author zzy
+ * @version 1.0
+ * @since 2019/8/2 12:53
+ */
+public interface ForecastPowerUltraShortTermRepository extends BaseRepository<ForecastPowerUltraShortTerm, Serializable> {
+
+	/**
+	 * 根据预测时间段查询预测数据
+	 *
+	 * @param stTime 开始时间
+	 * @param eTime  结束时间
+	 * @return 超短期预测数据集合
+	 */
+	List<ForecastPowerUltraShortTerm> deleteByForecastTimeBetweenAndStationCode(Long stTime, Long eTime,String stationCode);
+
+	/**
+	 * 按时间段查询数据
+	 *
+	 * @param startTime
+	 * @param endTime
+	 */
+	List<ForecastPowerUltraShortTerm> findByForecastTimeBetweenAndStationCode(Long startTime, Long endTime,String stationCode);
+}

+ 33 - 0
ipfcst-common/ipfcst-common-data/src/main/java/com/jiayue/ipfcst/common/data/repository/PowerStationStatusDataRepository.java

@@ -0,0 +1,33 @@
+package com.jiayue.ipfcst.common.data.repository;
+
+
+import com.jiayue.ipfcst.common.data.entity.PowerStationStatusData;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 实际功率仓储
+ *
+ * @author zzy
+ * @version 1.0
+ * @since 2019/8/6 12:42
+ */
+public interface PowerStationStatusDataRepository extends BaseRepository<PowerStationStatusData, Integer> {
+	/**
+	 * 按时间段查询数据
+	 *
+	 * @param startTime 开始时间
+	 * @param endTime 结束时间
+	 * @return 结果集
+	 */
+
+	List<PowerStationStatusData> findByTimeBetweenAndStationCode(Date startTime, Date endTime,String stationCode);
+	/**
+	 * 按时间段查询数据
+	 *
+	 * @param queryTime 开始时间
+	 * @return 结果集
+	 */
+	PowerStationStatusData findByTime(Date queryTime);
+}

+ 1 - 1
ipfcst-common/ipfcst-common-data/src/main/java/com/jiayue/ipfcst/common/data/repository/SysParameterRepository.java

@@ -14,7 +14,7 @@ import java.util.Optional;
 public interface SysParameterRepository extends BaseRepository<SysParameter, Integer> {
 	Optional<SysParameter> findBySysKeyAndStationCode(String sysKey,String stationCode);
 
-	Boolean existsBySysKey(String sysKey);
+	Boolean existsBySysKeyAndStationCode(String sysKey,String stationCode);
 
 	SysParameter findBySysKeyEquals(String sysKey);
 }

+ 12 - 1
ipfcst-common/ipfcst-common-data/src/main/java/com/jiayue/ipfcst/common/data/service/BaseService.java

@@ -80,7 +80,7 @@ public class BaseService {
 	}
 
 	/**
-	 * 查询场站信息
+	 * 查询单个场站信息
 	 *
 	 * @return 场站信息
 	 */
@@ -96,6 +96,17 @@ public class BaseService {
 	}
 
 	/**
+	 * 查询多场站信息
+	 *
+	 * @return 场站信息
+	 */
+	@Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
+	public List<ElectricField> getMultipleStation() throws BusinessException {
+		return this.electricFieldRepository.findAll();
+
+	}
+
+	/**
 	 * 查询开机容量
 	 *
 	 * @param startTime 开始时间

+ 397 - 0
ipfcst-console/src/main/java/com/jiayue/ipfcst/console/service/ForecastPowerUltraShortTermService.java

@@ -0,0 +1,397 @@
+package com.jiayue.ipfcst.console.service;
+
+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.ForecastPowerShortTermRepository;
+import com.jiayue.ipfcst.common.data.repository.ForecastPowerUltraShortTermHisRepository;
+import com.jiayue.ipfcst.common.data.repository.ForecastPowerUltraShortTermRepository;
+import com.jiayue.ipfcst.common.data.repository.PowerStationStatusDataRepository;
+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 ForecastPowerUltraShortTermService extends BaseService {
+  @Autowired
+  ElectricFieldService electricFieldService;
+  @Autowired
+  ForecastPowerShortTermRepository forecastPowerShortTermRepository;
+  @Autowired
+  SysParameterService sysParameterService;
+  @Autowired
+  PowerStationStatusDataRepository powerStationStatusDataRepository;
+  @Autowired
+  ForecastPowerUltraShortTermRepository forecastPowerUltraShortTermRepository;
+  @Autowired
+  ForecastPowerUltraShortTermHisRepository forecastPowerUltraShortTermHisRepository;
+  @Autowired
+  ForecastPowerShortTermService forecastPowerShortTermService;
+
+  /**
+   * 生成超短期预测功率,自动更新覆盖预测功率
+   *
+   * @param startTime 开始时间
+   * @param endTime   结束时间
+   */
+  @Transactional(propagation = Propagation.REQUIRED)
+  public void buildForecastPowerUltraShortTerm(@NotNull final Long startTime, @NotNull final Long endTime,String stationCode) {
+    this.getForecastPowerUltraShortTerm(startTime, endTime,stationCode);
+  }
+
+  /**
+   * 获取超短期预测功率,当数据库中超短期预测记录不足查询所需时,进行本地化计算,用于上报专用
+   *
+   * @param startTime 开始时间
+   * @param endTime   结束时间
+   * @return 预测功率结果集
+   */
+  @SuppressWarnings("WeakerAccess")
+  @Transactional(propagation = Propagation.REQUIRED)
+  public List<ForecastPowerUltraShortTermHis> getForecastPowerUltraShortTerm(@NotNull final Long startTime, @NotNull final Long endTime, @NotNull final String stationCode) {
+    log.info(stationCode+"开始获取超短期实时预测功率" + DateFormatUtils.format(startTime, "yyyy-MM-dd HH:mm:ss") + " 至 " + DateFormatUtils.format(endTime, "yyyy-MM-dd HH:mm:ss"));
+    // 查询场站信息
+    ElectricField electricFieldInfo = electricFieldService.getSingleStation(stationCode);
+    // 查询预测时间点对应的开机容量
+    Map<Long, BigDecimal> openCapacityMap = null;
+    try {
+      openCapacityMap = super.queryOpenCapacity(startTime, endTime, electricFieldInfo.getCapacity(),stationCode);
+    } catch (BusinessException e) {
+      log.error(stationCode+"超短期数据生成获取开机容量出错:" + CommonUtil.printStackTraceToString(e));
+    }
+    Long monentTime = 0L;
+    try {
+      monentTime = DateMomentUtil.getMomentTime(new Date().getTime(), 1, 15 * 60 * 1000L);
+    } catch (Exception e) {
+      log.error(stationCode+"获取当前时刻错误",e);
+    }
+
+    List<ForecastPowerUltraShortTerm> forecastPowerUltraShortTermList = new ArrayList<>();
+    List<ForecastPowerUltraShortTerm> tempList = this.forecastPowerUltraShortTermRepository.findByForecastTimeBetweenAndStationCode(startTime, endTime,stationCode);
+    for (ForecastPowerUltraShortTerm 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(stationCode+"获取所需记录数:" + moments);
+
+    if (moments > forecastPowerUltraShortTermList.size()) {
+      Map<Long, List<ForecastPowerUltraShortTerm>> forecastPowerShortTermsMap = forecastPowerUltraShortTermList.stream().collect(Collectors.groupingBy(ForecastPowerUltraShortTerm::getForecastTime));
+      for (Long tempTime = startTime; tempTime <= endTime; tempTime = tempTime + momentTime) {
+        if (forecastPowerShortTermsMap.get(tempTime) == null) {
+          log.info(stationCode+"文件超短期缺点:"+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);
+          ForecastPowerUltraShortTerm forecastPowerUltraShortTerm = new ForecastPowerUltraShortTerm();
+          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));
+          forecastPowerUltraShortTerm.setStationCode(stationCode);
+          // 保存超短期实时预测记录
+          this.forecastPowerUltraShortTermRepository.save(forecastPowerUltraShortTerm);
+          forecastPowerUltraShortTermList.add(forecastPowerUltraShortTerm);
+        }
+      }
+    }
+    log.info(stationCode+"生成超短期实时预测功率记录数:" + forecastPowerUltraShortTermList.size());
+    // 按预测时刻升序
+    forecastPowerUltraShortTermList.sort(Comparator.comparing(ForecastPowerUltraShortTerm::getForecastTime));
+
+    // 处理超短期历史记录
+    List<ForecastPowerUltraShortTermHis> forecastPowerUltraShortTermHiss = new ArrayList<>();
+    ForecastPowerUltraShortTermHis forecastPowerUltraShortTermHis;
+    int n = 1;
+    // 生成超短期历史数据
+    BigDecimal openCapacity;
+    //生成数据
+    for (ForecastPowerUltraShortTerm forecastPowerUltraShortTerm : forecastPowerUltraShortTermList) {
+      forecastPowerUltraShortTermHis = new ForecastPowerUltraShortTermHis();
+      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));
+      forecastPowerUltraShortTermHis.setStationCode(stationCode);
+      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",stationCode);
+    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(stationCode+"超短期数据用实际功率替换生成时刻步长错误", e);
+        pre5Time = DateMomentUtil.getDayStartTime(systemDate.getTime());
+      }
+      List<PowerStationStatusData> realPowerList = powerStationStatusDataRepository.findByTimeBetweenAndStationCode(new Date(pre5Time), new Date(pre5Time + 5 * 60 * 1000 - 1000),stationCode);
+      if (realPowerList.size() > 0) {
+        // 按时间降序排列
+        realPowerList.sort(Comparator.comparing(PowerStationStatusData::getTime).reversed());
+        // 获取最后一条最新的实际功率
+        PowerStationStatusData realPower = realPowerList.get(0);
+        // 将实际功率替换到对应的超短期点位上
+        ForecastPowerUltraShortTermHis d = forecastPowerUltraShortTermHiss.get(replacePoint - 1);
+        if (realPower.getRealValue().compareTo(new BigDecimal(0)) != -1) {
+          d.setAbleValue(realPower.getRealValue());
+        }
+      }
+    }
+
+    String lowerPredictionLimit = super.getSysParameter("LowerPredictionLimit", "0",stationCode);
+    BigDecimal lpl = new BigDecimal(lowerPredictionLimit);
+
+    forecastPowerUltraShortTermHiss.forEach(s->{
+      if(s.getAbleValue().compareTo(lpl)==-1){
+        s.setAbleValue(lpl);
+      }
+    });
+
+    // 删除当前时刻标记时间生成的超短期历史记录
+    this.forecastPowerUltraShortTermHisRepository.deleteNowMoment(startTime, endTime, new Date(monentTime),stationCode);
+    // 保存超短期历史记录
+    this.forecastPowerUltraShortTermHisRepository.saveAll(forecastPowerUltraShortTermHiss);
+    return forecastPowerUltraShortTermHiss;
+  }
+
+  /**
+   * 执行超短期预测
+   */
+  @Transactional(propagation = Propagation.REQUIRED, rollbackFor = RuntimeException.class)
+  public void executeForecast() {
+    // 获取多场站
+    List<ElectricField> electricFieldList = new ArrayList<>();
+    try {
+      electricFieldList = super.getMultipleStation();
+    } catch (BusinessException e) {
+      log.error("生成超短期实时获取多场站失败",e);
+    }
+
+    if (electricFieldList.isEmpty()){
+      log.error("没有找到场站,不能执行超短期实时数据生成");
+    }
+    else{
+      for (ElectricField electricField:electricFieldList){
+        String stationCode = electricField.getStationCode();
+        // 根据场站类型执行相应超短期预测
+        try {
+          String cdqUpMin = super.getSysParameter("CDQ_UP_MIN", "0",stationCode);
+          Long currentTime = System.currentTimeMillis()+ Integer.parseInt(cdqUpMin) * 1000 * 60;
+          String llcdq_point = sysParameterService.getSysParameter("FILE_LLCDQ_POINT", "16",stationCode);
+          Integer forecastPoints = Integer.parseInt(llcdq_point);
+          Integer forecastMinutes = forecastPoints * 15;
+
+          // 超短期提前N分钟生成文件
+          Long startTime = DateMomentUtil.getMomentTime(currentTime, 1, 15 * 60 * 1000L);
+          // 结束时间增加15分钟为了防止文件先生成,实时表中最后一个时间点没有点位的问题
+          Long endTime = DateUtils.addMinutes(new Date(startTime), forecastMinutes).getTime()+1000 * 60 * 15L;
+          // 查询该时间段内的短期预测功率
+          List<ForecastPowerShortTerm> forecastPowerShortTermList = this.forecastPowerShortTermRepository.findByForecastTimeBetweenAndStationCode(startTime, endTime,stationCode);
+          Map<Long, List<ForecastPowerShortTerm>> forecastPowerShortTermsMap =
+            forecastPowerShortTermList.stream().collect(Collectors.groupingBy(ForecastPowerShortTerm::getForecastTime));
+          Map<Long, BigDecimal> openCapacityMap = null;
+          try {
+            openCapacityMap = super.queryOpenCapacity(startTime, endTime, electricField.getCapacity(),stationCode);
+          } catch (BusinessException e) {
+            log.error("预测数据生成获取开机容量出错:" + CommonUtil.printStackTraceToString(e));
+          }
+          List<ForecastPowerShortTerm> addForecastPowerShortTermList = new ArrayList<>();
+          // 判断短期数据是否缺点
+          for (Long tempTime = startTime; tempTime <= endTime; tempTime = tempTime + 15 * 60 * 1000L) {
+            if (forecastPowerShortTermsMap.get(tempTime) == null) {
+              // 缺失时间点
+              ForecastPowerShortTerm forecastPowerShortTerms = null;
+              if (ElectricFieldTypeEnum.E1.compareTo(electricField.getElectricFieldTypeEnum()) == 0) {
+                forecastPowerShortTerms = forecastPowerShortTermService.generateSolarPowerShortTerm(tempTime, openCapacityMap.get(tempTime), electricField);
+              } else {
+                forecastPowerShortTerms = forecastPowerShortTermService.generateWindPowerShortTerm(tempTime, openCapacityMap.get(tempTime),stationCode);
+              }
+              addForecastPowerShortTermList.add(forecastPowerShortTerms);
+            }
+          }
+          if (!addForecastPowerShortTermList.isEmpty()) {
+            // 保存短期预测
+            this.forecastPowerShortTermRepository.saveAll(addForecastPowerShortTermList);
+            // 将补齐的预测功率追加到查询预测功率结果集中
+            forecastPowerShortTermList.addAll(addForecastPowerShortTermList);
+          }
+          forecastPowerShortTermList.sort(Comparator.comparing(ForecastPowerShortTerm::getForecastTime));
+
+          if (ElectricFieldTypeEnum.E1.compareTo(electricField.getElectricFieldTypeEnum()) == 0) {
+            // 光伏电站
+            this.executeForecastForlight(forecastPowerShortTermList, electricField.getCapacity(),stationCode);
+          } else if (ElectricFieldTypeEnum.E2.compareTo(electricField.getElectricFieldTypeEnum()) == 0) {
+            // 风力电场
+            this.executeForecastForWind(forecastPowerShortTermList, electricField.getCapacity(),stationCode);
+          } else {
+            log.error("场站类型非法!");
+          }
+        } catch (BusinessException e) {
+          log.error("获取场站信息出错!", e);
+        } catch (Exception e) {
+          log.error("系统运行错误!", e);
+        }
+      }
+    }
+  }
+
+  /**
+   * 执行风电场超短期预测
+   *
+   * @param forecastPowerShortTermList 短期预测结果集
+   * @param capacity                   装机容量
+   */
+  private List<ForecastPowerUltraShortTerm> executeForecastForWind(final List<ForecastPowerShortTerm> forecastPowerShortTermList, final BigDecimal capacity,String stationCode) {
+    List<ForecastPowerUltraShortTerm> forecastPowerUltraShortTermList = new ArrayList<>();
+    ForecastPowerUltraShortTerm forecastPowerUltraShortTerm;
+    //获取系统参数cdqjsfs,超短期计算方式,0为默认乘系数的方式,1为根据可用功率计算的方式
+    String cdqjsfs = electricFieldService.getSysParameter("cdqjsfs", "1",stationCode);
+    log.info("参数cdqjsfs值为:" + cdqjsfs + ",超短期计算方式,0为默认乘系数的方式,1为根据可用功率计算的方式。");
+    BigDecimal stPower, ustPower,ustPowers;
+    // 判断查询可用功率结果是否为空,如果不为空根据平均可用功率与短期预测结果的偏差值进行计算超短期结果,否则超短期=短期*随机系数
+    // 查询当前时间点标记时间前10分钟的可用功率
+    ForecastPowerShortTerm currentForecastPowerShortTerm = forecastPowerShortTermList.get(0);
+    Date currentTime = new Date(currentForecastPowerShortTerm.getForecastTime());
+    Date startTime = DateUtils.addMinutes(currentTime, -10);
+    Date endTime = DateUtils.addMinutes(currentTime, 1);
+    List<PowerStationStatusData> powerStationStatusDataList = this.powerStationStatusDataRepository.findByTimeBetweenAndStationCode(startTime, endTime,stationCode);
+    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",stationCode);
+
+    Long monentTime = 0L;
+    try {
+      monentTime = DateMomentUtil.getMomentTime(new Date().getTime(), 1, 15 * 60 * 1000L);
+    } catch (Exception e) {
+      log.error("获取当前时刻错误",e);
+    }
+    if (filterList.size() > 0) {
+      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(currentForecastPowerShortTerm.getFpValue());
+      for (int i = 1; i < forecastPowerShortTermList.size(); i++) {
+        forecastPowerUltraShortTerm = new ForecastPowerUltraShortTerm();
+        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",stationCode);
+          log.debug("参数cdqjsfsZbxz值为:" + cdqjsfsZbxz + ",超短期计算方式,可用和短期的差值加短期占比。");
+          String cdqjsfsZbdq = electricFieldService.getSysParameter("cdqjsfsZbdq", "0.6",stationCode);
+          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);
+        }
+        forecastPowerUltraShortTerm.setStationCode(stationCode);
+        forecastPowerUltraShortTermList.add(forecastPowerUltraShortTerm);
+      }
+    } else {
+      log.info("库中没有可用,本次可用计算数据采用短期*系数的方式生成数据");
+
+      // 短期乘以系数
+      for (int i = 1; i < forecastPowerShortTermList.size(); i++) {
+        stPower = forecastPowerShortTermList.get(i).getFpValue();
+        ustPower = stPower.multiply(new BigDecimal(coe)).setScale(2, BigDecimal.ROUND_HALF_UP);
+        forecastPowerUltraShortTerm = new ForecastPowerUltraShortTerm();
+        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));
+        forecastPowerUltraShortTerm.setStationCode(stationCode);
+        forecastPowerUltraShortTermList.add(forecastPowerUltraShortTerm);
+      }
+    }
+    // 保存超短期预测结果
+    this.forecastPowerUltraShortTermRepository.deleteByForecastTimeBetweenAndStationCode(forecastPowerShortTermList.get(1).getForecastTime(), forecastPowerShortTermList.get(forecastPowerShortTermList.size() - 1).getForecastTime(),stationCode);
+    this.forecastPowerUltraShortTermRepository.saveAll(forecastPowerUltraShortTermList);
+
+    return forecastPowerUltraShortTermList;
+  }
+
+  private void executeForecastForlight(final List<ForecastPowerShortTerm> forecastPowerShortTermList, final BigDecimal capacity,String stationCode) {
+    // 暂时光超短期预测方法=风超短期预测方法
+    this.executeForecastForWind(forecastPowerShortTermList, capacity,stationCode);
+  }
+
+}

+ 128 - 0
ipfcst-console/src/main/java/com/jiayue/ipfcst/console/service/SysParameterService.java

@@ -0,0 +1,128 @@
+package com.jiayue.ipfcst.console.service;
+
+import cn.hutool.core.util.StrUtil;
+import com.jiayue.ipfcst.common.core.exception.BusinessException;
+import com.jiayue.ipfcst.common.data.entity.SysParameter;
+import com.jiayue.ipfcst.common.data.repository.SysParameterRepository;
+import com.jiayue.ipfcst.common.data.service.BaseService;
+import lombok.extern.slf4j.Slf4j;
+import net.sf.ehcache.Cache;
+import net.sf.ehcache.Element;
+import net.sf.ehcache.search.Attribute;
+import net.sf.ehcache.search.Query;
+import net.sf.ehcache.search.Result;
+import net.sf.ehcache.search.Results;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.ehcache.EhCacheCacheManager;
+import org.springframework.data.domain.*;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * 系统参数业务层
+ *
+ * @author zzy
+ * @version 1.0
+ * @since 2019/8/6 16:35
+ */
+@Service
+@Slf4j
+public class SysParameterService extends BaseService {
+
+    private final SysParameterRepository sysParameterRepository;
+
+    private final EhCacheCacheManager ehCacheCacheManager;
+
+    @Autowired
+    public SysParameterService(SysParameterRepository sysParameterRepository, EhCacheCacheManager ehCacheCacheManager) {
+        this.sysParameterRepository = sysParameterRepository;
+        this.ehCacheCacheManager = ehCacheCacheManager;
+    }
+
+    /**
+     * 新增系统参数
+     *
+     * @param sysParameter 系统参数实体
+     * @throws BusinessException 业务异常
+     */
+    @Transactional(propagation = Propagation.SUPPORTS)
+    public void add(SysParameter sysParameter) throws BusinessException {
+        boolean b = this.sysParameterRepository.existsBySysKeyAndStationCode(sysParameter.getSysKey(),sysParameter.getStationCode());
+        if (b) {// 参数已存在
+            throw new BusinessException("系统参数已存在!");
+        } else {
+            this.sysParameterRepository.save(sysParameter);
+        }
+    }
+
+    /**
+     * 修改系统参数
+     *
+     * @param sysParameter 系统参数实体
+     * @throws BusinessException 业务异常
+     */
+    @Transactional(propagation = Propagation.SUPPORTS)
+    public void update(SysParameter sysParameter) throws BusinessException {
+        if (StrUtil.isEmpty(sysParameter.getSysKey())) {
+            throw new BusinessException("系统参数标识不能为空!");
+        } else {
+            this.sysParameterRepository.save(sysParameter);
+        }
+    }
+
+    /**
+     * 删除系统参数
+     *
+     * @param id 主键编号
+     * @throws BusinessException 业务异常
+     */
+    @Transactional(rollbackFor = Exception.class, propagation = Propagation.SUPPORTS)
+    public void delete(final Integer id) throws BusinessException {
+        this.sysParameterRepository.deleteById(id);
+    }
+
+    /**
+     * 查询参数
+     *
+     * @param sysParameter 查询条件
+     * @param page         页码
+     * @param size         每页记录数
+     * @return 分页结果
+     */
+    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
+    public Page<SysParameter> get(final SysParameter sysParameter, final Integer page, final Integer size) {
+        ExampleMatcher matcher = ExampleMatcher.matching()
+                .withMatcher("sysKey", ExampleMatcher.GenericPropertyMatchers.contains())
+                .withMatcher("sysValue", ExampleMatcher.GenericPropertyMatchers.contains())
+                .withMatcher("describe", ExampleMatcher.GenericPropertyMatchers.contains());
+        Example<SysParameter> example = Example.of(sysParameter, matcher);
+        Pageable pageable = PageRequest.of(page - 1, size);
+        return this.sysParameterRepository.findAll(example, pageable);
+    }
+
+    /**
+     * 查询参数值
+     *
+     * @param id 主键编号
+     * @return 参数
+     */
+    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
+    public String getParameter(final Integer id) {
+        Optional<SysParameter> sysParameterOptional = this.sysParameterRepository.findById(id);
+        return sysParameterOptional.map(SysParameter::getSysValue).orElse(null);
+    }
+
+    /**
+     * 查询所有参数信息
+     *
+     * @return 通道信息
+     */
+    public List<SysParameter> getAll() {
+      return  sysParameterRepository.findAll();
+    }
+}