namespace IStation.Algorithm { #region ViewModel /// /// /// public class FreCombine { public FreCombine() { } public List Flags { get; set; } public int RunCount { get; set; } public double Frequency { get; set; } public double Flow { get; set; } public double Power { get; set; } } /// /// 分析泵项 /// public class OptimalCombine { public OptimalCombine() { } public double Flow { get; set; } public double Head { get; set; } public double Power { get; set; } public List Combines { get; set; } public List Flags { get; set; } public int FlagCount { get; set; } public string Remark { get; set; } public double MeritRatio { get; set; } } #endregion /// /// 调度分析辅助类 /// public class SchedulingHelper { decimal _frequency_min = 25; decimal _frequency_max = 50; decimal _frequency_space = 0.1m;//频率间隔 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"; string _falgFixPumpTag = "G"; string _falgSpaceMark = "_"; string GetRunFlag(int[] flags) { var runFlag = string.Empty; var index = 0; var count = flags.Length; foreach (var flag in flags) { runFlag += GetGFlag(flag); index++; if (index != count) { runFlag += _falgSpaceMark; } } return runFlag; } string GetRunFlag(List flags) { var runFlag = string.Empty; var index = 0; var count = flags.Count; foreach (var flag in flags) { runFlag += GetGFlag(flag); index++; if (index != count) { runFlag += _falgSpaceMark; } } return runFlag; } string GetGFlag(int flag) { return _falgFrePumpTag + flag; } #endregion DAL.ScheduleCombine _dal = new DAL.ScheduleCombine(); DAL.ScheduleConclusion _dalScheduleConclusion = new DAL.ScheduleConclusion(); DAL.ScheduleAnaLog _dalAnaLog = new DAL.ScheduleAnaLog(); /* private List _combineFlags1 = new List() { 11, 12, 13, 14, 16, 17, 18 }; private List _combineFlags2 = new List() { 15 };*/ public string Ana(List pumps, List flags_part1, List flags_part2, double target_flow, double target_head, List current_open_pump_flags, List must_open_pump_flags, List must_not_open_pump_flags) { 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(); for (int pumpCount = 1; pumpCount <= pumps.Count; pumpCount++) { if (pumpCount == 1) { var max_total_flow = pumps.Max(x => x.Qr); if (max_total_flow < target_flow) continue; } var combine_list = PermutationAndCombination.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 combine_flag_list_part1 = new List(); List combine_flag_list_part2 = new List(); foreach (var pump in combine) { if (flags_part1.Contains(pump)) { combine_flag_list_part1.Add(pump); } else { combine_flag_list_part2.Add(pump); } } //区分同型号泵 List fre_combine_list_part1 = new List(); List fre_combine_list_part2 = new List(); if (combine_flag_list_part1.Count > 0) { var conclusion_list_dic = new Dictionary>(); foreach (var flag in combine_flag_list_part1) { var runFlag = GetGFlag(flag); if (conclusion_list_dic.ContainsKey(flag)) continue; var conclusionList = _dalScheduleConclusion.GetList(runFlag, target_head); conclusion_list_dic[flag] = conclusionList; } if (conclusion_list_dic.Count < 1) { continue; } for (decimal fre = _frequency_max; fre >= _frequency_min; fre -= _frequency_space) { var freCombine = new FreCombine(); freCombine.Frequency = (double)fre; freCombine.Flags = new List(); foreach (var item in conclusion_list_dic) { var conclusion = item.Value.Find(x => x.Pump1 == (double)fre); if (conclusion != null) { freCombine.Flags.Add(item.Key); freCombine.Flow += conclusion.Flow; freCombine.Power += conclusion.Power; freCombine.RunCount++; } } if (freCombine.Flags.Count < 1) continue; fre_combine_list_part1.Add(freCombine); } } if (combine_flag_list_part2.Count > 0) { var conclusion_list_dic = new Dictionary>(); foreach (var flag in combine_flag_list_part2) { var runFlag = GetGFlag(flag); if (conclusion_list_dic.ContainsKey(flag)) continue; var conclusionList = _dalScheduleConclusion.GetList(runFlag, target_head); conclusion_list_dic[flag] = conclusionList; } if (conclusion_list_dic.Count < 1) { continue; } for (decimal fre = _frequency_max; fre >= _frequency_min; fre -= _frequency_space) { var freCombine = new FreCombine(); freCombine.Frequency = (double)fre; freCombine.Flags = new List(); foreach (var item in conclusion_list_dic) { var conclusion = item.Value.Find(x => x.Pump1 == (double)fre); if (conclusion != null) { freCombine.Flags.Add(item.Key); freCombine.Flow += conclusion.Flow; freCombine.Power += conclusion.Power; freCombine.RunCount++; } } if (freCombine.Flags.Count < 1) continue; fre_combine_list_part2.Add(freCombine); } } if (fre_combine_list_part1.Count == 0 && fre_combine_list_part2.Count == 0) continue; double total_flow_deviation = target_flow;//总流量偏差 double total_power = double.MaxValue;//总功率 double total_flow = double.MaxValue;//总流量 FreCombine optimal_combine_part1 = null; FreCombine optimal_combine_part2 = null; if (fre_combine_list_part1.Count < 1 || fre_combine_list_part2.Count < 1) { 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 (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) { combine_merit_ratio -= total_flow_deviation_ratio; } #region 分析最优组合方案 var optimal_combine = new OptimalCombine(); optimal_combine.Combines = new List(); optimal_combine.Flags = new List(); 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_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) { 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")}"); } return sb.ToString(); } /// /// 插入分析日志 /// private void InsertAnaLog(string info) { var entity = new Entity.ScheduleAnaLog(info); _dalAnaLog.Insert(entity); } /// /// 判断表是否存在 /// public bool ExistTable(string runFlag) { return _dal.ExistTable(runFlag); } } }