namespace IStation.Algorithm { /// /// 调度分析辅助类 /// public partial class ScheduleHelper_test { readonly decimal _frequency_min = 25; readonly decimal _frequency_max = 50; readonly decimal _frequency_space = 0.1m;//频率间隔 readonly double _start_stop_loss_coefficient = 0.95;//泵启停损失系数 readonly double _sel_opt_flow_deviation_ratio = 0.05;//可选方案的流量偏差比 readonly double _sel_opt_reasonable_flow_deviation_ratio = 0.005;//合理的方案的流量偏差比 readonly Service.AnalysisCombine _service_analysis_combine = new(); readonly Service.AnalysisConclusion _service_analysis_conclusion = new(); readonly Service.AnalysisLog _service_analysis_log = new(); List _current_open_flag_list = null;// 当前开泵列表 List _must_open_flag_list = null; // 必开泵列表 List _must_close_flag_list = null; // 必关泵列表 List> _forbidden_flag_combine_list = null; // 禁用泵组合 List> _associative_flag_combine_list = null; // 关联泵组合 List> _same_section_flag_combine_list = null; // 同段泵组合 List _water_supply_limit_list = null; //供水限制列表 List _frequency_limit_list = null; // 频率限制列表 //List _priority_order_flag_list = null; // 优先度排序 暂未考虑 /// /// 初始化 /// public void Initial(List current_open_flag_list, Model.ScheduleConfig schedule_config) { _current_open_flag_list = current_open_flag_list; _must_open_flag_list = null; _must_close_flag_list = null; _forbidden_flag_combine_list = null; _associative_flag_combine_list = null; _same_section_flag_combine_list = null; _water_supply_limit_list = null; _frequency_limit_list = null; if (schedule_config != null) { _must_open_flag_list = schedule_config.MustOpenFlagList; _must_close_flag_list = schedule_config.MustCloseFlagList; _forbidden_flag_combine_list = schedule_config.ForbiddenFlagCombineList; _associative_flag_combine_list = schedule_config.AssociativeFlagCombineList; _same_section_flag_combine_list = schedule_config.SameSectionFlagCombineList; _water_supply_limit_list = schedule_config.WaterSupplyLimitList; _frequency_limit_list = schedule_config.FrequencyLimitList; } } /// /// 计算 /// /// /// /// /// /// /// public AnaOptimalCombine Calc(int station, List pumps, List flags, List flags_part2, double target_flow, double target_head) { var current_open_flag_list = _current_open_flag_list; var must_open_flag_list = _must_open_flag_list; var must_close_flag_list = _must_close_flag_list; var forbidden_flag_combine_list = _forbidden_flag_combine_list; var associative_flag_combine_list = _associative_flag_combine_list; var same_section_flag_combine_list = _same_section_flag_combine_list; var water_supply_limit_list = _water_supply_limit_list; var frequency_limit_list = _frequency_limit_list; if (pumps == null || !pumps.Any()) { return default; } target_flow = Math.Round(target_flow, 1); target_head = Math.Round(target_head, 1); #region 存在-当前开泵列表 var exist_current_open_flag_list = current_open_flag_list != null && current_open_flag_list.Count > 0; #endregion #region 存在-必开泵列表 var must_open_flag_list_remark = string.Empty; var exist_must_open_flag_list = must_open_flag_list != null && must_open_flag_list.Count > 0; if (exist_must_open_flag_list) { must_open_flag_list = must_open_flag_list.OrderBy(x => x).ToList(); must_open_flag_list_remark = IntListHelper.ToString(must_open_flag_list); } #endregion #region 存在-必关泵列表 var exist_must_close_flag_list = must_close_flag_list != null && must_close_flag_list.Count > 0; #endregion #region 存在-禁用组合 var exist_forbidden_flag_combine_list = forbidden_flag_combine_list != null && forbidden_flag_combine_list.Count > 0; #endregion #region 存在-关联组合 var exist_associative_flag_combine_list = associative_flag_combine_list != null && associative_flag_combine_list.Count > 0; #endregion #region 存在-同段泵组合 Dictionary> same_section_combine_dict = new(); var exist_same_section_flag_combine_list = _same_section_flag_combine_list != null && _same_section_flag_combine_list.Count > 0; #endregion #region 存在-供水限制 var exist_water_supply_limit_list = water_supply_limit_list != null && water_supply_limit_list.Count > 0; #endregion #region 存在-频率限制 var frequency_limit_flag_dict = new Dictionary(); var exist_frequency_limit_list = frequency_limit_list != null && frequency_limit_list.Count > 0; if (exist_frequency_limit_list) { frequency_limit_flag_dict = frequency_limit_list.ToDictionary(x => x.Flag, x => x); } #endregion #region 存在-优先度排序 暂未考虑 // var exist_priority_order_flag_list = priority_order_flag_list != null && priority_order_flag_list.Count > 0; #endregion var pump_bp_dict = pumps.ToDictionary(x => x.Flag, x => x.IsBp); var pump_nr_dict = pumps.ToDictionary(x => x.Flag, x => x.Nr); var pump_flag_list = pumps.Select(x => x.Flag).ToList(); var optimal_combine_list = new List(); var combine = new int[] { 11, 12, 14, 15, 17 }; if (station == 2) { combine = new int[] { 23, 24, 25 }; } double combine_merit_ratio = 1;//组合择优率 //必开 if (exist_must_open_flag_list) { var combine_remark = IntListHelper.ToString(combine.OrderBy(x => x)); if (!combine_remark.Contains(must_open_flag_list_remark)) return default; } //必关 if (exist_must_close_flag_list) { var exist_intersected = combine.Intersect(must_close_flag_list).Count() > 0; if (exist_intersected) return default; } //禁用组合 if (exist_forbidden_flag_combine_list) { var exist_equal = false; foreach (var flag_list in forbidden_flag_combine_list) { if (combine.SequenceEqual(flag_list)) { exist_equal = true; break; } } if (exist_equal) return default; } //关联组合 if (exist_associative_flag_combine_list) { var exist_intersected = false; foreach (var flag_list in associative_flag_combine_list) { var except_count = combine.Except(flag_list).Count(); if (except_count != flag_list.Count && except_count > 0) { exist_intersected = true; } } if (exist_intersected) return default; } int start_stop_count = 0;//启停数量 if (exist_current_open_flag_list) { var start_pump_count = combine.Except(current_open_flag_list).Count(); var close_pump_count = current_open_flag_list.Except(combine).Count(); start_stop_count = start_pump_count + close_pump_count;//启停数量 } else { start_stop_count = combine.Count(); if (exist_must_open_flag_list) { start_stop_count = combine.Except(must_open_flag_list).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 combine_flag_list_part2 = new(); foreach (var pump in combine) { if (flags.Contains(pump)) { combine_flag_list_part1.Add(pump); } else { combine_flag_list_part2.Add(pump); } } //区分同型号泵 List fre_combine_list_part1 = new(); List fre_combine_list_part2 = new(); var combine_correction_factor_dict = GetCombineCorrectionFactor(station,combine); if (combine_flag_list_part1.Count > 0) { var conclusion_list_dic = new Dictionary>(); foreach (var flag in combine_flag_list_part1) { var runFlag = RunFlagHelper.GetRunFlag(flag, pump_bp_dict[flag]); if (conclusion_list_dic.ContainsKey(flag)) return default; var combine_correction_factor = combine_correction_factor_dict[flag]; var current_target_head = target_head + combine_correction_factor; current_target_head = Math.Round(current_target_head, 1); //频率限制 var conclusionList = new List(); if (exist_frequency_limit_list && frequency_limit_flag_dict.ContainsKey(flag)) { var limit = frequency_limit_flag_dict[flag]; conclusionList = _service_analysis_conclusion.GetList(runFlag, limit.Min, limit.Max, current_target_head); } else { conclusionList = _service_analysis_conclusion.GetList(runFlag, current_target_head); } conclusion_list_dic[flag] = conclusionList; } if (conclusion_list_dic.Count < 1) return default; for (decimal fre = _frequency_max; fre >= _frequency_min; fre -= _frequency_space) { var freCombine = new AnaFreCombine(); freCombine.Frequency = (double)fre; freCombine.Flags = new List(); freCombine.FrePumps = 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++; var fre_pump = new AnaFrePump(); fre_pump.Flag = item.Key; fre_pump.Flow = conclusion.Flow; fre_pump.Head = conclusion.Head; fre_pump.Power = conclusion.Power; fre_pump.Efficiency = Curve.PumpCalculateHelper.CalculateE(fre_pump.Flow, fre_pump.Head, fre_pump.Power); fre_pump.Frequency = freCombine.Frequency; fre_pump.Speed = (double)fre / 50 * pump_nr_dict[item.Key]; freCombine.FrePumps.Add(fre_pump); } } 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 = RunFlagHelper.GetRunFlag(flag, pump_bp_dict[flag]); if (conclusion_list_dic.ContainsKey(flag)) return default; var combine_correction_factor = combine_correction_factor_dict[flag]; var current_target_head = target_head + combine_correction_factor; current_target_head = Math.Round(current_target_head, 1); //频率限制 var conclusionList = new List(); if (exist_frequency_limit_list && frequency_limit_flag_dict.ContainsKey(flag)) { var limit = frequency_limit_flag_dict[flag]; conclusionList = _service_analysis_conclusion.GetList(runFlag, limit.Min, limit.Max, current_target_head); } else { conclusionList = _service_analysis_conclusion.GetList(runFlag, current_target_head); } conclusion_list_dic[flag] = conclusionList; } if (conclusion_list_dic.Count < 1) { return default; } for (decimal fre = _frequency_max; fre >= _frequency_min; fre -= _frequency_space) { var freCombine = new AnaFreCombine(); freCombine.Frequency = (double)fre; freCombine.Flags = new List(); freCombine.FrePumps = 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++; var fre_pump = new AnaFrePump(); fre_pump.Flag = item.Key; fre_pump.Flow = conclusion.Flow; fre_pump.Head = conclusion.Head; fre_pump.Power = conclusion.Power; fre_pump.Efficiency = Curve.PumpCalculateHelper.CalculateE(fre_pump.Flow, fre_pump.Head, fre_pump.Power); fre_pump.Frequency = freCombine.Frequency; fre_pump.Speed = (double)fre / 50 * pump_nr_dict[item.Key]; freCombine.FrePumps.Add(fre_pump); } } 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) return default; double total_flow_deviation = target_flow;//总流量偏差 double total_power = double.MaxValue;//总功率 double total_flow = double.MaxValue;//总流量 AnaFreCombine optimal_combine_part1 = null; AnaFreCombine 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 (total_flow < target_flow * 0.99) return default; if (optimal_combine_part1 == null && optimal_combine_part2 == null) return default; var total_flow_deviation_ratio = Math.Abs((1 - Math.Abs((total_flow / target_flow)))); if (total_flow_deviation_ratio > _sel_opt_flow_deviation_ratio) return default; if (total_flow_deviation_ratio > _sel_opt_reasonable_flow_deviation_ratio) { combine_merit_ratio -= total_flow_deviation_ratio; } var efficiency = Curve.PumpCalculateHelper.CalculateE(total_flow, target_head, total_power); var wp = Curve.PumpCalculateHelper.CalculateWP(total_power, total_flow); var uwp = Curve.PumpCalculateHelper.CalculateUWP(total_power, total_flow, target_head); #region 分析最优组合方案 var optimal_combine = new AnaOptimalCombine(); 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.Head = target_head; optimal_combine.Power = total_power; optimal_combine.Efficiency = efficiency; optimal_combine.WP = wp; optimal_combine.UWP = uwp; 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_list.Add(optimal_combine); #endregion if (optimal_combine_list.Count < 1) return default; optimal_combine_list = optimal_combine_list.OrderByDescending(x => x.MeritRatio).ToList(); var opt = optimal_combine_list.First(); opt.Round(); return opt; } /// /// 获取排列组合 /// /// /// /// private List GetCombineList(List flags, int count) { var combine = IStation.Curve.PermutationAndCombination.GetCombination(flags.ToArray(), count); return combine; } /// /// 获取组合修正系数 /// /// /// private Dictionary GetCombineCorrectionFactor(int station,IEnumerable flags) { var correction_factor_dict = new Dictionary(); //if (station==1) //{ // correction_factor_dict.Add(11, 1.22); // correction_factor_dict.Add(12, 1.35); // correction_factor_dict.Add(14, 0.9); // correction_factor_dict.Add(15, 0.73); // correction_factor_dict.Add(17, 1.38); //} //else //{ // correction_factor_dict.Add(23, 0.51); // correction_factor_dict.Add(24, 0.81); // correction_factor_dict.Add(25, 0.75); //} foreach (var item in flags) { correction_factor_dict.Add(item,0); } return correction_factor_dict; } /// /// 根据工况计算 /// /// /// /// /// /// /// public AnaOptimalCombine WorkingCalc(List pumps, Dictionary flag_rpm_dic, Dictionary flag_head_dic, double target_flow, double target_head) { if (pumps == null || !pumps.Any()) { return default; } if (flag_rpm_dic == null || !flag_rpm_dic.Any()) { return default; } target_flow = Math.Round(target_flow, 1); target_head = Math.Round(target_head, 1); var freCombine = new AnaFreCombine(); freCombine.FrePumps = new List(); foreach (var item in flag_rpm_dic) { var pump = pumps.Find(x => x.Flag == item.Key); if (pump == null) return default; var rpm = Math.Round(item.Value, 1); if (rpm == 0) return default; var curveQH = Curve.PumpCalculateHelper.CalculateSimilarQH(pump.CurveQH, pump.Nr, rpm); var curveQP = Curve.PumpCalculateHelper.CalculateSimilarQP(pump.CurveQP, pump.Nr, rpm); double flow = 0, head = target_head; if (flag_head_dic != null && flag_head_dic.ContainsKey(pump.Flag)) head = flag_head_dic[pump.Flag]; flow = curveQH.GetInterPointLastX(head) ?? 0; if (flow < 0) return default; var fre_pump = new AnaFrePump(); fre_pump.Flag = item.Key; fre_pump.Flow = flow; fre_pump.Head = target_head; fre_pump.Power = curveQP.GetFitPointY(flow); fre_pump.Efficiency = Curve.PumpCalculateHelper.CalculateE(fre_pump.Flow, fre_pump.Head, fre_pump.Power); fre_pump.Frequency = rpm; fre_pump.Speed = (double)rpm / 50 * pump.Nr; freCombine.FrePumps.Add(fre_pump); freCombine.Flow += flow; freCombine.Power += fre_pump.Power; } var total_flow = freCombine.Flow; var total_power = freCombine.Power; var efficiency = Curve.PumpCalculateHelper.CalculateE(total_flow, target_head, total_power); var wp = Curve.PumpCalculateHelper.CalculateWP(total_power, total_flow); var uwp = Curve.PumpCalculateHelper.CalculateUWP(total_power, total_flow, target_head); var opt = new AnaOptimalCombine(); opt.Combines = new List() { freCombine }; opt.Flags = new List(); opt.Flow = total_flow; opt.Head = target_head; opt.Power = total_power; opt.Efficiency = efficiency; opt.WP = wp; opt.UWP = uwp; opt.Flags = opt.Flags.OrderBy(x => x).ToList(); opt.FlagCount = opt.Flags.Count; opt.Remark = IntListHelper.ToString(opt.Flags); opt.MeritRatio = 1; opt.Round(); return opt; } } }