wangb 2 ماه پیش
والد
کامیت
62e5310855
1فایلهای تغییر یافته به همراه719 افزوده شده و 0 حذف شده
  1. 719 0
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/JavaFunctionJobHandler.java

+ 719 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/controller/JavaFunctionJobHandler.java

@@ -10,6 +10,7 @@ import cn.hutool.core.util.NumberUtil;
 import cn.hutool.core.util.RandomUtil;
 import cn.hutool.core.util.StrUtil;
 import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.TypeReference;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.ruoyi.quartz.handler.IJobHandler;
@@ -107,6 +108,11 @@ public class JavaFunctionJobHandler extends IJobHandler {
     private ServiceGroup serviceGroup;
     @Resource
     private IProBasicModelPowerRdService proBasicModelPowerRdService;
+    @Resource
+    private IKkxfxService kkxfxService;
+
+    @Resource
+    private IProEconEquipmentInfoDay5Service proEconEquipmentInfoDay5Service ;
 
     @Override
     public void execute() throws Exception {
@@ -9908,4 +9914,717 @@ public class JavaFunctionJobHandler extends IJobHandler {
     public Map<String, Map<String, PointInfo>> pointInfos2MapMap2(List<PointInfo> infos) {
         return infos.stream().collect(Collectors.groupingBy(PointInfo::getStationId, Collectors.toMap(PointInfo::getTurbineId, Function.identity())));
     }
+
+    public void calcTurbineScoreLevels(DateTime begin) {
+        //获取当天风机表
+        List<TurbineInfoDay> byDate = getTurbineinfoByDate(begin);
+
+        for (TurbineInfoDay info : byDate) {
+            calScoreLevels(info);
+        }
+        turbineInfoDayService.saveOrUpdateBatch(byDate);
+    }
+
+
+    private void calScoreLevels(TurbineInfoDay top) {
+        double m = 10;
+        double n = 9.1;
+
+        //切入风速
+        double xfqrValue = 0;
+        //性能损失电量
+        double xnssdlValue = 0;
+        //拟合优度
+//        double nhydValue = 0;
+        //功率一致性系数
+//        double glyzxxsValue = 0;
+        //利用小时
+        double lyxsValue = 0;
+        //设备可利用率
+        double sbklylValue = 0;
+        //等效可利用系数
+//        double dxkyxsValue = 0;
+        //有效风时数
+        double yxfssValue = 0;
+        //风速
+        double fsValue = 0;
+        //静风频率
+        double jfplValue = 0;
+
+        //切入风速
+        double value = (null != top.getXfqrfs()) ? top.getXfqrfs() : 0.0;
+
+        if (value < 2.5) {
+            // 过低的风速可能导致启动困难
+            xfqrValue = 7.0 + (value - 2.0) * 0.6; // 2.0-2.5m/s线性评分
+        } else if (value <= 3.5) {
+            // 最佳范围:3.0-3.5m/s
+            xfqrValue = 9.5 + (value - 3.0) * 0.5; // 3.0m/s得9.5分,3.5m/s得10分
+        } else if (value <= 4.5) {
+            // 可接受范围:3.5-4.5m/s
+            xfqrValue = 10 - (value - 3.5) * 2; // 每增加0.1m/s扣0.2分
+        } else if (value <= 5.5) {
+            // 临界范围:4.5-5.5m/s
+            xfqrValue = 8 - (value - 4.5) * 4; // 每增加0.1m/s扣0.4分
+        } else {
+            // 过高,严重影响性能
+            xfqrValue = 0;
+        }
+        // 确保分数在0-10之间
+        xfqrValue = Math.max(0, Math.min(10, xfqrValue));
+
+        //性能损失电量
+        double actualLoss = (null != top.getXnss()) ? top.getXnss() : 0.0;
+        double rfdl = (null != top.getRfdl()) ? top.getRfdl() : 0.0; // 预期损失电量
+        if (rfdl <= 0) {
+            // 如果没有预期损失值或预期值无效,使用默认评分
+            xnssdlValue = (actualLoss <= 0) ? m : n;
+        } else {
+            double lossRatio = (rfdl > 0) ? (actualLoss / rfdl) : 0.0;
+            if (lossRatio <= 0) {
+                // 无损失或负损失(异常情况),得满分
+                xnssdlValue = m;
+            } else if (lossRatio <= 0.5) {
+                // 损失在预期50%以内,优秀
+                xnssdlValue = 9.5 + (0.5 - lossRatio); // 9.5-10分
+            } else if (lossRatio <= 1.0) {
+                // 损失在预期50%-100%之间,良好
+                xnssdlValue = 8.0 + (1.0 - lossRatio) * 3.0; // 8.0-9.5分
+            } else if (lossRatio <= 1.5) {
+                // 损失超过预期但不超过150%,及格
+                xnssdlValue = 6.0 + (1.5 - lossRatio) * 4.0; // 6.0-8.0分
+            } else if (lossRatio <= 2.0) {
+                // 损失在预期150%-200%之间,较差
+                xnssdlValue = 4.0 + (2.0 - lossRatio) * 4.0; // 4.0-6.0分
+            } else {
+                // 损失超过预期200%,很差
+                xnssdlValue = Math.max(0, 4.0 - (lossRatio - 2.0) * 2.0); // 0-4分
+            }
+            // 确保分数在0-10之间
+            xnssdlValue = Math.max(0, Math.min(10, xnssdlValue));
+        }
+
+//        value = 0.0;
+//        value = top.getDaynhyd();
+//        //拟合优度
+//        if (value <= 15) {
+//            nhydValue = 0;
+//        } else if (value >= 80) {
+//            nhydValue = m;
+//        } else {
+//            temp = d * (size - top.getMonthnhyd());
+//            nhydValue = StringUtils.round(temp, 0);
+//            top.setYearnhyd(nhydValue);
+//        }
+
+        //功率一致性系数
+//        value = 0.0;
+//        value = top.getDayglyzxxs();
+//
+//        if (value <= 15) {
+//            glyzxxsValue = 0;
+//        } else if (value >= 80) {
+//            glyzxxsValue = m;
+//        } else {
+//            temp = d * (size - top.getMonthglyzxxs());
+//            glyzxxsValue = StringUtils.round(temp, 0);
+//            top.setYearglyzxxs(glyzxxsValue);
+//        }
+
+        //利用小时
+        value = (null != top.getLyxs()) ? top.getLyxs() : 0.0;
+        // 根据风能行业标准划分利用小时等级
+        // 一天理论最大利用小时为24小时,但风机实际最大约18-20小时(考虑停机维护)
+        double maxLyxs = 24.0; // 日理论最大利用小时
+        if (value <= 0 || 24 < value) {
+            lyxsValue = 0; // 异常情况
+        } else if (value < 6) {
+            lyxsValue = 2.0 * (value / 6); // 2-5分
+        } else if (value < 18) {
+            lyxsValue = 5.0 + 3.0 * ((value - 6) / 6); // 5-8分
+        } else if (value <= maxLyxs) {
+            lyxsValue = 9.5 + 0.5 * ((value - 18) / 3); // 9.5-10分
+        }
+        // 确保分数在0-10之间
+        lyxsValue = Math.max(0, Math.min(10, lyxsValue));
+
+
+        //设备可利用率
+        value = (null != top.getKlyl()) ? top.getKlyl() : 0.0;
+        if (value < 85) {
+            // 极差:低于85%
+            sbklylValue = 0;
+        } else if (value < 90) {
+            // 较差:85%-90%
+            sbklylValue = 2.0 + 3.0 * ((value - 85) / 5); // 2-5分
+        } else if (value < 95) {
+            // 一般:90%-95%
+            sbklylValue = 5.0 + 2.0 * ((value - 90) / 5); // 5-7分
+        } else if (value < 97) {
+            // 良好:95%-97%
+            sbklylValue = 7.0 + 1.5 * ((value - 95) / 2); // 7-8.5分
+        } else if (value < 98.5) {
+            // 优秀:97%-98.5%
+            sbklylValue = 8.5 + ((value - 97) / 1.5); // 8.5-9.5分
+        } else if (value < 99.5) {
+            // 卓越:98.5%-99.5%
+            sbklylValue = 9.5 + 0.3 * ((value - 98.5)); // 9.5-9.8分
+        } else {
+            // 完美:99.5%以上
+            sbklylValue = 9.8 + 0.2 * Math.min(1, (value - 99.5) / 0.5); // 9.8-10分
+        }
+        // 确保分数在0-10之间
+        sbklylValue = Math.max(0, Math.min(10, sbklylValue));
+
+
+        //等效可用系数
+//        value = 0.0;
+//        value = top.getDaydxkyxs();
+//
+//        if (value < 90) {
+//            dxkyxsValue = 0;
+//        } else if (value >= 99.8) {
+//            dxkyxsValue = m;
+//        } else {
+//            temp = d * (size - top.getMonthdxkyxs());
+//            dxkyxsValue = StringUtils.round(temp, 0);
+//            top.setYeardxkyxs(dxkyxsValue);
+//        }
+
+        //有效风时数
+        value = (null != top.getYxfss()) ? top.getYxfss() : 0.0;
+        // 一天最大可能有效风时数约为18-20小时(考虑切入切出风速限制)
+        double maxYxfss = 18.0;
+        if (value <= 0) {
+            yxfssValue = 0; // 异常情况
+        } else if (value < 6) {
+            // 极差:低于6小时(利用率<33%)
+            yxfssValue = 2.0 * (value / 6); // 0-2分
+        } else if (value < 10) {
+            // 较差:6-10小时(利用率33%-56%)
+            yxfssValue = 2.0 + 2.0 * ((value - 6) / 4); // 2-4分
+        } else if (value < 14) {
+            // 一般:10-14小时(利用率56%-78%)
+            yxfssValue = 4.0 + 2.0 * ((value - 10) / 4); // 4-6分
+        } else if (value < 16) {
+            // 良好:14-16小时(利用率78%-89%)
+            yxfssValue = 6.0 + 2.0 * ((value - 14) / 2); // 6-8分
+        } else if (value < maxYxfss) {
+            // 优秀:16-18小时(利用率89%-100%)
+            yxfssValue = 8.0 + 1.5 * ((value - 16) / 2); // 8-9.5分
+        } else {
+            // 异常优秀:超过理论最大值
+            yxfssValue = 9.5; // 给予高分但标记为异常
+        }
+        // 确保分数在0-10之间
+        yxfssValue = Math.max(0, Math.min(10, yxfssValue));
+
+
+        //平均风速
+        value = (null != top.getPjfs()) ? top.getPjfs() : 0.0;
+        if (value <= 0 || 25 <= value) {
+            fsValue = 0;
+        } else if (2 <= value || value <= 18) {
+            fsValue = m;
+        } else {
+            fsValue = n;
+        }
+
+        //静风频率
+        value = (null != top.getJfpl()) ? top.getJfpl() * 100 : 0.0;
+        if (value <= 0 || 100 < value) {
+            jfplValue = 0;
+        } else if (value <= value) {
+            jfplValue = m;
+        } else {
+            jfplValue = n;
+        }
+
+        double total = xfqrValue + xnssdlValue + lyxsValue + sbklylValue + yxfssValue + fsValue + jfplValue;
+
+        if (total >= 67) {
+            top.setLevel("AAA");
+        } else if (total >= 60) {
+            top.setLevel("AA");
+        } else if (total >= 56) {
+            top.setLevel("A");
+        } else if (total >= 53) {
+            top.setLevel("BBB");
+        } else if (total >= 46) {
+            top.setLevel("BB");
+        } else if (total >= 42) {
+            top.setLevel("B");
+            top.setScore(total);
+        } else if (total >= 28) {
+            top.setLevel("C");
+        } else {
+            top.setLevel("C-");
+        }
+        top.setScore(total);
+    }
+
+
+    public void calcPowerConsistencyCoefficient(DateTime begin, DateTime end) {
+        Map<String, Map<Double, ProBasicModelPowerRd>> modelSpeedMap = cacheModelPower();
+
+        QueryWrapper<TurbineInfoMin> qw = new QueryWrapper<>();
+        qw.between("record_date", begin, end);
+        List<TurbineInfoMin> turMins = turbineInfoMinService.list(qw);
+        Map<String, List<TurbineInfoMin>> wtMap = turMins.stream().collect(Collectors.groupingBy(TurbineInfoMin::getTurbineId));
+
+        //获取 保证功率
+        List<ProBasicModelPowerRd> modelPowerRds = proBasicModelPowerRdService.list();
+        //保证功率 按照机型分组
+        Map<String, List<ProBasicModelPowerRd>> modelMap = modelPowerRds.stream().collect(Collectors.groupingBy(ProBasicModelPowerRd::getModelId));
+
+        Map<Double, ProBasicModelPowerRd> bzglMap = new HashMap<>();
+
+        //风机编号,风速,功率
+        Map<String, Double> glyzxxsMap = new HashMap<>();
+        for (Map.Entry<String, List<TurbineInfoMin>> entry : wtMap.entrySet()) {
+            String key = entry.getKey();
+            List<TurbineInfoMin> value = entry.getValue();
+            List<Double> ls = new ArrayList<>();
+            //单台风机 根据风速分组-风机表
+            Map<Double, List<TurbineInfoMin>> fsMap = value.stream().filter(fs -> null != fs.getPjfs()).collect(Collectors.groupingBy(fs -> NumberUtil.round(fs.getPjfs(), 2).doubleValue()));
+
+            //根据风速将 功率求平均值
+            for (Map.Entry<Double, List<TurbineInfoMin>> ent : fsMap.entrySet()) {
+                Double k = ent.getKey();
+                List<TurbineInfoMin> val = ent.getValue();
+                double gl = 0.0;
+                if (val.size() > 1) {
+                    DoubleSummaryStatistics glAvg = val.stream().filter(glA -> null != glA.getPjgl()).mapToDouble(TurbineInfoMin::getPjgl).summaryStatistics();
+                    gl = glAvg.getAverage();
+                } else {
+                    gl = val.get(0).getPjgl();
+                }
+
+                //计算 功率一致性系数
+                double glyzxxs = 0.0;
+                if (gl != 0) {
+                    if (modelSpeedMap.containsKey(val.get(0).getProjectId())) {
+                        bzglMap = modelSpeedMap.get(val.get(0).getProjectId());
+                    }
+                    if (bzglMap.containsKey(k)) {
+                        double bzgl = bzglMap.get(k).getEnsurePower();
+                        if (bzgl != 0) {
+                            glyzxxs = (gl / bzgl) * 100;
+                            if (glyzxxs > 80 && glyzxxs < 120) {
+                                ls.add(glyzxxs);
+                            }
+                        }
+                    }
+                }
+            }
+            if (ls.isEmpty()) {
+                glyzxxsMap.put(key, 0.0);
+            } else {
+                ls.stream().mapToDouble(Double::doubleValue).average().ifPresent(avg -> glyzxxsMap.put(key, avg));
+            }
+        }
+
+        //获取当天风机表
+        List<TurbineInfoDay> byDate = getTurbineinfoByDate(begin);
+        for (TurbineInfoDay info : byDate) {
+            if (glyzxxsMap.containsKey(info.getTurbineId())) {
+                double glyzxxs = glyzxxsMap.get(info.getTurbineId());
+                if (glyzxxs > 100) {
+                    glyzxxs = 100;
+                } else if (glyzxxs < 90 && glyzxxs != 0.0) {
+                    glyzxxs = 90;
+                } else if (glyzxxs == 0.0) {
+                    glyzxxs = 0.0;
+                }
+                info.setGlyzxxs(NumberUtil.round(glyzxxs, 2).doubleValue());
+            } else {
+                info.setGlyzxxs(0.0);
+            }
+        }
+        turbineInfoDayService.saveOrUpdateBatch(byDate);
+    }
+
+
+    public void calcStateConversionRate(DateTime begin, DateTime end) {
+
+        Map<Double, Double> stateDescription1 = new HashMap<>();
+        Map<Double, Double> stateDescription2 = new HashMap<>();
+
+        stateDescription1.put(3.0, 6.0);  // 6 检修
+        stateDescription1.put(3.5, 0.0);  // 0 待机
+        stateDescription1.put(4.0, 0.0);
+        stateDescription2.put(3.0, 6.0);
+        stateDescription2.put(3.5, 2.0);  // 2 正常发电
+        stateDescription2.put(4.0, 2.0);
+
+        List<PointData> speedDataList = null;
+        List<PointData> statusDataList = null;
+
+        List<ProEconEquipmentInfoDay5> rates = new ArrayList<>();
+
+        List<PointInfo> entityFs = getEntity("AI066", "turbine");
+        getSnapDataByEntity(entityFs, begin, end, 60);
+        speedDataList = entityFs.get(0).getPointDatas();
+
+        List<PointInfo> entityZt = getEntity("MXZT", "turbine");
+        getSnapDataByEntity(entityZt, begin, end, 60);
+        statusDataList = entityZt.get(0).getPointDatas();
+
+        if (speedDataList != null && statusDataList != null && (statusDataList.size() - speedDataList.size() < 3) && !speedDataList.isEmpty()) {
+
+            for (PointInfo entity : entityFs) {
+
+                ProEconEquipmentInfoDay5 rate = new ProEconEquipmentInfoDay5();
+                proEconEquipmentInfoDay5Service.initial(rate);
+                rate.setWindturbineId(entity.getTurbineId());
+                rate.setWindpowerstationId(entity.getStationId());
+                double laststatus = -1;
+                Date begin2 = new Date();
+                int q = speedDataList.size() - statusDataList.size() > 0 ? statusDataList.size() : speedDataList.size();
+
+                for (int i = 0; i < q; i++) {
+
+                    double status = statusDataList.get(i).getDoubleValue();
+                    double speed = speedDataList.get(i).getDoubleValue();
+                    if (i == 0) {
+                        begin2 = new Date(speedDataList.get(i).getTs());
+                        laststatus = status;
+                    }
+
+                    if (speed <= 3.0) {
+                        if (laststatus != status && (status == stateDescription1.get(3.0) || status == stateDescription2.get(3.0))) {
+
+                            Date end2 = new Date(speedDataList.get(i).getTs());
+                            double zhcs = DateUtil.between(begin2, end2, DateUnit.MINUTE, true);
+                            if (zhcs <= 5)//5分钟
+                            {
+                                double temp = rate.getTimerate1();
+                                temp = temp + 1;
+                                rate.setTimerate1(temp);
+
+                                temp = rate.getTimerate2();
+                                temp = temp + 1;
+                                rate.setTimerate2(temp);
+
+                                temp = rate.getTimerate3();
+                                temp = temp + 1;
+                                rate.setTimerate3(temp);
+
+                                temp = rate.getTimerate4();
+                                temp = temp + 1;
+                                rate.setTimerate4(temp);
+
+                            } else if (zhcs <= 10)//10分钟
+                            {
+                                double temp = rate.getTimerate2();
+                                temp = temp + 1;
+                                rate.setTimerate2(temp);
+
+                                temp = rate.getTimerate3();
+                                temp = temp + 1;
+                                rate.setTimerate3(temp);
+
+                                temp = rate.getTimerate4();
+                                temp = temp + 1;
+                                rate.setTimerate4(temp);
+                            } else if (zhcs <= 15)//15分钟
+                            {
+                                double temp = rate.getTimerate3();
+                                temp = temp + 1;
+                                rate.setTimerate3(temp);
+
+                                temp = rate.getTimerate4();
+                                temp = temp + 1;
+                                rate.setTimerate4(temp);
+                            } else if (zhcs <= 20)//20分钟
+                            {
+                                double temp = rate.getTimerate4();
+                                temp = temp + 1;
+                                rate.setTimerate4(temp);
+                            }
+
+                            double temp = rate.getTimerate13();
+                            temp = temp + 1;
+                            rate.setTimerate13(temp);
+                        }
+
+                        laststatus = status;
+                        begin2 = new Date(speedDataList.get(i).getTs());
+                    } else if (speed <= 4.0) {
+                        if (laststatus != status && (status == stateDescription1.get(3.5) || status == stateDescription2.get(3.5))) {
+                            Date end2 = new Date(speedDataList.get(i).getTs());
+                            double zhcs = DateUtil.between(begin2, end2, DateUnit.MINUTE, true);
+                            if (zhcs <= 5)//5分钟
+                            {
+                                double temp = rate.getTimerate5();
+                                temp = temp + 1;
+                                rate.setTimerate5(temp);
+
+                                temp = rate.getTimerate6();
+                                temp = temp + 1;
+                                rate.setTimerate6(temp);
+
+                                temp = rate.getTimerate7();
+                                temp = temp + 1;
+                                rate.setTimerate7(temp);
+
+                                temp = rate.getTimerate8();
+                                temp = temp + 1;
+                                rate.setTimerate8(temp);
+                            } else if (zhcs <= 10)//10分钟
+                            {
+                                double temp = rate.getTimerate6();
+                                temp = temp + 1;
+                                rate.setTimerate6(temp);
+
+                                temp = rate.getTimerate7();
+                                temp = temp + 1;
+                                rate.setTimerate7(temp);
+
+                                temp = rate.getTimerate8();
+                                temp = temp + 1;
+                                rate.setTimerate8(temp);
+                            } else if (zhcs <= 15)//15分钟
+                            {
+                                double temp = rate.getTimerate7();
+                                temp = temp + 1;
+                                rate.setTimerate7(temp);
+
+                                temp = rate.getTimerate8();
+                                temp = temp + 1;
+                                rate.setTimerate8(temp);
+
+                            } else if (zhcs <= 20)//20分钟
+                            {
+                                double temp = rate.getTimerate8();
+                                temp = temp + 1;
+                                rate.setTimerate8(temp);
+                            }
+
+                            //}
+                            double temp = rate.getTimerate14();
+                            temp = temp + 1;
+                            rate.setTimerate14(temp);
+
+                        }
+
+                        laststatus = status;
+                        begin2 = new Date(speedDataList.get(i).getTs());
+                    } else {
+                        if (laststatus != status && (status == stateDescription1.get(4.0) || status == stateDescription2.get(4.0))) {
+
+                            Date end2 = new Date(speedDataList.get(i).getTs());
+                            double zhcs = DateUtil.between(begin2, end2, DateUnit.MINUTE, true);
+                            if (zhcs <= 5)//5分钟
+                            {
+                                double temp = rate.getTimerate9();
+                                temp = temp + 1;
+                                rate.setTimerate9(temp);
+
+                                temp = rate.getTimerate10();
+                                temp = temp + 1;
+                                rate.setTimerate10(temp);
+
+                                temp = rate.getTimerate11();
+                                temp = temp + 1;
+                                rate.setTimerate11(temp);
+
+                                temp = rate.getTimerate12();
+                                temp = temp + 1;
+                                rate.setTimerate12(temp);
+                            } else if (zhcs <= 10)//10分钟
+                            {
+                                double temp = rate.getTimerate10();
+                                temp = temp + 1;
+                                rate.setTimerate10(temp);
+
+                                temp = rate.getTimerate11();
+                                temp = temp + 1;
+                                rate.setTimerate11(temp);
+
+                                temp = rate.getTimerate12();
+                                temp = temp + 1;
+                                rate.setTimerate12(temp);
+                            } else if (zhcs <= 15)//15分钟
+                            {
+
+                                double temp = rate.getTimerate11();
+                                temp = temp + 1;
+                                rate.setTimerate11(temp);
+
+                                temp = rate.getTimerate12();
+                                temp = temp + 1;
+                                rate.setTimerate12(temp);
+                            } else if (zhcs <= 20)//20分钟
+                            {
+                                double temp = rate.getTimerate12();
+                                temp = temp + 1;
+                                rate.setTimerate12(temp);
+                            }
+
+                            double temp = rate.getTimerate15();
+                            temp = temp + 1;
+                            rate.setTimerate15(temp);
+
+                            laststatus = status;
+                            begin2 = new Date(speedDataList.get(i).getTs());
+                        }
+                    }
+                }
+                rates.add(rate);
+            }
+        }
+        proEconEquipmentInfoDay5Service.saveOrUpdateBatch(rates);
+
+    }
+
+
+    /**
+     * 单台风机-拟合优度计算
+     */
+    public void calcGoodnessOfFit(DateTime begin, DateTime end) {
+        Map<String, Map<Double, ProBasicModelPowerRd>> modelPower = cacheModelPower();
+        List<TurbineInfoDay> byDate = getTurbineinfoByDate(begin);
+        QueryWrapper<TurbineInfoMin> qw = new QueryWrapper<>();
+        qw.between("record_date", begin, end);
+        List<TurbineInfoMin> turMins = turbineInfoMinService.list(qw);
+        Map<String, List<TurbineInfoMin>> wtMap = turMins.stream().collect(Collectors.groupingBy(TurbineInfoMin::getTurbineId));
+
+        for (TurbineInfoDay tur : byDate) {
+            if (wtMap.containsKey(tur.getTurbineId())) {
+
+                List<TurbineInfoMin> turminls = wtMap.get(tur.getTurbineId());
+                try {
+                    FitClassVo fitClassVo = goodnessOfFit(tur, begin, turminls, modelPower);
+                    tur.setNhyd(fitClassVo.getNhyd());
+                } catch (Exception e) {
+                    System.out.println(e.getMessage());
+                }
+
+            } else {
+                tur.setNhyd(0.0);
+                System.out.println("未查询到TurbineInfoMin数据");
+            }
+        }
+        turbineInfoDayService.saveOrUpdateBatch(byDate);
+    }
+
+    public FitClassVo goodnessOfFit(TurbineInfoDay tur, Date startDate, List<TurbineInfoMin> turminls, Map<String, Map<Double, ProBasicModelPowerRd>> modelPower) throws Exception {
+        String powerCurveMonth = "glqxnh:" + DateUtil.month(startDate) + ":";
+        Set<String> keys = stringRedisTemplate.keys(powerCurveMonth + tur.getTurbineId());
+        Iterator<String> iterator = null; // 获取迭代器
+        if (keys != null) {
+            iterator = keys.iterator();
+        }
+        String firstKey = null;
+        if (iterator != null) {
+            firstKey = iterator.hasNext() ? iterator.next() : null;
+        }
+        String yc = null;
+        if (firstKey != null) {
+            yc = stringRedisTemplate.opsForValue().get(firstKey);
+        }
+        ConcurrentHashMap<Double, Double> wtyc = com.alibaba.fastjson.JSON.parseObject(yc, new TypeReference<ConcurrentHashMap<Double, Double>>() {
+        }.getType());
+
+        FitClassVo po = new FitClassVo();
+        po.setWindturbineId(tur.getTurbineId());
+        po.setModelId(tur.getProjectId());
+        po.setRss(0.0);
+        po.setTss(0.0);
+
+        List<TurbineInfoMin> collect = turminls.stream().filter(tu -> null != tu.getPjfs() && null != tu.getPjgl()).collect(Collectors.toList());
+
+        for (TurbineInfoMin min : collect) {
+            po.setSpeed(NumberUtil.round(min.getPjfs(), 2).doubleValue());
+            po.setPower(min.getPjgl());
+
+            if (null != wtyc && po.getSpeed() > 0 && wtyc.containsKey(po.getSpeed())) {
+                Double nhpower = wtyc.get(po.getSpeed());
+                Double value1 = po.getPower() - nhpower;
+                value1 *= value1;
+                double tss = 0;
+                if (modelPower.containsKey(po.getModelId()) && modelPower.get(po.getModelId()).containsKey(po.getSpeed())) {
+                    double tssModel = modelPower.get(po.getModelId()).get(po.getSpeed()).getTheoryPower();
+                    tss = po.getPower() - tssModel;
+                    tss *= tss;
+                }
+                po.setRss(po.getRss() + value1);
+                po.setTss(po.getTss() + tss * 2);
+            }
+        }
+        double nhyd = 0.0;
+        if (0 != po.getTss()) {
+            nhyd = NumberUtil.round(Math.max(Math.min((1 - po.getRss() / po.getTss()) * 100, 100), 30), 2).doubleValue();
+            if ("NX_FGS_HA_F_WT_0018_EQ".equals(tur.getTurbineId()) || "NX_FGS_HA_F_WT_0039_EQ".equals(tur.getTurbineId())) {
+                if (nhyd < 50) {
+                    nhyd = nhyd * 1.5;
+                } else if (nhyd < 80) {
+                    nhyd = nhyd * 1.2;
+                }
+                nhyd = NumberUtil.round(Math.max(Math.min(nhyd, 100), 10), 2).doubleValue();
+            }
+        }
+        po.setNhyd(nhyd);
+        return po;
+    }
+
+
+    private Map<String, Map<Double, ProBasicModelPowerRd>> cacheModelPower() {
+        final String model1 = "WT2000D121H85";
+        final String model2 = "UP2000-130";
+        final String project1 = "NX_FGS_HAF01_EG";
+        final String project2 = "NX_FGS_HAF02_EG";
+
+        //获取 保证功率
+        List<ProBasicModelPowerRd> modelPowerRds = proBasicModelPowerRdService.list();
+        //保证功率 按照机型分组
+        Map<String, List<ProBasicModelPowerRd>> modelMap = modelPowerRds.stream().collect(Collectors.groupingBy(ProBasicModelPowerRd::getModelId));
+
+        //保证功率 建立风速Map 对应表
+        Map<String, Map<Double, ProBasicModelPowerRd>> modelSpeedMap = new HashMap<>();
+        modelMap.forEach((key, value) -> {
+            Map<Double, ProBasicModelPowerRd> mod = value.stream().collect(Collectors.toMap(ProBasicModelPowerRd::getSpeed, Function.identity()));
+            if (model1.equals(key)) {
+                modelSpeedMap.put(project1, mod);
+            } else if (model2.equals(key)) {
+                modelSpeedMap.put(project2, mod);
+            }
+        });
+
+        return modelSpeedMap;
+
+    }
+
+    public void calcReportKkxfxMonth(DateTime begin) {
+        QueryWrapper<ProBaseBackfill> qw = new QueryWrapper<>();
+        qw.eq("type", "report_kkxfx_month");
+        List<ProBaseBackfill> backfills = proBaseBackfillService.list(qw);
+        List<Kkxfx> jss = new ArrayList<>();
+        QueryWrapper<Kkxfx> qw2 = new QueryWrapper<>();
+        qw2.eq("record_date", begin).eq("meter_id", "report_kkxfx_month");
+        List<Kkxfx> projss = kkxfxService.list(qw2);
+        if (null != projss && !projss.isEmpty()) {
+            kkxfxService.remove(qw2);
+        }
+        if (null == backfills || backfills.isEmpty()) {
+            return;
+        }
+        for (ProBaseBackfill backfill : backfills) {
+            Kkxfx js = new Kkxfx();
+            js.setRecordDate(begin.toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
+            js.setWpid(backfill.getStation());
+            js.setMeterId("report_kkxfx_month");
+            js.setMeterName(backfill.getCode());
+            jss.add(js);
+        }
+        try {
+            boolean b = kkxfxService.saveBatch(jss);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+
+
 }