ningshuxia
2025-04-22 b24092beff11a75a3fec392dcedd475b407ebdc3
01-api/Service/IStation.Service/07-helper/02-schedule/ScheduleHelper.cs
@@ -1,7 +1,4 @@
using IStation.Application;
using IStation.Model;
namespace IStation.Service
namespace IStation.Service
{
    /// <summary>
    /// 调度分析辅助类
@@ -20,7 +17,6 @@
            }
            public int Flag { get; set; }
        }
        #endregion
        #region Private Variable
@@ -29,41 +25,44 @@
        private readonly decimal _frequency_max = 50;
        private readonly decimal _frequency_space = 1;//频率间隔 
        private readonly double _start_stop_loss_coefficient = 0.95;//泵启停损失系数
        private readonly double _start_stop_loss_coefficient = 0.9;//泵启停损失系数
        private double _sel_opt_flow_excess = 1;//可选方案的流量余量
        private readonly double _sel_opt_pump_pressure_excess = 0;//可选方案的单泵扬程默认抬升余量
        private double _station_target_flow_diff = 0; // 站点目标流量差值
        private readonly double _sel_opt_flow_deviation_ratio = 0.05;//可选方案的流量偏差比
        private readonly double _sel_opt_flow_deviation_ratio = 0.08;//可选方案的流量偏差比
        private readonly double _sel_opt_reasonable_flow_deviation_ratio = 0.005;//合理的方案的流量偏差比
        private readonly Service.AnalysisParameter _service_analysis_conclusion = new();
        private readonly Service.AnalysisDeviation _service_analysis_deviation = new();
        private readonly Service.AnalysisFactor _service_analysis_factor = new();
        private readonly Service.AnalysisParameter _service_analysis_parameter = new();
        private int _min_open_count;//最小开泵数量
        private int _max_open_count;//最大开泵数量
        private List<int> _current_open_flag_list = null;// 当前开泵列表
        private List<int> _must_open_flag_list = null; // 必开泵列表  
        private List<int> _must_close_flag_list = null; // 必关泵列表
        private List<int> _must_close_flag_list = null; // 必关泵列表
        private List<List<int>> _forbidden_flag_combine_list = null; // 禁用泵组合 
        private List<List<int>> _associative_flag_combine_list = null; // 关联泵组合 
        private List<List<int>> _same_section_flag_combine_list = null; // 同段泵组合  
        private List<Model.WaterSupplyLimit> _water_supply_limit_list = null; //供水限制列表
        private List<Model.FrequencyLimit> _frequency_limit_list = null; // 频率限制列表
        private Dictionary<int, double> _flag_cumulative_runtime_dict = null; // 泵累计运行时长字典
        private List<int> _priority_open_flag_list = null; // 优先开泵列表
        private List<int> _maintenance_flag_list = null; // 检修列表
        private List<Model.AnalysisDeviation> _analysis_deviation_list = null;//分析偏差
        #endregion
        /// <summary>
        /// 初始化
        /// </summary>
        public void Initial(List<int> current_open_flag_list, Model.ScheduleConfig schedule_config, List<Model.AnalysisDeviation> analysis_deviation_list)
        public void Initial(List<int> current_open_flag_list, Model.ScheduleConfig schedule_config, List<Model.AnalysisDeviation> analysis_deviation_list, double station_target_flow_diff = 0)
        {
            _current_open_flag_list = current_open_flag_list;
            _min_open_count = 1;
            _max_open_count = 0;
@@ -75,6 +74,9 @@
            _water_supply_limit_list = null;
            _frequency_limit_list = null;
            _flag_cumulative_runtime_dict = null;
            _priority_open_flag_list = null;
            _maintenance_flag_list = null;
            _station_target_flow_diff = 0;
            if (schedule_config != null)
            {
                _min_open_count = schedule_config.MinOpenCount;
@@ -87,15 +89,16 @@
                _water_supply_limit_list = schedule_config.WaterSupplyLimitList;
                _frequency_limit_list = schedule_config.FrequencyLimitList;
                _flag_cumulative_runtime_dict = schedule_config.FlagCumulativeRuntimeDict;
                _priority_open_flag_list = schedule_config.PriorityOpenFlagList;
                _maintenance_flag_list = schedule_config.MaintenanceFlagList;
            }
            _analysis_deviation_list = analysis_deviation_list;
            _station_target_flow_diff = station_target_flow_diff;
        }
        #region OptAnaCombine
        /// <summary>
        /// 获取最优组合
@@ -107,13 +110,14 @@
        /// <returns></returns>
        public AnaCombine GetOptAnaCombine
            (
            List<Model.Pump> pump_list,
            List<Model.Pump> pump_list,
            Dictionary<int, double> flag_inlet_water_level_dict,
            double target_flow,
            double target_pressure
            )
        {
            //获取方案时用补差的流量,供水限制用目标流量判断
            var target_flow_compensation = target_flow + _station_target_flow_diff;
            #region 初始化参数 
            if (pump_list == null || !pump_list.Any())
            {
@@ -131,6 +135,8 @@
            var water_supply_limit_list = _water_supply_limit_list;
            var frequency_limit_list = _frequency_limit_list;
            var flag_cumulative_runtime_dict = _flag_cumulative_runtime_dict;
            var priority_open_flag_list = _priority_open_flag_list;
            var maintenance_flag_list = _maintenance_flag_list;
            var pump_bp_dict = pump_list.ToDictionary(x => x.Flag, x => x.IsBp);
            var pump_nr_dict = pump_list.ToDictionary(x => x.Flag, x => x.Nr);
@@ -139,6 +145,7 @@
            var combine_merit_ratio = 1d;//组合择优率 
            target_flow = Math.Round(target_flow, 1);
            target_flow_compensation = Math.Round(target_flow_compensation,1);
            target_pressure = Math.Round(target_pressure, 1);
            #endregion
@@ -193,6 +200,10 @@
            {
                var water_supply_min = water_supply_limit_list.Min(x => x.Min);
                var water_supply_max = water_supply_limit_list.Max(x => x.Max);
#if DEBUG
                water_supply_min = 0;
#endif
                if (target_flow < water_supply_min || target_flow > water_supply_max)
                {
                    return default;
@@ -222,6 +233,24 @@
            }
            #endregion
            #region 存在-优先开泵列表
            var priority_open_flag_list_remark = string.Empty;
            var exist_priority_open_flag_list = priority_open_flag_list != null && priority_open_flag_list.Count > 0;
            if (exist_priority_open_flag_list)
            {
                priority_open_flag_list = priority_open_flag_list.OrderBy(x => x).ToList();
                priority_open_flag_list_remark = IntListHelper.ToString(priority_open_flag_list);
            }
            #endregion
            #region 存在-检修列表
            var exist_maintenance_flag_list = maintenance_flag_list != null && maintenance_flag_list.Count > 0;
            #endregion
            #region 存在-当前开泵列表 (是否切泵)
            var exist_current_open_flag_list = current_open_flag_list != null && current_open_flag_list.Count > 0;
@@ -236,7 +265,7 @@
                    {
                        if (target_flow < limit.Min || target_flow > limit.Max)
                        {
                            exist_limit = true;
                            exist_limit = true;
                        }
                    }
                }
@@ -251,15 +280,16 @@
                       pump_bp_dict,
                       exist_frequency_limit_list,
                       frequency_limit_flag_dict,
                       target_flow,
                       target_flow_compensation,
                       target_pressure
                       );
                    if (opt_ana_combine != null)
                    if (opt_ana_combine != null)
                        return opt_ana_combine;
                }
            }
            #endregion
            #endregion
@@ -319,7 +349,6 @@
                        if (exist_intersected)
                            continue;
                    }
                    //禁用组合
                    if (exist_forbidden_flag_combine_list)
@@ -405,6 +434,24 @@
                        }
                    }
                    //优先开泵列表
                    if (exist_priority_open_flag_list)
                    {
                        //目前逻辑 优先开泵==必开方案
                        var combine_remark = IntListHelper.ToString(combine.OrderBy(x => x));
                        if (!combine_remark.Contains(priority_open_flag_list_remark))
                            continue;
                    }
                    //检修列表
                    if (exist_maintenance_flag_list)
                    {
                        var exist_intersected = combine.Intersect(maintenance_flag_list).Count() > 0;
                        if (exist_intersected)
                            continue;
                    }
                    #endregion
                    var total_loss_ratio = Math.Pow(_start_stop_loss_coefficient, start_stop_count);//启停一次损失些能耗
@@ -419,7 +466,7 @@
                        pump_bp_dict,
                        exist_frequency_limit_list,
                        frequency_limit_flag_dict,
                        target_flow,
                        target_flow_compensation,
                        target_pressure
                        );
                    if (opt_ana_combine == null)
@@ -427,11 +474,12 @@
                    opt_ana_combine_list.Add(opt_ana_combine);
                }
                // 20250422 注释原因:供水范围会有重叠,考虑切泵操作
                //如果当前循环已经满足,不需要再加泵
                if (opt_ana_combine_list.Any())
                {
                    break;
                }
                //if (opt_ana_combine_list.Any())
                //{
                //    break;
                //}
            }
            if (opt_ana_combine_list.Count < 1)
@@ -478,53 +526,6 @@
            //先修正组合曲线和模型的偏差扬程
            var combine_deviation_factor_dict = GetCombineDeviationFactorDict(target_flow, combine);
            if (GlobalHelper.IsStation1(combine))
            {
                var err_combine = new List<Tuple<double, List<int>>>()
                {
                    new (23500, new List<int>(){12,13,14,15,17 })
                };
                var exist_err_combine = err_combine.Find(x => x.Item2.SequenceEqual(combine));
                if (exist_err_combine != null)
                {
                    ScheduleLog.Info(-1, "测试", $"目标:{target_pressure}");
                    if (target_flow > exist_err_combine.Item1)
                    {
                        var dev_diff = 0.5;
                        foreach (var flag in combine)
                        {
                            var dev_pressure = combine_deviation_factor_dict[flag];
                            combine_deviation_factor_dict[flag] = dev_pressure - dev_diff;
                            //combine_deviation_factor_dict[flag] = 0;
                            ScheduleLog.Info(-1, "测试", $"{flag}#:压力偏差{dev_pressure}-{dev_diff}={dev_pressure - dev_diff:N4}");
                        }
                    }
                }
            }
            else
            {
                //var err_combine = new List<Tuple<double, List<int>>>()
                //{
                //    new (29000, new List<int>(){22,23,26})
                //};
                //var exist_err_combine = err_combine.Find(x => x.Item2.SequenceEqual(combine));
                //if (exist_err_combine != null)
                //{
                //    ScheduleLog.Info(-1, "测试", $"目标:{target_pressure}");
                //    if (target_flow > exist_err_combine.Item1)
                //    {
                //        foreach (var flag in combine)
                //        {
                //            combine_deviation_factor_dict[flag] = 0;
                //            ScheduleLog.Info(-1, "测试", $"{flag}#:压力偏差{0}");
                //        }
                //    }
                //}
            }
            var conclusion_ex_list_list = new List<List<AnalysisConclusionViewModel>>();
            var conclusion_ex_list_dict = new Dictionary<int, List<AnalysisConclusionViewModel>>();
            double max_supply_flow = 0;
@@ -537,7 +538,8 @@
                //组合偏差系数
                var combine_deviation_factor = combine_deviation_factor_dict[flag];
                var current_pressure_diff = target_pressure - inlet_water_level + combine_deviation_factor + _sel_opt_pump_pressure_excess;
                var current_pressure_diff = target_pressure - inlet_water_level - combine_deviation_factor + _sel_opt_pump_pressure_excess;
                current_pressure_diff = Math.Round(current_pressure_diff, 1);
                //频率限制
@@ -545,13 +547,13 @@
                if (exist_frequency_limit_list && frequency_limit_flag_dict.ContainsKey(flag))
                {
                    var limit = frequency_limit_flag_dict[flag];
                    conclusion_list = _service_analysis_conclusion.GetList(run_flag, limit.Min, limit.Max, current_pressure_diff);
                    conclusion_list = _service_analysis_parameter.GetList(run_flag, limit.Min, limit.Max, current_pressure_diff);
                }
                else
                {
                    //定频泵 可能最小压差超过目标压差
                    var min_pressure_diff_conclusion = _service_analysis_conclusion.GetMinPressureDiff(run_flag);
                    var min_pressure_diff_conclusion = _service_analysis_parameter.GetMinPressureDiff(run_flag);
                    if (min_pressure_diff_conclusion != null && min_pressure_diff_conclusion.PressureDiff > current_pressure_diff)
                    {
                        conclusion_list = new List<Model.AnalysisParameter>() { min_pressure_diff_conclusion };
@@ -561,11 +563,12 @@
                        var is_bp = pump_bp_dict[flag];
                        if (is_bp)
                        {
                            conclusion_list = _service_analysis_conclusion.GetList(run_flag, current_pressure_diff);
                            conclusion_list = _service_analysis_parameter.GetList(run_flag, current_pressure_diff);
                        }
                        else
                        {
                            conclusion_list = new List<Model.AnalysisParameter>() { min_pressure_diff_conclusion };
                            var list = _service_analysis_parameter.GetList(run_flag);
                            conclusion_list = _service_analysis_parameter.GetList(run_flag, current_pressure_diff);
                        }
                    }
                }
@@ -580,18 +583,17 @@
            }
            if (conclusion_ex_list_list.Count != combine.Count())
                return default;
                return default;
            if (max_supply_flow < target_flow * _sel_opt_flow_excess)
            {
                if (GlobalHelper.IsStation1(combine))
                {
                    _sel_opt_flow_excess= 0.995;
                    _sel_opt_flow_excess = 0.97;
                }
                var flow_excess = target_flow * _sel_opt_flow_excess;
                if (max_supply_flow < flow_excess)
                    return default;
            }
            var opt_ana_combine = GetOptAnaCombine(conclusion_ex_list_dict, pump_nr_dict, pump_bp_dict, target_flow);
@@ -712,7 +714,7 @@
                        ana_combine.TotalPower += opt_cl_ex.Power;
                        var ana_fre_pump = new AnaFrePump();
                        ana_fre_pump.Flag = flag;
                        ana_fre_pump.Flag = flag;
                        ana_fre_pump.Flow = opt_cl_ex.Flow;
                        ana_fre_pump.Head = opt_cl_ex.Head;
                        ana_fre_pump.PressureDiff = opt_cl_ex.PressureDiff;
@@ -732,7 +734,7 @@
            }
            if (!ana_combine_list.Any())
                return default;
            var opt_ana_combine = ana_combine_list.OrderBy(x => x.TotalPower).First();
            var opt_ana_combine = ana_combine_list.OrderBy(x => x.TotalFlow).OrderBy(x => x.TotalPower).First();
            return opt_ana_combine;
        }
@@ -957,7 +959,7 @@
                Yw.LogHelper.Error($"[{Yw.Untity.IntListHelper.ToString(flags)}]组合不存在偏差系数!");
                return deviation_factor_dict;
            }
            var a = flow;
            var flow_dev = flow;
            Model.AnalysisDeviation analysis_deviation = null;
@@ -967,8 +969,8 @@
                analysis_deviation = analysis_deviation_list.Where(x => x.MinFlow <= flow_dev && flow_dev <= x.MaxFlow).FirstOrDefault();
                if (analysis_deviation != null)
                    break;
            }
            }
            if (analysis_deviation == null)
            {
                Yw.LogHelper.Error($"[{Yw.Untity.IntListHelper.ToString(flags)}]组合不存在偏差系数!");
@@ -991,7 +993,7 @@
        #endregion
        #region Expand
        /// <summary>
        /// 获取变频泵列表 根据工况计算
        /// </summary>
@@ -1062,7 +1064,7 @@
                var fre_pump = new AnaFrePump();
                fre_pump.Flag = flag;
                fre_pump.Flag = flag;
                fre_pump.Flow = flow;
                fre_pump.Head = head;
                fre_pump.Power = curveQP.GetFitPointY(flow);
@@ -1078,109 +1080,7 @@
            return ana_fre_pump_list;
        }
        /// <summary>
        /// 获取变频泵列表 根据工况计算
        /// </summary>
        /// <param name="pumps"></param>
        /// <param name="flag_rpm_dic"></param>
        /// <param name="flag_inlet_water_level_dict"></param>
        /// <param name="flag_flow_dic"></param>
        /// <param name="flag_head_dic"></param>
        /// <param name="flag_curve_head_dic"></param>
        /// <param name="total_flow"></param>
        /// <param name="ues_deviation_factor"></param>
        /// <returns></returns>
        public List<AnaFrePump> GetAnaFrePumpListByWorking(
            List<Model.Pump> pumps,
            Dictionary<int, double> flag_rpm_dic,
            Dictionary<int, double> flag_inlet_water_level_dict,
            Dictionary<int, double> flag_flow_dic,
            Dictionary<int, double> flag_head_dic,
            double total_flow,
            out Dictionary<int, double> flag_curve_head_dic,
            bool ues_deviation_factor = false
            )
        {
            flag_curve_head_dic = new Dictionary<int, double>();
            if (pumps == null || !pumps.Any())
            {
                return default;
            }
            if (flag_rpm_dic == null || !flag_rpm_dic.Any())
            {
                return default;
            }
            var run_flag_list = flag_rpm_dic.Where(x => x.Value > 1).Select(x => x.Key).OrderBy(x => x).ToList();
            var ana_fre_pump_list = new List<AnaFrePump>();
            foreach (var flag in run_flag_list)
            {
                var pump = pumps.Find(x => x.Flag == flag);
                if (pump == null)
                    continue;
                var rpm = flag_rpm_dic[flag];
                if (rpm < 1)
                    continue;
                var hz = Math.Round(rpm / pump.Nr * 50, 1);
                var CurveQH50 = pump.CurveQH;
                var CurveQP50 = pump.CurveQP;
                var curveQH = Curve.PumpCalculateHelper.CalculateSimilarQH(CurveQH50, pump.Nr, rpm);
                var curveQP = Curve.PumpCalculateHelper.CalculateSimilarQP(CurveQP50, pump.Nr, rpm);
                double flow = 0, head = 0;
                if (flag_head_dic != null && flag_head_dic.ContainsKey(pump.Flag))
                {
                    head = flag_head_dic[pump.Flag];
                }
                if (flag_inlet_water_level_dict != null && flag_inlet_water_level_dict.ContainsKey(pump.Flag))
                {
                    head -= flag_inlet_water_level_dict[pump.Flag];
                }
                if (ues_deviation_factor)
                {
                    //var combine_deviation_factor_dict = GetCombineDeviationFactorDict(total_flow, run_flag_list);//修正组合曲线和模型的偏差扬程
                    //if (combine_deviation_factor_dict != null && combine_deviation_factor_dict.ContainsKey(flag))
                    //{
                    //    var combine_deviation_factor = combine_deviation_factor_dict[flag];  //组合偏差系数
                    //    head -= combine_deviation_factor;
                    //}
                }
                flow = curveQH.GetInterPointLastX(head) ?? 0;
                if (flow < 0)
                    continue;
                var working_flow = flag_flow_dic[flag];
                flag_curve_head_dic[flag] = curveQH.GetFitPointY(working_flow);
                var fre_pump = new AnaFrePump();
                fre_pump.Flag = flag;
                fre_pump.Flow = flow;
                fre_pump.Head = head;
                fre_pump.Power = curveQP.GetFitPointY(flow);
                fre_pump.PressureDiff = head - Curve.PumpCalculateHelper.CalculateOtherPress(flow, pump.Ic, pump.Oc, null, null);
                fre_pump.Eff = Curve.PumpCalculateHelper.CalculateE(fre_pump.Flow, fre_pump.Head, fre_pump.Power);
                fre_pump.Frequency = rpm / pump.Nr * 50;
                fre_pump.Speed = rpm;
                ana_fre_pump_list.Add(fre_pump);
            }
            return ana_fre_pump_list;
        }
        #endregion
        #endregion
    }
}