| | |
| | | using IStation.Application; |
| | | using IStation.Model; |
| | | |
| | | namespace IStation.Service |
| | | namespace IStation.Service |
| | | { |
| | | /// <summary> |
| | | /// 调度分析辅助类 |
| | |
| | | } |
| | | public int Flag { get; set; } |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region Private Variable |
| | |
| | | private readonly decimal _frequency_max = 50; |
| | | private readonly decimal _frequency_space = 1;//频率间隔 |
| | | |
| | | private readonly double _start_stop_loss_coefficient = 0.95;//泵启停损失系数 |
| | | private readonly double _start_stop_loss_coefficient = 0.9;//泵启停损失系数 |
| | | |
| | | private double _sel_opt_flow_excess = 1;//可选方案的流量余量 |
| | | private readonly double _sel_opt_pump_pressure_excess = 0;//可选方案的单泵扬程默认抬升余量 |
| | | private double _station_target_flow_diff = 0; // 站点目标流量差值 |
| | | |
| | | private readonly double _sel_opt_flow_deviation_ratio = 0.05;//可选方案的流量偏差比 |
| | | |
| | | private readonly double _sel_opt_flow_deviation_ratio = 0.08;//可选方案的流量偏差比 |
| | | private readonly double _sel_opt_reasonable_flow_deviation_ratio = 0.005;//合理的方案的流量偏差比 |
| | | |
| | | private readonly Service.AnalysisParameter _service_analysis_conclusion = new(); |
| | | private readonly Service.AnalysisDeviation _service_analysis_deviation = new(); |
| | | private readonly Service.AnalysisFactor _service_analysis_factor = new(); |
| | | private readonly Service.AnalysisParameter _service_analysis_parameter = new(); |
| | | |
| | | private int _min_open_count;//最小开泵数量 |
| | | private int _max_open_count;//最大开泵数量 |
| | | private List<int> _current_open_flag_list = null;// 当前开泵列表 |
| | | private List<int> _must_open_flag_list = null; // 必开泵列表 |
| | | private List<int> _must_close_flag_list = null; // 必关泵列表 |
| | | private List<int> _must_close_flag_list = null; // 必关泵列表 |
| | | private List<List<int>> _forbidden_flag_combine_list = null; // 禁用泵组合 |
| | | private List<List<int>> _associative_flag_combine_list = null; // 关联泵组合 |
| | | private List<List<int>> _same_section_flag_combine_list = null; // 同段泵组合 |
| | | private List<Model.WaterSupplyLimit> _water_supply_limit_list = null; //供水限制列表 |
| | | private List<Model.FrequencyLimit> _frequency_limit_list = null; // 频率限制列表 |
| | | private Dictionary<int, double> _flag_cumulative_runtime_dict = null; // 泵累计运行时长字典 |
| | | private List<int> _priority_open_flag_list = null; // 优先开泵列表 |
| | | private List<int> _maintenance_flag_list = null; // 检修列表 |
| | | |
| | | |
| | | |
| | | private List<Model.AnalysisDeviation> _analysis_deviation_list = null;//分析偏差 |
| | | |
| | | |
| | | |
| | | #endregion |
| | | |
| | | /// <summary> |
| | | /// 初始化 |
| | | /// </summary> |
| | | public void Initial(List<int> current_open_flag_list, Model.ScheduleConfig schedule_config, List<Model.AnalysisDeviation> analysis_deviation_list) |
| | | public void Initial(List<int> current_open_flag_list, Model.ScheduleConfig schedule_config, List<Model.AnalysisDeviation> analysis_deviation_list, double station_target_flow_diff = 0) |
| | | { |
| | | |
| | | _current_open_flag_list = current_open_flag_list; |
| | | _min_open_count = 1; |
| | | _max_open_count = 0; |
| | |
| | | _water_supply_limit_list = null; |
| | | _frequency_limit_list = null; |
| | | _flag_cumulative_runtime_dict = null; |
| | | _priority_open_flag_list = null; |
| | | _maintenance_flag_list = null; |
| | | _station_target_flow_diff = 0; |
| | | if (schedule_config != null) |
| | | { |
| | | _min_open_count = schedule_config.MinOpenCount; |
| | |
| | | _water_supply_limit_list = schedule_config.WaterSupplyLimitList; |
| | | _frequency_limit_list = schedule_config.FrequencyLimitList; |
| | | _flag_cumulative_runtime_dict = schedule_config.FlagCumulativeRuntimeDict; |
| | | _priority_open_flag_list = schedule_config.PriorityOpenFlagList; |
| | | _maintenance_flag_list = schedule_config.MaintenanceFlagList; |
| | | } |
| | | |
| | | _analysis_deviation_list = analysis_deviation_list; |
| | | |
| | | _station_target_flow_diff = station_target_flow_diff; |
| | | } |
| | | |
| | | |
| | | #region OptAnaCombine |
| | | |
| | | |
| | | /// <summary> |
| | | /// 获取最优组合 |
| | |
| | | /// <returns></returns> |
| | | public AnaCombine GetOptAnaCombine |
| | | ( |
| | | List<Model.Pump> pump_list, |
| | | List<Model.Pump> pump_list, |
| | | Dictionary<int, double> flag_inlet_water_level_dict, |
| | | double target_flow, |
| | | double target_pressure |
| | | ) |
| | | { |
| | | |
| | | //获取方案时用补差的流量,供水限制用目标流量判断 |
| | | var target_flow_compensation = target_flow + _station_target_flow_diff; |
| | | #region 初始化参数 |
| | | if (pump_list == null || !pump_list.Any()) |
| | | { |
| | |
| | | var water_supply_limit_list = _water_supply_limit_list; |
| | | var frequency_limit_list = _frequency_limit_list; |
| | | var flag_cumulative_runtime_dict = _flag_cumulative_runtime_dict; |
| | | var priority_open_flag_list = _priority_open_flag_list; |
| | | var maintenance_flag_list = _maintenance_flag_list; |
| | | |
| | | var pump_bp_dict = pump_list.ToDictionary(x => x.Flag, x => x.IsBp); |
| | | var pump_nr_dict = pump_list.ToDictionary(x => x.Flag, x => x.Nr); |
| | |
| | | var combine_merit_ratio = 1d;//组合择优率 |
| | | |
| | | target_flow = Math.Round(target_flow, 1); |
| | | target_flow_compensation = Math.Round(target_flow_compensation,1); |
| | | target_pressure = Math.Round(target_pressure, 1); |
| | | |
| | | #endregion |
| | |
| | | { |
| | | var water_supply_min = water_supply_limit_list.Min(x => x.Min); |
| | | var water_supply_max = water_supply_limit_list.Max(x => x.Max); |
| | | |
| | | #if DEBUG |
| | | water_supply_min = 0; |
| | | #endif |
| | | if (target_flow < water_supply_min || target_flow > water_supply_max) |
| | | { |
| | | return default; |
| | |
| | | } |
| | | #endregion |
| | | |
| | | #region 存在-优先开泵列表 |
| | | |
| | | var priority_open_flag_list_remark = string.Empty; |
| | | var exist_priority_open_flag_list = priority_open_flag_list != null && priority_open_flag_list.Count > 0; |
| | | if (exist_priority_open_flag_list) |
| | | { |
| | | priority_open_flag_list = priority_open_flag_list.OrderBy(x => x).ToList(); |
| | | priority_open_flag_list_remark = IntListHelper.ToString(priority_open_flag_list); |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | #region 存在-检修列表 |
| | | |
| | | var exist_maintenance_flag_list = maintenance_flag_list != null && maintenance_flag_list.Count > 0; |
| | | |
| | | #endregion |
| | | |
| | | #region 存在-当前开泵列表 (是否切泵) |
| | | |
| | | var exist_current_open_flag_list = current_open_flag_list != null && current_open_flag_list.Count > 0; |
| | |
| | | { |
| | | if (target_flow < limit.Min || target_flow > limit.Max) |
| | | { |
| | | exist_limit = true; |
| | | exist_limit = true; |
| | | } |
| | | } |
| | | } |
| | |
| | | pump_bp_dict, |
| | | exist_frequency_limit_list, |
| | | frequency_limit_flag_dict, |
| | | target_flow, |
| | | target_flow_compensation, |
| | | target_pressure |
| | | ); |
| | | if (opt_ana_combine != null) |
| | | if (opt_ana_combine != null) |
| | | return opt_ana_combine; |
| | | } |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | |
| | | #endregion |
| | | |
| | |
| | | if (exist_intersected) |
| | | continue; |
| | | } |
| | | |
| | | |
| | | //禁用组合 |
| | | if (exist_forbidden_flag_combine_list) |
| | |
| | | } |
| | | } |
| | | |
| | | //优先开泵列表 |
| | | if (exist_priority_open_flag_list) |
| | | { |
| | | //目前逻辑 优先开泵==必开方案 |
| | | var combine_remark = IntListHelper.ToString(combine.OrderBy(x => x)); |
| | | if (!combine_remark.Contains(priority_open_flag_list_remark)) |
| | | continue; |
| | | } |
| | | |
| | | //检修列表 |
| | | if (exist_maintenance_flag_list) |
| | | { |
| | | var exist_intersected = combine.Intersect(maintenance_flag_list).Count() > 0; |
| | | if (exist_intersected) |
| | | continue; |
| | | } |
| | | |
| | | |
| | | #endregion |
| | | |
| | | var total_loss_ratio = Math.Pow(_start_stop_loss_coefficient, start_stop_count);//启停一次损失些能耗 |
| | |
| | | pump_bp_dict, |
| | | exist_frequency_limit_list, |
| | | frequency_limit_flag_dict, |
| | | target_flow, |
| | | target_flow_compensation, |
| | | target_pressure |
| | | ); |
| | | if (opt_ana_combine == null) |
| | |
| | | opt_ana_combine_list.Add(opt_ana_combine); |
| | | } |
| | | |
| | | // 20250422 注释原因:供水范围会有重叠,考虑切泵操作 |
| | | //如果当前循环已经满足,不需要再加泵 |
| | | if (opt_ana_combine_list.Any()) |
| | | { |
| | | break; |
| | | } |
| | | //if (opt_ana_combine_list.Any()) |
| | | //{ |
| | | // break; |
| | | //} |
| | | } |
| | | |
| | | if (opt_ana_combine_list.Count < 1) |
| | |
| | | |
| | | //先修正组合曲线和模型的偏差扬程 |
| | | var combine_deviation_factor_dict = GetCombineDeviationFactorDict(target_flow, combine); |
| | | |
| | | if (GlobalHelper.IsStation1(combine)) |
| | | { |
| | | var err_combine = new List<Tuple<double, List<int>>>() |
| | | { |
| | | new (23500, new List<int>(){12,13,14,15,17 }) |
| | | }; |
| | | |
| | | var exist_err_combine = err_combine.Find(x => x.Item2.SequenceEqual(combine)); |
| | | if (exist_err_combine != null) |
| | | { |
| | | ScheduleLog.Info(-1, "测试", $"目标:{target_pressure}"); |
| | | if (target_flow > exist_err_combine.Item1) |
| | | { |
| | | var dev_diff = 0.5; |
| | | foreach (var flag in combine) |
| | | { |
| | | var dev_pressure = combine_deviation_factor_dict[flag]; |
| | | combine_deviation_factor_dict[flag] = dev_pressure - dev_diff; |
| | | //combine_deviation_factor_dict[flag] = 0; |
| | | ScheduleLog.Info(-1, "测试", $"{flag}#:压力偏差{dev_pressure}-{dev_diff}={dev_pressure - dev_diff:N4}"); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | else |
| | | { |
| | | //var err_combine = new List<Tuple<double, List<int>>>() |
| | | //{ |
| | | // new (29000, new List<int>(){22,23,26}) |
| | | //}; |
| | | //var exist_err_combine = err_combine.Find(x => x.Item2.SequenceEqual(combine)); |
| | | //if (exist_err_combine != null) |
| | | //{ |
| | | // ScheduleLog.Info(-1, "测试", $"目标:{target_pressure}"); |
| | | // if (target_flow > exist_err_combine.Item1) |
| | | // { |
| | | // foreach (var flag in combine) |
| | | // { |
| | | |
| | | // combine_deviation_factor_dict[flag] = 0; |
| | | // ScheduleLog.Info(-1, "测试", $"{flag}#:压力偏差{0}"); |
| | | // } |
| | | // } |
| | | //} |
| | | } |
| | | |
| | | var conclusion_ex_list_list = new List<List<AnalysisConclusionViewModel>>(); |
| | | var conclusion_ex_list_dict = new Dictionary<int, List<AnalysisConclusionViewModel>>(); |
| | | double max_supply_flow = 0; |
| | |
| | | |
| | | //组合偏差系数 |
| | | var combine_deviation_factor = combine_deviation_factor_dict[flag]; |
| | | var current_pressure_diff = target_pressure - inlet_water_level + combine_deviation_factor + _sel_opt_pump_pressure_excess; |
| | | var current_pressure_diff = target_pressure - inlet_water_level - combine_deviation_factor + _sel_opt_pump_pressure_excess; |
| | | |
| | | current_pressure_diff = Math.Round(current_pressure_diff, 1); |
| | | |
| | | //频率限制 |
| | |
| | | if (exist_frequency_limit_list && frequency_limit_flag_dict.ContainsKey(flag)) |
| | | { |
| | | var limit = frequency_limit_flag_dict[flag]; |
| | | conclusion_list = _service_analysis_conclusion.GetList(run_flag, limit.Min, limit.Max, current_pressure_diff); |
| | | conclusion_list = _service_analysis_parameter.GetList(run_flag, limit.Min, limit.Max, current_pressure_diff); |
| | | } |
| | | else |
| | | { |
| | | |
| | | //定频泵 可能最小压差超过目标压差 |
| | | var min_pressure_diff_conclusion = _service_analysis_conclusion.GetMinPressureDiff(run_flag); |
| | | var min_pressure_diff_conclusion = _service_analysis_parameter.GetMinPressureDiff(run_flag); |
| | | if (min_pressure_diff_conclusion != null && min_pressure_diff_conclusion.PressureDiff > current_pressure_diff) |
| | | { |
| | | conclusion_list = new List<Model.AnalysisParameter>() { min_pressure_diff_conclusion }; |
| | |
| | | var is_bp = pump_bp_dict[flag]; |
| | | if (is_bp) |
| | | { |
| | | conclusion_list = _service_analysis_conclusion.GetList(run_flag, current_pressure_diff); |
| | | conclusion_list = _service_analysis_parameter.GetList(run_flag, current_pressure_diff); |
| | | } |
| | | else |
| | | { |
| | | conclusion_list = new List<Model.AnalysisParameter>() { min_pressure_diff_conclusion }; |
| | | var list = _service_analysis_parameter.GetList(run_flag); |
| | | conclusion_list = _service_analysis_parameter.GetList(run_flag, current_pressure_diff); |
| | | } |
| | | } |
| | | } |
| | |
| | | } |
| | | |
| | | if (conclusion_ex_list_list.Count != combine.Count()) |
| | | return default; |
| | | return default; |
| | | |
| | | if (max_supply_flow < target_flow * _sel_opt_flow_excess) |
| | | { |
| | | if (GlobalHelper.IsStation1(combine)) |
| | | { |
| | | _sel_opt_flow_excess= 0.995; |
| | | _sel_opt_flow_excess = 0.97; |
| | | } |
| | | 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); |
| | |
| | | ana_combine.TotalPower += opt_cl_ex.Power; |
| | | |
| | | var ana_fre_pump = new AnaFrePump(); |
| | | ana_fre_pump.Flag = flag; |
| | | 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; |
| | |
| | | } |
| | | if (!ana_combine_list.Any()) |
| | | return default; |
| | | var opt_ana_combine = ana_combine_list.OrderBy(x => x.TotalPower).First(); |
| | | var opt_ana_combine = ana_combine_list.OrderBy(x => x.TotalFlow).OrderBy(x => x.TotalPower).First(); |
| | | return opt_ana_combine; |
| | | } |
| | | |
| | |
| | | Yw.LogHelper.Error($"[{Yw.Untity.IntListHelper.ToString(flags)}]组合不存在偏差系数!"); |
| | | return deviation_factor_dict; |
| | | } |
| | | |
| | | |
| | | var a = flow; |
| | | var flow_dev = flow; |
| | | Model.AnalysisDeviation analysis_deviation = null; |
| | |
| | | analysis_deviation = analysis_deviation_list.Where(x => x.MinFlow <= flow_dev && flow_dev <= x.MaxFlow).FirstOrDefault(); |
| | | if (analysis_deviation != null) |
| | | break; |
| | | } |
| | | |
| | | } |
| | | |
| | | if (analysis_deviation == null) |
| | | { |
| | | Yw.LogHelper.Error($"[{Yw.Untity.IntListHelper.ToString(flags)}]组合不存在偏差系数!"); |
| | |
| | | #endregion |
| | | |
| | | #region Expand |
| | | |
| | | |
| | | /// <summary> |
| | | /// 获取变频泵列表 根据工况计算 |
| | | /// </summary> |
| | |
| | | |
| | | |
| | | var fre_pump = new AnaFrePump(); |
| | | fre_pump.Flag = flag; |
| | | fre_pump.Flag = flag; |
| | | fre_pump.Flow = flow; |
| | | fre_pump.Head = head; |
| | | fre_pump.Power = curveQP.GetFitPointY(flow); |
| | |
| | | return ana_fre_pump_list; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取变频泵列表 根据工况计算 |
| | | /// </summary> |
| | | /// <param name="pumps"></param> |
| | | /// <param name="flag_rpm_dic"></param> |
| | | /// <param name="flag_inlet_water_level_dict"></param> |
| | | /// <param name="flag_flow_dic"></param> |
| | | /// <param name="flag_head_dic"></param> |
| | | /// <param name="flag_curve_head_dic"></param> |
| | | /// <param name="total_flow"></param> |
| | | /// <param name="ues_deviation_factor"></param> |
| | | /// <returns></returns> |
| | | public List<AnaFrePump> GetAnaFrePumpListByWorking( |
| | | List<Model.Pump> pumps, |
| | | Dictionary<int, double> flag_rpm_dic, |
| | | Dictionary<int, double> flag_inlet_water_level_dict, |
| | | Dictionary<int, double> flag_flow_dic, |
| | | Dictionary<int, double> flag_head_dic, |
| | | double total_flow, |
| | | out Dictionary<int, double> flag_curve_head_dic, |
| | | bool ues_deviation_factor = false |
| | | ) |
| | | { |
| | | flag_curve_head_dic = new Dictionary<int, double>(); |
| | | if (pumps == null || !pumps.Any()) |
| | | { |
| | | return default; |
| | | } |
| | | |
| | | if (flag_rpm_dic == null || !flag_rpm_dic.Any()) |
| | | { |
| | | return default; |
| | | } |
| | | |
| | | var run_flag_list = flag_rpm_dic.Where(x => x.Value > 1).Select(x => x.Key).OrderBy(x => x).ToList(); |
| | | var ana_fre_pump_list = new List<AnaFrePump>(); |
| | | foreach (var flag in run_flag_list) |
| | | { |
| | | var pump = pumps.Find(x => x.Flag == flag); |
| | | if (pump == null) |
| | | continue; |
| | | var rpm = flag_rpm_dic[flag]; |
| | | if (rpm < 1) |
| | | continue; |
| | | |
| | | var hz = Math.Round(rpm / pump.Nr * 50, 1); |
| | | |
| | | |
| | | var CurveQH50 = pump.CurveQH; |
| | | var CurveQP50 = pump.CurveQP; |
| | | |
| | | |
| | | var curveQH = Curve.PumpCalculateHelper.CalculateSimilarQH(CurveQH50, pump.Nr, rpm); |
| | | var curveQP = Curve.PumpCalculateHelper.CalculateSimilarQP(CurveQP50, pump.Nr, rpm); |
| | | |
| | | double flow = 0, head = 0; |
| | | if (flag_head_dic != null && flag_head_dic.ContainsKey(pump.Flag)) |
| | | { |
| | | head = flag_head_dic[pump.Flag]; |
| | | } |
| | | |
| | | if (flag_inlet_water_level_dict != null && flag_inlet_water_level_dict.ContainsKey(pump.Flag)) |
| | | { |
| | | head -= flag_inlet_water_level_dict[pump.Flag]; |
| | | } |
| | | |
| | | if (ues_deviation_factor) |
| | | { |
| | | //var combine_deviation_factor_dict = GetCombineDeviationFactorDict(total_flow, run_flag_list);//修正组合曲线和模型的偏差扬程 |
| | | //if (combine_deviation_factor_dict != null && combine_deviation_factor_dict.ContainsKey(flag)) |
| | | //{ |
| | | // var combine_deviation_factor = combine_deviation_factor_dict[flag]; //组合偏差系数 |
| | | // head -= combine_deviation_factor; |
| | | //} |
| | | } |
| | | |
| | | flow = curveQH.GetInterPointLastX(head) ?? 0; |
| | | if (flow < 0) |
| | | continue; |
| | | |
| | | var working_flow = flag_flow_dic[flag]; |
| | | flag_curve_head_dic[flag] = curveQH.GetFitPointY(working_flow); |
| | | |
| | | var fre_pump = new AnaFrePump(); |
| | | fre_pump.Flag = flag; |
| | | fre_pump.Flow = flow; |
| | | fre_pump.Head = head; |
| | | fre_pump.Power = curveQP.GetFitPointY(flow); |
| | | fre_pump.PressureDiff = head - Curve.PumpCalculateHelper.CalculateOtherPress(flow, pump.Ic, pump.Oc, null, null); |
| | | fre_pump.Eff = Curve.PumpCalculateHelper.CalculateE(fre_pump.Flow, fre_pump.Head, fre_pump.Power); |
| | | fre_pump.Frequency = rpm / pump.Nr * 50; |
| | | fre_pump.Speed = rpm; |
| | | |
| | | ana_fre_pump_list.Add(fre_pump); |
| | | } |
| | | |
| | | |
| | | return ana_fre_pump_list; |
| | | } |
| | | |
| | | |
| | | |
| | | #endregion |
| | | #endregion |
| | | |
| | | } |
| | | } |