浏览代码

碳排预测任务

learshaw 1 月之前
父节点
当前提交
09a07e6ab0

+ 7 - 0
ems/ems-cloud/ems-server/src/main/java/com/ruoyi/ems/config/AnalysisConfig.java

@@ -40,6 +40,9 @@ public class AnalysisConfig {
     @Value("${analysis-task.carbon-calculation.area-codes}")
     private String carbonCalcArea;
 
+    @Value("${analysis-task.carbon-forecast.area-codes}")
+    private String carbonForecastArea;
+
     @Value("${analysis-task.pv-forecast.forecastDays}")
     private int prodForecastDays;
 
@@ -62,6 +65,10 @@ public class AnalysisConfig {
         return StringUtils.split(carbonCalcArea, ",");
     }
 
+    public String[] getCarbonForecastAreas() {
+        return StringUtils.split(carbonForecastArea, ",");
+    }
+
     public int getProdForecastDays() {
         return prodForecastDays;
     }

+ 26 - 0
ems/ems-cloud/ems-server/src/main/java/com/ruoyi/ems/task/TaskService.java

@@ -348,6 +348,32 @@ public class TaskService {
         }
     }
 
+    /**
+     * 碳排预测
+     */
+    @Async
+    @Scheduled(cron = "${analysis-task.carbon-forecast.cron}")
+    public void carbonForecastTask() {
+        log.debug("start carbon forecast task.");
+
+        try {
+            // 获取今天的日期
+            LocalDate today = LocalDate.now();
+            String[] areaCodes = analysisConfig.getCarbonForecastAreas();
+
+            if (ArrayUtils.isNotEmpty(areaCodes)) {
+                for (String areaCode : areaCodes) {
+                    // 碳排碳汇
+                    carbonCalculationService.calculateMonthCarbonForecast(areaCode, today);
+                }
+            }
+        }
+        catch (Exception e) {
+            log.error("carbon calculation fail!", e);
+        }
+    }
+
+
     private void areaElecConsumeForecast(String rootArea, LocalDate today) {
         List<Area> areas = areaService.selectAreaTree(rootArea, true);
         areaElecConsumeForecastSub(rootArea, areas, today);

+ 3 - 0
ems/ems-cloud/ems-server/src/main/resources/application-local.yml

@@ -73,6 +73,9 @@ analysis-task:
   carbon-calculation:
     cron: 0 0 2 * * ?
     area-codes: 321283124S3001,321283124S3002
+  carbon-forecast:
+    cron: 0 10 2 1 * ?
+    area-codes: 321283124S3001,321283124S3002
 
 # 定时任务配置
 # mybatis配置

+ 3 - 0
ems/ems-cloud/ems-server/src/main/resources/application-prod-ct.yml

@@ -73,6 +73,9 @@ analysis-task:
   carbon-calculation:
     cron: 0 0 2 * * ?
     area-codes: 321283124S3001,321283124S3002
+  carbon-forecast:
+    cron: 0 10 2 1 * ?
+    area-codes: 321283124S3001,321283124S3002
 
 # mybatis配置
 mybatis:

+ 4 - 5
ems/ems-core/src/main/java/com/ruoyi/ems/domain/CaEmissionForecast.java

@@ -37,14 +37,13 @@ public class CaEmissionForecast extends BaseEntity {
     /**
      * 日期
      */
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @Excel(name = "日期", width = 30, dateFormat = "yyyy-MM-dd")
-    private Date date;
+    @Excel(name = "日期", width = 30, dateFormat = "yyyy-MM")
+    private String month;
 
     /**
      * (千克)
      */
-    @Excel(name = "", readConverterExp = "千=克")
+    @Excel(name = "", readConverterExp = "千克")
     private Double caEmission;
 
     @Override
@@ -52,7 +51,7 @@ public class CaEmissionForecast extends BaseEntity {
         return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
                 .append("id", getId())
                 .append("areaCode", getAreaCode())
-                .append("date", getDate())
+                .append("date", getMonth())
                 .append("caEmission", getCaEmission())
                 .toString();
     }

+ 9 - 6
ems/ems-core/src/main/java/com/ruoyi/ems/mapper/CaEmissionForecastMapper.java

@@ -1,6 +1,7 @@
 package com.ruoyi.ems.mapper;
 
 import com.ruoyi.ems.domain.CaEmissionForecast;
+import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
 
@@ -22,26 +23,28 @@ public interface CaEmissionForecastMapper {
     /**
      * 查询碳排放预测列表
      *
-     * @param admEmsCaEmissionForecast 碳排放预测
+     * @param caEmissionForecast 碳排放预测
      * @return 碳排放预测集合
      */
-    List<CaEmissionForecast> selectCaEmissionForecastList(CaEmissionForecast admEmsCaEmissionForecast);
+    List<CaEmissionForecast> selectCaEmissionForecastList(CaEmissionForecast caEmissionForecast);
 
     /**
      * 新增碳排放预测
      *
-     * @param admEmsCaEmissionForecast 碳排放预测
+     * @param caEmissionForecast 碳排放预测
      * @return 结果
      */
-    int insertCaEmissionForecast(CaEmissionForecast admEmsCaEmissionForecast);
+    int insertCaEmissionForecast(CaEmissionForecast caEmissionForecast);
 
     /**
      * 修改碳排放预测
      *
-     * @param admEmsCaEmissionForecast 碳排放预测
+     * @param caEmissionForecast 碳排放预测
      * @return 结果
      */
-    int updateCaEmissionForecast(CaEmissionForecast admEmsCaEmissionForecast);
+    int updateCaEmissionForecast(CaEmissionForecast caEmissionForecast);
+
+    int deleteCaMeterDByArea(@Param("areaCode") String areaCode, @Param("month") String date);
 
     /**
      * 删除碳排放预测

+ 83 - 15
ems/ems-core/src/main/java/com/ruoyi/ems/service/analysis/CarbonCalculationService.java

@@ -10,14 +10,14 @@
  */
 package com.ruoyi.ems.service.analysis;
 
+import com.ruoyi.ems.domain.CaEmissionForecast;
 import com.ruoyi.ems.domain.CaMeterD;
 import com.ruoyi.ems.domain.ElecPgSupplyH;
 import com.ruoyi.ems.domain.ElecPvSupplyH;
 import com.ruoyi.ems.domain.EmissionFactor;
-import com.ruoyi.ems.domain.EnergyMeter;
+import com.ruoyi.ems.mapper.CaEmissionForecastMapper;
 import com.ruoyi.ems.mapper.CaMeterDMapper;
 import com.ruoyi.ems.model.QueryMeter;
-import com.ruoyi.ems.service.IElecMeterHService;
 import com.ruoyi.ems.service.IElecPgSupplyHService;
 import com.ruoyi.ems.service.IElecPvSupplyHService;
 import com.ruoyi.ems.service.IEmissionFactorService;
@@ -31,8 +31,12 @@ import java.math.RoundingMode;
 import java.time.LocalDate;
 import java.time.ZoneId;
 import java.time.format.DateTimeFormatter;
+import java.time.temporal.TemporalAdjusters;
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 /**
  * 碳计算任务
@@ -49,10 +53,22 @@ public class CarbonCalculationService {
 
     private final DateTimeFormatter dateForm = DateTimeFormatter.ofPattern("yyyy-MM-dd");
 
+    private final DateTimeFormatter monthForm = DateTimeFormatter.ofPattern("yyyy-MM");
+
+    // 历史数据权重配置
+    private static final double WEIGHT_CURRENT_MONTH = 0.5;  // 最近一个月权重
+
+    private static final double WEIGHT_PREVIOUS_MONTH = 0.3; // 前一个月权重
+
+    private static final double WEIGHT_OLDEST_MONTH = 0.2;   // 最早一个月权重
+
     @Resource
     private CaMeterDMapper caMeterDMapper;
 
     @Resource
+    private CaEmissionForecastMapper caEmissionForecastMapper;
+
+    @Resource
     private IElecPgSupplyHService pgSupplyHService;
 
     @Resource
@@ -76,7 +92,7 @@ public class CarbonCalculationService {
 
             // 计算碳排放量(基于电网用电数据)
             ElecPgSupplyH totalElectricity = getDailyElectricityConsumption(areaCode, date);
-            Double emission = calculateCarbonEmission(totalElectricity);
+            Double emission = calculateCarbonEmission(totalElectricity != null ? totalElectricity.getUseElecQuantity() : null);
             caMeterD.setCaEmissionQuantity(emission);
 
             // 计算碳汇量(基于光伏产能数据)
@@ -93,6 +109,28 @@ public class CarbonCalculationService {
         }
     }
 
+    public void calculateMonthCarbonForecast(String areaCode, LocalDate date) {
+        try {
+            List<ElecPgSupplyH> totalElectricitys = getMonthElectricityConsumption(areaCode, date);
+            Map<String, Double> monthElectricityMap = totalElectricitys.stream()
+                .collect(Collectors.toMap(ElecPgSupplyH::getStartRecTime, ElecPgSupplyH::getUseElecQuantity));
+            Double totalElectricity = calculateForecastElectricity(monthElectricityMap);
+            Double emission = calculateCarbonEmission(totalElectricity);
+
+            CaEmissionForecast caEmissionForecast = new CaEmissionForecast();
+            caEmissionForecast.setAreaCode(areaCode);
+            caEmissionForecast.setMonth(date.format(monthForm));
+            caEmissionForecast.setCaEmission(emission);
+
+            caEmissionForecastMapper.deleteCaMeterDByArea(areaCode, date.format(monthForm));
+            caEmissionForecastMapper.insertCaEmissionForecast(caEmissionForecast);
+        }
+        catch (Exception e) {
+            log.error("calculate month carbon forecast error! areaCode:{}, date:{}", areaCode, date.format(dateForm),
+                e);
+        }
+    }
+
     private ElecPvSupplyH getDailyPVProduction(String areaCode, LocalDate date) {
         QueryMeter queryMeter = new QueryMeter();
         queryMeter.setAreaCode(areaCode);
@@ -108,29 +146,33 @@ public class CarbonCalculationService {
         return pgSupplyHService.calDaySupplyByH(queryMeter);
     }
 
+    private List<ElecPgSupplyH> getMonthElectricityConsumption(String areaCode, LocalDate date) {
+        LocalDate startTime = date.minusMonths(3).withDayOfMonth(1);
+        LocalDate endTime = date.minusMonths(1).with(TemporalAdjusters.lastDayOfMonth());
+
+        ElecPgSupplyH queryMeter = new ElecPgSupplyH();
+        queryMeter.setAreaCode(areaCode);
+        queryMeter.setStartRecTime(startTime.format(dateForm));
+        queryMeter.setEndRecTime(endTime.format(dateForm));
+        return pgSupplyHService.calMonthSupplyByH(queryMeter);
+    }
+
     // 计算碳排放量
-    private Double calculateCarbonEmission(ElecPgSupplyH totalElectricity) {
+    private Double calculateCarbonEmission(Double useElecQuantity) {
         EmissionFactor factor = emissionFactorService.selectByRegion("CN", 1);
 
-        if (null == factor || factor.getFactorValue() == null) {
+        if (null == factor || useElecQuantity == null || factor.getFactorValue() == null) {
             return null;
         }
 
-        if (totalElectricity == null || totalElectricity.getUseElecQuantity() == null) {
-            return null;
-        }
-
-        return round(totalElectricity.getUseElecQuantity() * factor.getFactorValue(), 2);
+        return round(useElecQuantity * factor.getFactorValue(), 2);
     }
 
     private Double calculateCarbonSink(ElecPvSupplyH totalPVProduction) {
         EmissionFactor factor = emissionFactorService.selectByRegion("CN", 4);
 
-        if (null == factor || factor.getFactorValue() == null) {
-            return null;
-        }
-
-        if (totalPVProduction == null || totalPVProduction.getGenElecQuantity() == null) {
+        if (null == factor || totalPVProduction == null || factor.getFactorValue() == null
+            || totalPVProduction.getGenElecQuantity() == null) {
             return null;
         }
 
@@ -145,4 +187,30 @@ public class CarbonCalculationService {
         bd = bd.setScale(scale, RoundingMode.HALF_UP);
         return bd.doubleValue();
     }
+
+    // 计算预测电网购电量
+    private double calculateForecastElectricity(Map<String, Double> historicalData) {
+        // 按月份排序(从近到远)
+        List<Map.Entry<String, Double>> sortedData = historicalData.entrySet().stream()
+            .sorted(Map.Entry.<String, Double>comparingByKey().reversed()).collect(Collectors.toList());
+
+        double forecast = 0.0;
+
+        // 加权平均计算
+        if (sortedData.size() >= 3) {
+            forecast = sortedData.get(0).getValue() * WEIGHT_CURRENT_MONTH
+                + sortedData.get(1).getValue() * WEIGHT_PREVIOUS_MONTH
+                + sortedData.get(2).getValue() * WEIGHT_OLDEST_MONTH;
+        }
+        else if (sortedData.size() == 2) {
+            // 如果只有两个月数据,平均分配权重
+            forecast = sortedData.get(0).getValue() * 0.6 + sortedData.get(1).getValue() * 0.4;
+        }
+        else if (sortedData.size() == 1) {
+            // 如果只有一个月数据,直接使用
+            forecast = sortedData.get(0).getValue();
+        }
+
+        return forecast;
+    }
 }

+ 6 - 6
ems/ems-core/src/main/java/com/ruoyi/ems/service/analysis/ElecProdForecastService.java

@@ -74,12 +74,12 @@ public class ElecProdForecastService {
         weatherFactorMap.put("1103", 0.8);   // 多云
         weatherFactorMap.put("1106", 0.4);   // 阴天
         weatherFactorMap.put("2100", 0.5);   // 雨
-        weatherFactorMap.put("2101", 0.6);   // 小雨
-        weatherFactorMap.put("2102", 0.5);   // 中雨
-        weatherFactorMap.put("2103", 0.4);   // 大雨
-        weatherFactorMap.put("2104", 0.3);   // 暴雨
-        weatherFactorMap.put("2111", 0.7);   // 阵雨
-        weatherFactorMap.put("2121", 0.7);   // 雷阵雨
+        weatherFactorMap.put("2101", 0.4);   // 小雨
+        weatherFactorMap.put("2102", 0.4);   // 中雨
+        weatherFactorMap.put("2103", 0.5);   // 大雨
+        weatherFactorMap.put("2104", 0.6);   // 暴雨
+        weatherFactorMap.put("2111", 0.8);   // 阵雨
+        weatherFactorMap.put("2121", 0.8);   // 雷阵雨
         weatherFactorMap.put("2200", 0.3);   // 雪
         weatherFactorMap.put("2201", 0.3);   // 小雪
         weatherFactorMap.put("2202", 0.3);   // 中雪

+ 9 - 9
ems/ems-core/src/main/java/com/ruoyi/ems/service/impl/CaEmissionForecastServiceImpl.java

@@ -33,34 +33,34 @@ public class CaEmissionForecastServiceImpl implements ICaEmissionForecastService
     /**
      * 查询碳排放预测列表
      *
-     * @param admEmsCaEmissionForecast 碳排放预测
+     * @param caEmissionForecast 碳排放预测
      * @return 碳排放预测
      */
     @Override
-    public List<CaEmissionForecast> selectCaEmissionForecastList(CaEmissionForecast admEmsCaEmissionForecast) {
-        return caEmissionForecastMapper.selectCaEmissionForecastList(admEmsCaEmissionForecast);
+    public List<CaEmissionForecast> selectCaEmissionForecastList(CaEmissionForecast caEmissionForecast) {
+        return caEmissionForecastMapper.selectCaEmissionForecastList(caEmissionForecast);
     }
 
     /**
      * 新增碳排放预测
      *
-     * @param admEmsCaEmissionForecast 碳排放预测
+     * @param caEmissionForecast 碳排放预测
      * @return 结果
      */
     @Override
-    public int insertCaEmissionForecast(CaEmissionForecast admEmsCaEmissionForecast) {
-        return caEmissionForecastMapper.insertCaEmissionForecast(admEmsCaEmissionForecast);
+    public int insertCaEmissionForecast(CaEmissionForecast caEmissionForecast) {
+        return caEmissionForecastMapper.insertCaEmissionForecast(caEmissionForecast);
     }
 
     /**
      * 修改碳排放预测
      *
-     * @param admEmsCaEmissionForecast 碳排放预测
+     * @param caEmissionForecast 碳排放预测
      * @return 结果
      */
     @Override
-    public int updateCaEmissionForecast(CaEmissionForecast admEmsCaEmissionForecast) {
-        return caEmissionForecastMapper.updateCaEmissionForecast(admEmsCaEmissionForecast);
+    public int updateCaEmissionForecast(CaEmissionForecast caEmissionForecast) {
+        return caEmissionForecastMapper.updateCaEmissionForecast(caEmissionForecast);
     }
 
     /**

+ 12 - 8
ems/ems-core/src/main/resources/mapper/ems/CaEmissionForecastMapper.xml

@@ -7,24 +7,24 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     <resultMap type="com.ruoyi.ems.domain.CaEmissionForecast" id="CaEmissionForecastResult">
         <result property="id"    column="id"    />
         <result property="areaCode"    column="area_code"    />
-        <result property="date"    column="date"    />
+        <result property="month"    column="month"    />
         <result property="caEmission"    column="ca_emission"    />
     </resultMap>
 
     <sql id="selectCaEmissionForecastVo">
-        select id, area_code, date, ca_emission from adm_ems_ca_emission_forecast
+        select id, area_code, month, ca_emission from adm_ems_ca_emission_forecast
     </sql>
 
     <select id="selectCaEmissionForecastList" parameterType="com.ruoyi.ems.domain.CaEmissionForecast" resultMap="CaEmissionForecastResult">
-        select d.id, d.area_code,area.area_name, date, ca_emission from adm_ems_ca_emission_forecast d
+        select d.id, d.area_code,area.area_name, month, ca_emission from adm_ems_ca_emission_forecast d
         inner join adm_area area on area.area_code = d.area_code
         <where>
             <if test="areaCode != null and areaCode != '' and areaCode !='-1'">and d.area_code = #{areaCode}</if>
             <if test="startRecTime != null and startRecTime != '' ">
-                and d.`date` &gt;= #{startRecTime}
+                and d.`month` &gt;= #{startRecTime}
             </if>
             <if test="endRecTime != null and endRecTime !=''">
-                and d.`date` &lt;= #{endRecTime}
+                and d.`month` &lt;= #{endRecTime}
             </if>
         </where>
     </select>
@@ -38,12 +38,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         insert into adm_ems_ca_emission_forecast
         <trim prefix="(" suffix=")" suffixOverrides=",">
             <if test="areaCode != null and areaCode != ''">area_code,</if>
-            <if test="date != null">date,</if>
+            <if test="month != null">month,</if>
             <if test="caEmission != null">ca_emission,</if>
          </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="areaCode != null and areaCode != ''">#{areaCode},</if>
-            <if test="date != null">#{date},</if>
+            <if test="month != null">#{month},</if>
             <if test="caEmission != null">#{caEmission},</if>
          </trim>
     </insert>
@@ -52,12 +52,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         update adm_ems_ca_emission_forecast
         <trim prefix="SET" suffixOverrides=",">
             <if test="areaCode != null and areaCode != ''">area_code = #{areaCode},</if>
-            <if test="date != null">date = #{date},</if>
+            <if test="month != null">month = #{month},</if>
             <if test="caEmission != null">ca_emission = #{caEmission},</if>
         </trim>
         where id = #{id}
     </update>
 
+    <delete id="deleteCaMeterDByArea" >
+        delete from adm_ems_ca_emission_forecast where area_code = #{areaCode} and month = #{month}
+    </delete>
+
     <delete id="deleteCaEmissionForecastById" parameterType="Long">
         delete from adm_ems_ca_emission_forecast where id = #{id}
     </delete>

+ 2 - 2
ems/ems-core/src/main/resources/mapper/ems/ElecPgSupplyHMapper.xml

@@ -129,8 +129,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         FROM
         adm_ems_pg_supply_h pg
         <where>
-            <if test="startRecTime != null and startRecTime != ''">and DATE >=#{startRecTime}</if>
-            <if test="endRecTime != null and endRecTime != ''">and DATE <![CDATA[ <= ]]>#{endRecTime}</if>
+            <if test="startRecTime != null and startRecTime != ''">and `date` &gt;= #{startRecTime}</if>
+            <if test="endRecTime != null and endRecTime != ''">and `date` &lt;= #{endRecTime}</if>
             <if test="areaCode != null and areaCode != '' and areaCode != '-1'">
                 and pg.area_code = #{areaCode}
             </if>

+ 2 - 2
ems/sql/ems_server.sql

@@ -1481,8 +1481,8 @@ drop table if exists adm_ems_ca_emission_forecast;
 create table adm_ems_ca_emission_forecast (
   `id`                        bigint(20)      not null auto_increment      comment '序号',
   `area_code`                 varchar(32)     not null                     comment '园区代码',
-  `date`                      date            not null                     comment '日期 yyyy-MM-dd',
+  `month`                     varchar(16)     not null                     comment '日期 yyyy-MM',
   `ca_emission`               double          default null                 comment '单位:kg(千克)',
   primary key (`id`),
-  unique key ux_ems_ca_emission_forecast(`area_code`, `date`)
+  unique key ux_ems_ca_emission_forecast(`area_code`, `month`)
 ) engine=innodb auto_increment=1 comment = '碳排放预测表';