namespace PBS.WinFrmUI.Hydro { /// /// 调度分析辅助类 /// public partial class ScheduleHelper { #region ViewModel private class AnalysisConclusionViewModel : AnalysisParameter { public AnalysisConclusionViewModel() { } public AnalysisConclusionViewModel(AnalysisParameter rhs) : base(rhs) { } public AnalysisConclusionViewModel(AnalysisParameter rhs, long flag) : base(rhs) { this.Flag = flag; } public long Flag { get; set; } } #endregion #region Private Variable private readonly decimal _frequency_min = 25; private readonly decimal _frequency_max = 50; private readonly decimal _frequency_space = 1;//频率间隔 private double _sel_opt_flow_excess = 1;//可选方案的流量余量 private readonly double _sel_opt_pump_pressure_excess = 0;//可选方案的单泵扬程默认抬升余量 private double _sel_opt_flow_deviation_ratio = 0.05;//可选方案的流量偏差比 private readonly double _sel_opt_reasonable_flow_deviation_ratio = 0.005;//合理的方案的流量偏差比 private int _min_open_count;//最小开泵数量 private int _max_open_count;//最大开泵数量 private List _current_open_flag_list = null;// 当前开泵列表 private List _must_open_flag_list = null; // 必开泵列表 private List _must_close_flag_list = null; // 必关泵列表 private AnalysisParameterService _service_analysis_parameter = new AnalysisParameterService(); #endregion /// /// 初始化 /// public void Initial(int min_open_count,int max_open_count) { _current_open_flag_list = null; _min_open_count = min_open_count; _max_open_count = max_open_count; _must_open_flag_list = null; _must_close_flag_list = null; } #region OptAnaCombine /// /// 获取最优组合 /// /// /// /// /// /// public async Task GetOptAnaCombine ( long Id, List pump_list, double target_flow, double target_pressure ) { #region 初始化参数 if (pump_list == null || !pump_list.Any()) { return default; } var current_open_flag_list = _current_open_flag_list; var min_open_count = _min_open_count; var max_open_count = _max_open_count < 1 ? pump_list.Count : _max_open_count; var must_open_flag_list = _must_open_flag_list; var must_close_flag_list = _must_close_flag_list; var pump_bp_dict = pump_list.ToDictionary(x => x.ID, x=>true); var pump_nr_dict = pump_list.ToDictionary(x => x.ID, x => x.RatedSpeed); var pump_flag_list = pump_list.Select(x => x.ID).ToList(); var combine_merit_ratio = 1d;//组合择优率 target_flow = Math.Round(target_flow, 1); target_pressure = Math.Round(target_pressure, 1); #endregion #region 初始化规则 #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 #endregion #region 调度分析 var opt_ana_combine_list = new List(); for (int pump_count = min_open_count; pump_count <= max_open_count; pump_count++) { if (pump_count == 1) { var max_total_flow = pump_list.Max(x => x.RatedFlow); if (max_total_flow < target_flow) continue; } var combine_list = GetCombineList(pump_flag_list, pump_count);//排列组合 foreach (var combine in combine_list) { combine_merit_ratio = 1; #region 规则过滤 //必开 if (exist_must_open_flag_list) { var combine_remark = LongListHelper.ToString(combine.OrderBy(x => x)); if (!combine_remark.Contains(must_open_flag_list_remark)) continue; } #endregion var opt_ana_combine = await GetOptAnaCombine ( Id, combine, combine_merit_ratio, pump_nr_dict, pump_bp_dict, target_flow, target_pressure ); if (opt_ana_combine == null) continue; opt_ana_combine_list.Add(opt_ana_combine); } //如果当前循环已经满足,不需要再加泵 if (opt_ana_combine_list.Any()) { break; } } if (opt_ana_combine_list.Count < 1) return default; opt_ana_combine_list = opt_ana_combine_list.OrderBy(x => x.TotalPower).OrderByDescending(x => x.MeritRatio).ToList(); var opt = opt_ana_combine_list.First(); opt.Round(); return opt; #endregion } /// /// 获取最优组合 /// /// /// /// /// /// /// /// /// private async Task GetOptAnaCombine ( long Id, IEnumerable combine, double combine_merit_ratio, Dictionary pump_nr_dict, Dictionary pump_bp_dict, double target_flow, double target_pressure ) { if (combine == null || !combine.Any()) return default; //先修正组合曲线和模型的偏差扬程 var conclusion_ex_list_list = new List>(); var conclusion_ex_list_dict = new Dictionary>(); double max_supply_flow = 0; foreach (var flag in combine) { //进口水位 var inlet_water_level = 0; var current_pressure_diff = target_pressure - inlet_water_level + _sel_opt_pump_pressure_excess; current_pressure_diff = Math.Round(current_pressure_diff, 1); var conclusion_list = await _service_analysis_parameter.GetList(Id, flag, 38, 50, current_pressure_diff); if (conclusion_list == null || !conclusion_list.Any()) { break; } max_supply_flow += conclusion_list.Max(x => x.Flow); var conclusion_ex_list = conclusion_list.Select(x => new AnalysisConclusionViewModel(x, flag)).ToList(); conclusion_ex_list_list.Add(conclusion_ex_list); conclusion_ex_list_dict[flag] = conclusion_ex_list; } if (conclusion_ex_list_list.Count != combine.Count()) return default; if (max_supply_flow < target_flow * _sel_opt_flow_excess) { 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); if (opt_ana_combine == null) return default; var total_flow = opt_ana_combine.TotalFlow; var total_power = opt_ana_combine.TotalPower; if (total_flow < target_flow * _sel_opt_flow_excess) 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; //} double eff = 0, wp = 0, uwp = 0; wp = Yw.Pump.CalculationHelper.CalcuWP(total_power, total_flow); foreach (var ana_pump in opt_ana_combine.AnaFrePumps) { var pump_flow = ana_pump.Flow; var pump_eff = ana_pump.Eff; var pump_uwp = ana_pump.UWP; eff += pump_eff * pump_flow / total_flow; uwp += pump_uwp * pump_flow / total_flow; } opt_ana_combine.TotalFlow = total_flow; opt_ana_combine.TotalPressure = target_pressure; opt_ana_combine.TotalPower = total_power; opt_ana_combine.TotalEfficiency = eff; opt_ana_combine.WP = wp; opt_ana_combine.UWP = uwp; opt_ana_combine.MeritRatio = combine_merit_ratio; return opt_ana_combine; } /// /// 获取最优组合 /// /// /// /// /// /// private AnaCombine GetOptAnaCombine( Dictionary> conclusion_ex_list_dict, Dictionary pump_nr_dict, Dictionary pump_bp_dict, double target_flow ) { if (conclusion_ex_list_dict == null || !conclusion_ex_list_dict.Any()) return default; var frequency_min = (double)_frequency_min; var frequency_max = (double)_frequency_max; var frequency_space = (double)_frequency_space; var all_fre_conclusion_ex_list_list = new List>(); var all_fix_conclusion_ex_list_list = new List>(); foreach (var item in conclusion_ex_list_dict) { var flag = item.Key; var cl_list = item.Value; if (pump_bp_dict[flag]) { all_fre_conclusion_ex_list_list.Add(cl_list); } else { all_fix_conclusion_ex_list_list.Add(cl_list); } } var cl_ex_list_list_list = new List>>(); //默认1hz内能求出满足目标需求的排列组合,不满足继续迭代 var frequency_iteration_count = 5;//频率迭代次数 var frequency_iteration_space = 1d;//频率迭代间隔 for (int i = 0; i < frequency_iteration_count; i++) { var current_frequency_space = frequency_space + (i * frequency_iteration_space); cl_ex_list_list_list = FrequencyFilters(target_flow, frequency_min, frequency_max, current_frequency_space, all_fre_conclusion_ex_list_list, all_fix_conclusion_ex_list_list); if (cl_ex_list_list_list.Any()) { break; } } if (!cl_ex_list_list_list.Any()) { return default; } //分组排列组合求最优 var ana_combine_list = new List(); foreach (var item_cl_ex_list_list in cl_ex_list_list_list) { var cl_ex_list_list = CartesianProduct(item_cl_ex_list_list, target_flow); var opt_cl_ex_list = cl_ex_list_list.OrderBy(x => x.Sum(x => x.Power)).FirstOrDefault(); if (opt_cl_ex_list != null && opt_cl_ex_list.Any()) { var ana_combine = new AnaCombine(); ana_combine.Flags = new List(); ana_combine.AnaFrePumps = new List(); foreach (var opt_cl_ex in opt_cl_ex_list) { var flag = opt_cl_ex.Flag; ana_combine.Flags.Add(flag); ana_combine.TotalFlow += opt_cl_ex.Flow; ana_combine.TotalPower += opt_cl_ex.Power; var ana_fre_pump = new AnaFrePump(); 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; ana_fre_pump.Power = opt_cl_ex.Power; ana_fre_pump.Eff = Yw.Pump.CalculationHelper.CalcuE(ana_fre_pump.Flow, ana_fre_pump.Head, ana_fre_pump.Power); ana_fre_pump.WP = Yw.Pump.CalculationHelper.CalcuWP(ana_fre_pump.Power, ana_fre_pump.Flow); ana_fre_pump.UWP = Yw.Pump.CalculationHelper.CalcuUWP(ana_fre_pump.Power, ana_fre_pump.Flow, ana_fre_pump.Head); ana_fre_pump.Frequency = opt_cl_ex.Hz; ana_fre_pump.Speed = opt_cl_ex.Hz / 50 * pump_nr_dict[flag]; ana_combine.AnaFrePumps.Add(ana_fre_pump); } ana_combine.FlagCount = opt_cl_ex_list.Count; ana_combine.Remark = LongListHelper.ToString(ana_combine.Flags); ana_combine_list.Add(ana_combine); } } if (!ana_combine_list.Any()) return default; var opt_ana_combine = ana_combine_list.OrderBy(x => x.TotalPower).First(); return opt_ana_combine; } /// /// 过滤频率分组 /// /// /// /// /// /// /// /// private List>> FrequencyFilters( double target_flow, double frequency_min, double frequency_max, double frequency_space, List> all_fre_conclusion_ex_list_list, List> all_fix_conclusion_ex_list_list) { double fix_total_flow = 0; var exist_all_fix_conclusion_ex_list_list = all_fix_conclusion_ex_list_list.Any(); if (exist_all_fix_conclusion_ex_list_list) { fix_total_flow = all_fix_conclusion_ex_list_list.Sum(x => x.Sum(x => x.Flow)); } //频率按间隔分组 var cl_ex_list_list_list = new List>>(); for (double fre_current_min = frequency_min; fre_current_min <= frequency_max; fre_current_min++) { var fre_current_max = fre_current_min + frequency_space; var skip_current = false; var total_flow_current = 0d; var cl_ex_list_list = new List>(); foreach (var conclusion_ex_list in all_fre_conclusion_ex_list_list) { var cl_ex_list = conclusion_ex_list.Where(x => x.Hz <= fre_current_max && x.Hz >= fre_current_min).ToList(); if (cl_ex_list == null || !cl_ex_list.Any()) { skip_current = true; break; } total_flow_current += cl_ex_list.Max(x => x.Flow); cl_ex_list_list.Add(cl_ex_list); } if (skip_current) continue; if (exist_all_fix_conclusion_ex_list_list) { total_flow_current += fix_total_flow; cl_ex_list_list.AddRange(all_fix_conclusion_ex_list_list); } if (total_flow_current < target_flow * _sel_opt_flow_excess) continue; cl_ex_list_list_list.Add(cl_ex_list_list); } return cl_ex_list_list_list; } /// /// 获取排列组合列表(笛卡尔乘积) /// private List> CartesianProduct(List> lstSplit, double target_flow) { long count = 1; lstSplit.ForEach(item => count *= item.Count); var lstResult = new List>(); for (long i = 0; i < count; ++i) { var lstTemp = new List(); long j = 1; var lstFre = new List(); double totalFlow = 0; lstSplit.ForEach(item => { j *= item.Count; var index = (i / (count / j)) % item.Count; var index_int = (int)index; var obj = item[index_int]; totalFlow += obj.Flow; lstTemp.Add(obj); }); if (totalFlow < target_flow * _sel_opt_flow_excess) continue; lstResult.Add(lstTemp); } return lstResult; } /// /// 获取排列组合 /// /// /// /// private List GetCombineList(List flags, int count) { var combine = PermutationAndCombination.GetCombination(flags.ToArray(), count); return combine; } #endregion } }