ningshuxia
2024-05-06 8f6d2b48f22b695574bd4a6c4ac91b1ac9f780b1
Schedule/IStation.Algorithm/Schedule/SchedulingHelper.cs
@@ -24,11 +24,14 @@
    public class OptimalCombine
    {
        public OptimalCombine() { }
        public List<int> Flags { get; set; }
        public double Flow { get; set; }
        public double Head { get; set; }
        public double Power { get; set; }
        public List<FreCombine> Combines { get; set; }
        public List<int> Flags { get; set; }
        public int FlagCount { get; set; }
        public string Remark { get; set; }
        public double MeritRatio { get; set; }
    }
    #endregion
@@ -38,12 +41,15 @@
    /// </summary>
    public class SchedulingHelper
    {
        double _frequency_def = 50;
        decimal _frequency_min = 25;
        decimal _frequency_max = 50;
        decimal _frequency_space = 0.1m;//频率间隔  
        double _head_space = 0.1;//扬程间隔
        double _start_stop_loss_coefficient = 0.95;//泵启停损失系数
        double _sel_opt_flow_deviation_ratio = 0.05;//可选方案的流量偏差比
        double _sel_opt_reasonable_flow_deviation_ratio = 0.005;//合理的方案的流量偏差比
        #region RunFlag
        string _falgFrePumpTag = "B";
@@ -97,24 +103,92 @@
        DAL.ScheduleAnaLog _dalAnaLog = new DAL.ScheduleAnaLog();
        private List<int> _combineFlags1 = new List<int>() { 11, 12, 13, 14, 16, 17, 18 };
        private List<int> _combineFlags2 = new List<int>() { 15 };
        /* private List<int> _combineFlags1 = new List<int>() { 11, 12, 13, 14, 16, 17, 18 };
         private List<int> _combineFlags2 = new List<int>() { 15 };*/
        public void Ana(List<Pump> pumps, double taget_flow, double tagetHead)
        public string Ana(List<Pump> pumps, List<int> flags_part1, List<int> flags_part2, double target_flow, double target_head, List<int> current_open_pump_flags, List<int> must_open_pump_flags, List<int> must_not_open_pump_flags)
        {
            tagetHead = Math.Round(tagetHead);
            if (pumps == null || !pumps.Any())
            {
                return "无方案:pumps is null";
            }
            target_flow = Math.Round(target_flow, 1);
            target_head = Math.Round(target_head, 1);
            #region 存在-当前开泵列表
            var exist_current_open_pump_flags = current_open_pump_flags != null && current_open_pump_flags.Count > 0;
            #endregion
            #region 存在-必开泵列表
            var must_open_pump_flags_remark = string.Empty;
            var exist_must_open_pump_flags = must_open_pump_flags != null && must_open_pump_flags.Count > 0;
            if (exist_must_open_pump_flags)
            {
                must_open_pump_flags = must_open_pump_flags.OrderBy(x => x).ToList();
                must_open_pump_flags_remark = IntListHelper.ToString(must_open_pump_flags);
            }
            #endregion
            #region 存在-必不能开泵列表
            var exist_must_not_open_pump_flags = must_not_open_pump_flags != null && must_not_open_pump_flags.Count > 0;
            #endregion
            var pump_flag_list = pumps.Select(x => x.ID).ToList();
            var optimal_combine_list = new List<OptimalCombine>();
            for (int pumpCount = 1; pumpCount <= pumps.Count; pumpCount++)
            {
                var combine_list = PermutationAndCombination<int>.GetCombination(pump_flag_list.ToArray(), pumpCount);
                if (pumpCount == 1)
                {
                    var max_total_flow = pumps.Max(x => x.Qr);
                    if (max_total_flow < target_flow)
                        continue;
                }
                var combine_list = PermutationAndCombination<int>.GetCombination(pump_flag_list.ToArray(), pumpCount);//排列组合
                foreach (var combine in combine_list)
                {
                    double combine_merit_ratio = 1;//组合择优率
                    if (exist_must_open_pump_flags)
                    {
                        var combine_remark = IntListHelper.ToString(combine.OrderBy(x => x));
                        if (!combine_remark.Contains(must_open_pump_flags_remark))
                            continue;
                    }
                    if (exist_must_not_open_pump_flags)
                    {
                        var exist_intersected = combine.Intersect(must_not_open_pump_flags).Count() > 0;
                        if (exist_intersected)
                            continue;
                    }
                    int start_stop_count = 0;//启停数量
                    if (exist_current_open_pump_flags)
                    {
                        var start_pump_count = combine.Except(current_open_pump_flags).Count();
                        var close_pump_count = current_open_pump_flags.Except(combine).Count();
                        start_stop_count = start_pump_count + close_pump_count;//启停数量
                    }
                    else
                    {
                        start_stop_count = combine.Count();
                        if (exist_must_open_pump_flags)
                        {
                            start_stop_count = combine.Except(must_open_pump_flags).Count();
                        }
                    }
                    var total_loss_ratio = Math.Pow(_start_stop_loss_coefficient, start_stop_count);//启停一次损失些能耗
                    combine_merit_ratio *= total_loss_ratio;
                    List<int> combine_flag_list_part1 = new List<int>();
                    List<int> combine_flag_list_part2 = new List<int>();
                    foreach (var pump in combine)
                    {
                        if (_combineFlags1.Contains(pump))
                        if (flags_part1.Contains(pump))
                        {
                            combine_flag_list_part1.Add(pump);
                        }
@@ -124,7 +198,7 @@
                        }
                    }
                    //区分同型号泵
                    List<FreCombine> fre_combine_list_part1 = new List<FreCombine>();
                    List<FreCombine> fre_combine_list_part2 = new List<FreCombine>();
@@ -136,7 +210,7 @@
                            var runFlag = GetGFlag(flag);
                            if (conclusion_list_dic.ContainsKey(flag))
                                continue;
                            var conclusionList = _dalScheduleConclusion.GetList(runFlag, tagetHead);
                            var conclusionList = _dalScheduleConclusion.GetList(runFlag, target_head);
                            conclusion_list_dic[flag] = conclusionList;
                        }
@@ -165,12 +239,7 @@
                                continue;
                            fre_combine_list_part1.Add(freCombine);
                        }
                    }
                    if (combine_flag_list_part2.Count > 0)
                    {
                        var conclusion_list_dic = new Dictionary<int, List<Entity.ScheduleConclusion>>();
@@ -179,7 +248,7 @@
                            var runFlag = GetGFlag(flag);
                            if (conclusion_list_dic.ContainsKey(flag))
                                continue;
                            var conclusionList = _dalScheduleConclusion.GetList(runFlag, tagetHead);
                            var conclusionList = _dalScheduleConclusion.GetList(runFlag, target_head);
                            conclusion_list_dic[flag] = conclusionList;
                        }
@@ -210,68 +279,131 @@
                        }
                    }
                    if (fre_combine_list_part1.Count == 0 && fre_combine_list_part2.Count == 0)
                        continue;
                    var optimalCombine = AnaOptimalCombine(fre_combine_list_part1, fre_combine_list_part2, taget_flow);
                }
                    double total_flow_deviation = target_flow;//总流量偏差
                    double total_power = double.MaxValue;//总功率
                    double total_flow = double.MaxValue;//总流量
            }
        }
        private OptimalCombine AnaOptimalCombine(List<FreCombine> fre_combine_list_part1, List<FreCombine> fre_combine_list_part2, double target_flow)
        {
            double flow_deviation = target_flow;
            double total_power = double.MaxValue;
            double total_flow = double.MaxValue;
            FreCombine optimal_combine_part1 = null;
            FreCombine optimal_combine_part2 = null;
            for (int Index_part1 = 0; Index_part1 < fre_combine_list_part1.Count; Index_part1++)
            {
                for (int Index_part2 = 0; Index_part2 < fre_combine_list_part2.Count; Index_part2++)
                {
                    var fre_combine1 = fre_combine_list_part1[Index_part1];
                    var fre_combine2 = fre_combine_list_part2[Index_part2];
                    var current_flow = fre_combine1.Flow + fre_combine2.Flow;
                    var current_power = fre_combine1.Power + fre_combine2.Power;
                    var diff_flow = Math.Abs(current_flow - target_flow);
                    if (diff_flow < flow_deviation)
                    FreCombine optimal_combine_part1 = null;
                    FreCombine optimal_combine_part2 = null;
                    if (fre_combine_list_part1.Count < 1 || fre_combine_list_part2.Count < 1)
                    {
                        optimal_combine_part1 = fre_combine1;
                        optimal_combine_part2 = fre_combine2;
                        total_power = fre_combine1.Power + fre_combine2.Power;
                        total_flow = current_flow;
                        flow_deviation = diff_flow;
                        if (fre_combine_list_part1.Count < 1)
                        {
                            fre_combine_list_part1 = fre_combine_list_part2;
                        }
                        for (int Index_part1 = 0; Index_part1 < fre_combine_list_part1.Count; Index_part1++)
                        {
                            var fre_combine1 = fre_combine_list_part1[Index_part1];
                            var current_flow = fre_combine1.Flow;
                            var current_power = fre_combine1.Power;
                            var diff_flow = Math.Abs(current_flow - target_flow);
                            if (diff_flow < total_flow_deviation)
                            {
                                optimal_combine_part1 = fre_combine1;
                                total_power = fre_combine1.Power;
                                total_flow = current_flow;
                                total_flow_deviation = diff_flow;
                            }
                            if (diff_flow < target_flow * 0.01 && current_power < total_power)
                            {
                                optimal_combine_part1 = fre_combine1;
                                total_power = fre_combine1.Power;
                                total_flow = current_flow;
                            }
                        }
                    }
                    else
                    {
                        for (int Index_part1 = 0; Index_part1 < fre_combine_list_part1.Count; Index_part1++)
                        {
                            for (int Index_part2 = 0; Index_part2 < fre_combine_list_part2.Count; Index_part2++)
                            {
                                var fre_combine1 = fre_combine_list_part1[Index_part1];
                                var fre_combine2 = fre_combine_list_part2[Index_part2];
                                var current_flow = fre_combine1.Flow + fre_combine2.Flow;
                                var current_power = fre_combine1.Power + fre_combine2.Power;
                                var diff_flow = Math.Abs(current_flow - target_flow);
                                if (diff_flow < total_flow_deviation)
                                {
                                    optimal_combine_part1 = fre_combine1;
                                    optimal_combine_part2 = fre_combine2;
                                    total_power = fre_combine1.Power + fre_combine2.Power;
                                    total_flow = current_flow;
                                    total_flow_deviation = diff_flow;
                                }
                                if (diff_flow < target_flow * 0.01 && current_power < total_power)
                                {
                                    optimal_combine_part1 = fre_combine1;
                                    optimal_combine_part2 = fre_combine2;
                                    total_power = fre_combine1.Power + fre_combine2.Power;
                                    total_flow = current_flow;
                                }
                            }
                        }
                    }
                    if (diff_flow < target_flow * 0.01 && current_power < total_power)
                    if (optimal_combine_part1 == null && optimal_combine_part2 == null)
                        continue;
                    var total_flow_deviation_ratio = Math.Abs((1 - Math.Abs((total_flow / target_flow))));
                    if (total_flow_deviation_ratio > _sel_opt_flow_deviation_ratio)
                        continue;
                    if (total_flow_deviation_ratio > _sel_opt_reasonable_flow_deviation_ratio)
                    {
                        optimal_combine_part1 = fre_combine1;
                        optimal_combine_part2 = fre_combine2;
                        total_power = fre_combine1.Power + fre_combine2.Power;
                        total_flow = current_flow;
                        combine_merit_ratio -= total_flow_deviation_ratio;
                    }
                    #region 分析最优组合方案
                    var optimal_combine = new OptimalCombine();
                    optimal_combine.Combines = new List<FreCombine>();
                    optimal_combine.Flags = new List<int>();
                    if (optimal_combine_part1 != null)
                    {
                        optimal_combine.Combines.Add(optimal_combine_part1);
                        optimal_combine.Flags.AddRange(optimal_combine_part1.Flags);
                    }
                    if (optimal_combine_part2 != null)
                    {
                        optimal_combine.Combines.Add(optimal_combine_part2);
                        optimal_combine.Flags.AddRange(optimal_combine_part2.Flags);
                    }
                    optimal_combine.Flow = total_flow;
                    optimal_combine.Power = total_power;
                    optimal_combine.Flags = optimal_combine.Flags.OrderBy(x => x).ToList();
                    optimal_combine.FlagCount = optimal_combine.Flags.Count;
                    optimal_combine.Remark = IntListHelper.ToString(optimal_combine.Flags);
                    optimal_combine.MeritRatio = combine_merit_ratio;
                    optimal_combine.Head = target_head;
                    optimal_combine_list.Add(optimal_combine);
                    #endregion
                }
            }
            if (optimal_combine_part1 == null && optimal_combine_part2 == null)
                return default;
            var optimal_combine = new OptimalCombine();
            optimal_combine.Combines = new List<FreCombine>();
            if (optimal_combine_part1 != null)
            if (optimal_combine_list.Count < 1)
                return "无方案";
            var sb = new StringBuilder();
            optimal_combine_list = optimal_combine_list.OrderByDescending(x => x.MeritRatio).ToList();
            foreach (var opt in optimal_combine_list)
            {
                optimal_combine.Combines.Add(optimal_combine_part1);
                sb.AppendLine($"MeritRatio:{opt.MeritRatio.ToString("N5")},Flow:{opt.Flow.ToString("N1")},Power:{opt.Power.ToString("N1")}," +
                    $"Flags:{opt.Remark};FlowDeviation:{(opt.Flow - target_flow).ToString("N1")}");
            }
            if (optimal_combine_part2 != null)
            {
                optimal_combine.Combines.Add(optimal_combine_part2);
            }
            optimal_combine.Flow = total_flow;
            optimal_combine.Power = total_power;
            return optimal_combine;
            return sb.ToString();
        }
        /// <summary>