| | |
| | | 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 |
| | |
| | | /// </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"; |
| | |
| | | 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); |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | //区分同型号泵 |
| | | List<FreCombine> fre_combine_list_part1 = new List<FreCombine>(); |
| | | List<FreCombine> fre_combine_list_part2 = new List<FreCombine>(); |
| | | |
| | |
| | | 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; |
| | | } |
| | | |
| | |
| | | continue; |
| | | fre_combine_list_part1.Add(freCombine); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | } |
| | | |
| | | if (combine_flag_list_part2.Count > 0) |
| | | { |
| | | var conclusion_list_dic = new Dictionary<int, List<Entity.ScheduleConclusion>>(); |
| | |
| | | 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; |
| | | } |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | 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> |