using Yw.Geometry; using Yw.WinFrmUI.Phart; namespace PBS.WinFrmUI.Hydro.Dispatch.Common { /// /// 调度分析(核心算法) /// public class DispatchAnaGeneralHelper扬程 { /// /// /// static public double MinFlowIngore = 50;//流量低于多少就不考虑了 /// /// /// static public double ExtendMaxRatio = 1.25;//最大延长率 25% /// /// /// static public double MinChangeFrequence = 15;//最小变化的频率 /// /// /// // static public double ChangeFrequenceSpaece = 0.5;//频率变化值 static public double ChangeFrequenceSpaece = 0.1;//频率变化值 private double _targetQ; private double _targetH; private double _targetQmax, _targetQmin; private List _machineRunFilterList = null; private List _must_open_machine_array = null; private List _must_close_machine_array = null; private Dictionary _machine_flow_limit_max_dict = null; private Dictionary _machine_flow_limit_min_dict = null; private int _max_open_machine_number = 0;//最多开机数量 private List _anaSchemeList = null; private List _allMachineList = null; //组合运行约束(禁止判断) private List _allCombineRunJudgeList4Forbid = null; //组合运行约束(必须判断) private List> _allCombineRunJudgeList4Must = null; /// /// 初始化参数 /// /// /// /// /// /// /// /// public bool InitialParas( double targetQ, double targetH, string MinQ, string MaxQ, List allEnginePumpList, List MachineRunFilterList) { this._targetH = targetH; this._targetQ = targetQ; this._allMachineList = allEnginePumpList; this._targetQmax = targetQ * 1.25; this._targetQmin = targetQ * 0.85; if (!string.IsNullOrEmpty(MinQ)) { double minq = targetQ; if (MinQ.Contains("%")) { double ratio; if (double.TryParse(MinQ.Replace("%", ""), out ratio)) { minq = targetQ * (Math.Abs(ratio) / 100); } } else { double.TryParse(MinQ, out minq); } if (minq < targetQ) { _targetQmin = minq; } } if (!string.IsNullOrEmpty(MaxQ)) { double maxq = targetQ; if (MaxQ.Contains("%")) { double ratio; if (double.TryParse(MaxQ.Replace("%", ""), out ratio)) { maxq = targetQ * (Math.Abs(ratio) / 100); } } else { double.TryParse(MaxQ, out maxq); } if (maxq > targetQ) { _targetQmax = maxq; } } InitialFilter(MachineRunFilterList); return true; } #region 过滤 private void InitialFilter(List MachineRunFilterList) { this._machineRunFilterList = MachineRunFilterList; if (_machineRunFilterList != null) { _must_open_machine_array = null; _must_close_machine_array = null; _machine_flow_limit_max_dict = null; _machine_flow_limit_min_dict = null; foreach (var m in _machineRunFilterList) { if (m.RunStatus == 1) { if (_must_open_machine_array == null) _must_open_machine_array = new List(); _must_open_machine_array.Add(m.MachineID); } if (m.RunStatus == 0) { if (_must_close_machine_array == null) _must_close_machine_array = new List(); _must_close_machine_array.Add(m.MachineID); } if (m.MaxFlow > 10) { if (this._machine_flow_limit_max_dict == null) _machine_flow_limit_max_dict = new Dictionary(); _machine_flow_limit_max_dict[m.MachineID] = m.MaxFlow; } } } } //是否符合过滤 private bool IsAccordMachineRunFilter(List current_open_machine_id_array) { if (current_open_machine_id_array == null || current_open_machine_id_array.Count() == 0) return false; //必须开机 if (_must_open_machine_array != null && _must_open_machine_array.Count > 0) { foreach (var machine_id in _must_open_machine_array) { if (!current_open_machine_id_array.Contains(machine_id)) return false; } } //不能开机 if (_must_close_machine_array != null && _must_close_machine_array.Count > 0) { foreach (var machine_id in current_open_machine_id_array) { if (_must_close_machine_array.Contains(machine_id)) return false; } } //开机组合 约束(禁止) if (_allCombineRunJudgeList4Forbid != null && _allCombineRunJudgeList4Forbid.Count() > 0) { foreach (var combineRunJudge in _allCombineRunJudgeList4Forbid) {//符合禁止约束就不行 if (combineRunJudge.Judgement(current_open_machine_id_array)) return false; } } //开机组合 约束(必须) if (this._allCombineRunJudgeList4Must != null) { foreach (var item_arr in this._allCombineRunJudgeList4Must) { var q = from a in item_arr join b in current_open_machine_id_array on a equals b select a; bool flag = item_arr.Count == current_open_machine_id_array.Count && q.Count() == item_arr.Count; if (!flag) return false; } } return true; } #endregion /// /// 计算(最优) /// /// /// /// public List CalcOptList( Dispatch.Model.eAnaSchemeSortType SchemeSortType, int ReturnSchemeNumber) { if (_allMachineList == null || _allMachineList.Count() == 0) { return null; } #region 获取并预算一下 List fixPumpAnaDataList = new List();//固频泵 List frePumpAnaDataList = new List();//变频泵 foreach (var machine in _allMachineList) { if (_must_close_machine_array != null) { if (_must_close_machine_array.Contains(machine.MachineID)) continue;//必须关闭 } if (machine.IsFrequency) {//变频泵 var anaData = GetFrePumpAnaData(machine); if (anaData != null) frePumpAnaDataList.Add(anaData); } else {//固频泵 var anaData = GetFixPumpAnaData(machine); if (anaData != null) fixPumpAnaDataList.Add(anaData); } } #endregion #region 开始分析 _anaSchemeList = new List(); if (fixPumpAnaDataList == null || fixPumpAnaDataList.Count() == 0) {//没有合适的固频泵 AddOnlyFrePumpPrj(frePumpAnaDataList.ToArray()); } else { //分析没有变频泵开启的情况 AddOnlyFrePumpPrj(frePumpAnaDataList.ToArray()); //分析有固频泵开启的情况 for (int fixPumpNum = 1; fixPumpNum <= fixPumpAnaDataList.Count(); fixPumpNum++) { //得到所有排列组合(工频) List fixPumpAnaCombineList = PermutationAndCombination.GetCombination( fixPumpAnaDataList.ToArray(), fixPumpNum); #region 分析每种组合 foreach (Dispatch.Model.FixPumpAnaData[] fixPumpAnaCombine in fixPumpAnaCombineList) { //遍历各种工频组合 #region 检查是否符合开机约束 List machine_ids = new List(); if (fixPumpAnaCombine != null) { foreach (var item in fixPumpAnaCombine) machine_ids.Add(item.MachineDetail.MachineID); } if (!IsAccordMachineRunFilter(machine_ids)) { continue; } #endregion var fix_pump_total_flow = (from x in fixPumpAnaCombine select x.AnaItem50Hz.WorkPointQ).Sum(); if (fix_pump_total_flow > _targetQmax) { continue; } if (fix_pump_total_flow > _targetQmin) {//只用固频泵即可 AddOnlyFixPumpPrj(fixPumpAnaCombine, fix_pump_total_flow); } else if (frePumpAnaDataList.Count() > 0) { //只有一台变频泵 AddSingleFreqPumpPrj1(fixPumpAnaCombine, frePumpAnaDataList.ToArray()); //有2台变频泵 if (frePumpAnaDataList.Count() >= 2) { AddMultiFreqPumpPrj2(fixPumpAnaCombine, frePumpAnaDataList.ToArray()); } //有3台变频泵 if (frePumpAnaDataList.Count() >= 3) { AddMultiFreqPumpPrj3(fixPumpAnaCombine, frePumpAnaDataList.ToArray()); }   } } #endregion } } #endregion //计算 var ds_disp_project_list = new List(); foreach (var project in _anaSchemeList) { //计算流量 //project.TotalWrkQ = (from x in project.Items where x.WorkPointQ > 0 select x.WorkPointQ).Sum(); //if (project.TotalWrkQ <= _targetQmax && project.TotalWrkQ >= this._targetQmin) ds_disp_project_list.Add(project); project.UWP = Math.Round(project.UWP, 3); project.WP = Math.Round(project.WP, 3); project.SpanQ = Math.Round(project.TotalWrkQ - _targetQ, 0); project.CalcItemParas(); } // 0 功率 1 流量间隔 if (SchemeSortType == Dispatch.Model.eAnaSchemeSortType.功率) ds_disp_project_list = (from x in ds_disp_project_list orderby x.TotalWrkP select x).ToList(); else if (SchemeSortType == Dispatch.Model.eAnaSchemeSortType.流量差值) ds_disp_project_list = (from x in ds_disp_project_list orderby Math.Abs(x.SpanQ) select x).ToList(); //重新编号ID for (int i = 0; i < ds_disp_project_list.Count; i++) { ds_disp_project_list[i].ID = i + 1; } if (ReturnSchemeNumber <= 0) return ds_disp_project_list; else return ds_disp_project_list.Take(ReturnSchemeNumber).ToList(); } #region 算出是否符合的固频泵:GetFixPumpAnaData private Dispatch.Model.FixPumpAnaData GetFixPumpAnaData(Dispatch.Model.MachineDetailEx Machine) { if (Machine == null) return null; Dispatch.Model.AnaCurveItem anaData = new Dispatch.Model.AnaCurveItem(); if (CalcAnaCurve(Machine.MaxCurveInfoQH, Machine.MaxCurveInfoQP, this._targetH, 50, Machine.Percentage, ref anaData) <= 0) return null; anaData.CurveInfoQH = Machine.MaxCurveInfoQH; anaData.CurveInfoQP = Machine.MaxCurveInfoQP; anaData.Frequence = 50; anaData.Speed = Machine.RatedN; return new Dispatch.Model.FixPumpAnaData() { MachineDetail = Machine, AnaItem50Hz = anaData }; } #endregion #region 算出是否符合的变频泵:GetFrePumpAnaData private Dispatch.Model.FrePumpAnaData GetFrePumpAnaData( Dispatch.Model.MachineDetailEx Machine) { if (Machine == null) return null; Dispatch.Model.FrePumpAnaData anaData = new Dispatch.Model.FrePumpAnaData(); anaData.MachineDetail = Machine; anaData.AnaItemList = new List(); double targetH = this._targetH; var points50 = Machine.MaxCurveInfoQH.GetPointList(50); points50.GetMinMaxPointY(out double maxH, out double minH); if (maxH < targetH) { return null; } var pointsMin = Yw.Pump.PerformSimilarNHelper.GetQHPointListByN(Machine.MaxCurveInfoQH.GetPointList(), 50, MinChangeFrequence); pointsMin.GetMinMaxPointY(out maxH, out minH); if (minH > targetH) { return null; } //获取每个频率的值(粗算) for (double freqCurrentFrequ = 50; freqCurrentFrequ > MinChangeFrequence; freqCurrentFrequ = freqCurrentFrequ - ChangeFrequenceSpaece) { Dispatch.Model.AnaCurveItem curve = new Dispatch.Model.AnaCurveItem(); int ret = CalcAnaCurve(Machine.MaxCurveInfoQH, Machine.MaxCurveInfoQP, this._targetH, freqCurrentFrequ, Machine.Percentage, ref curve); if (ret == -1) break;//-1 表示最大扬程都已经低于目标扬程了, 没必要再迭代了 if (ret == 0) continue; curve.Speed = Machine.CalcSpeedByFrequence(curve.Frequence); anaData.AnaItemList.Add(curve); } return anaData; } #endregion #region 精算 private void CalcDetailAccurate(ref Dispatch.Model.AnaScheme project) { //没有变频泵, 就没有必要精算 var frequecePumps = (from x in project.Items where x.IsFrequency select x); if (frequecePumps == null || frequecePumps.Count() == 0) return; if (frequecePumps.Count() == 1) {//只有一台,比较简单 #region 只有一台,比较简单 Dispatch.Model.AnaSchemeItem current_adjust_item = frequecePumps.FirstOrDefault(); var current_machine = (from x in this._allMachineList where x.MachineID == current_adjust_item.MachineID select x).FirstOrDefault(); if (current_machine == null) return; var totalWrkQ_other = (from x in project.Items where x.WorkPointQ > 0 && x.MachineID != current_adjust_item.MachineID select x.WorkPointQ).Sum(); // var target_pump_flow = this._targetQ - totalWrkQ_other; var max_fr = Math.Min(50, current_adjust_item.Frequence + ChangeFrequenceSpaece * 2); var min_fr = current_adjust_item.Frequence - ChangeFrequenceSpaece * 2; double flow_chajiu = Math.Abs(project.TotalWrkQ - this._targetQ); for (double fre = max_fr; fre > min_fr; fre = fre - 0.1) { Dispatch.Model.AnaCurveItem ana_item = new Dispatch.Model.AnaCurveItem(); int ret = CalcAnaCurve(current_machine.MaxCurveInfoQH, current_machine.MaxCurveInfoQP, this._targetH, fre, current_machine.Percentage, ref ana_item); if (ret == -1) return;//-1 表示最大扬程都已经低于目标扬程了, 没必要再迭代了 if (ret == 0) continue; var total_q = totalWrkQ_other + ana_item.WorkPointQ; if (total_q < this._targetQmin) break;//如果已经低于最小,不用再变频了 if (Math.Abs(total_q - this._targetQ) < flow_chajiu) { flow_chajiu = Math.Abs(total_q - this._targetQ); current_adjust_item.Frequence = Math.Round(fre, 1); current_adjust_item.WorkPointQ = Math.Round(ana_item.WorkPointQ, 1); current_adjust_item.WorkPointP = Math.Round(ana_item.WorkPointP, 1); // 再汇总一下 project.TotalWrkQ = (from x in project.Items where x.WorkPointQ > 0 select x.WorkPointQ).Sum(); project.TotalWrkP = (from x in project.Items where x.WorkPointP > 0 select x.WorkPointP).Sum(); project.UWP = Calcu_UWP(project.TotalWrkP, project.TotalWrkQ, this._targetH); project.WP = Calcu_WP(project.TotalWrkP, project.TotalWrkQ); } if (total_q < this._targetQ) { break; } } #endregion } else if (frequecePumps.Count() == 2) { Dispatch.Model.AnaSchemeItem adjust_item_1 = frequecePumps.ElementAt(0); Dispatch.Model.AnaSchemeItem adjust_item_2 = frequecePumps.ElementAt(1); var adjust_machine_1 = (from x in this._allMachineList where x.MachineID == adjust_item_1.MachineID select x).FirstOrDefault(); if (adjust_machine_1 == null) return; var adjust_machine_2 = (from x in this._allMachineList where x.MachineID == adjust_item_2.MachineID select x).FirstOrDefault(); if (adjust_machine_2 == null) return; //除了调解泵的其他泵流量 var total_flow_other = (from x in project.Items where x.WorkPointQ > 0 && x.MachineID != adjust_machine_1.MachineID && x.MachineID != adjust_machine_2.MachineID select x.WorkPointQ).Sum(); var total_power_other = (from x in project.Items where x.WorkPointP > 0 && x.MachineID != adjust_machine_1.MachineID && x.MachineID != adjust_machine_2.MachineID select x.WorkPointP).Sum(); List item_js_1 = new List(); for (double fre = Math.Min(50, adjust_item_1.Frequence + ChangeFrequenceSpaece * 2); fre > adjust_item_1.Frequence - ChangeFrequenceSpaece * 2; fre = fre - 0.1) { Dispatch.Model.AnaCurveItem ana_item = new Dispatch.Model.AnaCurveItem(); int ret = CalcAnaCurve(adjust_machine_1.MaxCurveInfoQH, adjust_machine_1.MaxCurveInfoQP, this._targetH, fre, adjust_machine_1.Percentage, ref ana_item); if (ret == -1) break; item_js_1.Add(ana_item); } List item_js_2 = new List(); for (double fre = Math.Min(50, adjust_item_2.Frequence + ChangeFrequenceSpaece * 2); fre > adjust_item_2.Frequence - ChangeFrequenceSpaece * 2; fre = fre - 0.1) { Dispatch.Model.AnaCurveItem ana_item = new Dispatch.Model.AnaCurveItem(); int ret = CalcAnaCurve(adjust_machine_2.MaxCurveInfoQH, adjust_machine_2.MaxCurveInfoQP, this._targetH, fre, adjust_machine_2.Percentage, ref ana_item); if (ret == -1) break; item_js_2.Add(ana_item); } double ump_chajiu = project.UWP; foreach (var item1 in item_js_1) { foreach (var item2 in item_js_2) { var total_flow = item1.WorkPointQ + item2.WorkPointQ + total_flow_other; if (Math.Abs(total_flow - this._targetQ) < this._targetQ * 0.01) { var total_power = item1.WorkPointP + item2.WorkPointP + total_power_other; var uwp = Calcu_UWP(total_power, total_flow, this._targetH); if (uwp < ump_chajiu) { adjust_item_1.ResetItem(item1); adjust_item_2.ResetItem(item2); adjust_item_1.Frequence = Math.Round(item1.Frequence, 1); adjust_item_2.Frequence = Math.Round(item2.Frequence, 1); // 再汇总一下 project.TotalWrkQ = (from x in project.Items where x.WorkPointQ > 0 select x.WorkPointQ).Sum(); project.TotalWrkP = (from x in project.Items where x.WorkPointP > 0 select x.WorkPointP).Sum(); project.UWP = Calcu_UWP(project.TotalWrkP, project.TotalWrkQ, this._targetH); project.WP = Calcu_WP(project.TotalWrkP, project.TotalWrkQ); } } } } } else { //哪个泵流量大,就调整哪个泵 Dispatch.Model.AnaSchemeItem aj_pump = frequecePumps.FirstOrDefault(); foreach (var p in project.Items) { if (!p.IsFrequency) continue; if (p.WorkPointQ > aj_pump.WorkPointQ) { aj_pump = p; } } //除了调解泵的其他泵流量 var total_flow_other = (from x in project.Items where x.WorkPointQ > 0 && x.MachineID != aj_pump.MachineID select x.WorkPointQ).Sum(); // double flow_chajiu = Math.Abs(project.TotalWrkQ - this._targetQ); // var pump_curve = (from x in this._allMachineList where x.MachineID == aj_pump.MachineID select x).FirstOrDefault(); if (pump_curve != null) { var max_fr = Math.Min(50, aj_pump.Frequence + ChangeFrequenceSpaece * 2); var min_fr = aj_pump.Frequence - ChangeFrequenceSpaece * 2; for (double fre = max_fr; fre > min_fr; fre = fre - 0.1) { Dispatch.Model.AnaCurveItem curve = new Dispatch.Model.AnaCurveItem(); int ret = CalcAnaCurve(pump_curve.MaxCurveInfoQH, pump_curve.MaxCurveInfoQP, this._targetH, fre, pump_curve.Percentage, ref curve); if (ret == -1) break;//-1 表示最大扬程都已经低于目标扬程了, 没必要再迭代了 if (ret == 0) continue; var total_q = total_flow_other + curve.WorkPointQ; if (total_q < this._targetQmin) break;//如果已经低于最小,不用再变频了 if (Math.Abs(total_q - this._targetQ) < flow_chajiu) { flow_chajiu = Math.Abs(total_q - this._targetQ); aj_pump.Frequence = Math.Round(fre, 1); aj_pump.WorkPointQ = Math.Round(curve.WorkPointQ, 1); aj_pump.WorkPointP = Math.Round(curve.WorkPointP, 1); //再汇总一下 project.TotalWrkQ = (from x in project.Items where x.WorkPointQ > 0 select x.WorkPointQ).Sum(); project.TotalWrkP = (from x in project.Items where x.WorkPointP > 0 select x.WorkPointP).Sum(); project.UWP = Calcu_UWP(project.TotalWrkP, project.TotalWrkQ, this._targetH); project.WP = Calcu_WP(project.TotalWrkP, project.TotalWrkQ); } if (total_q < this._targetQ) { break; } } } } } #endregion #region 根据频率值,计算变频曲线 /// /// 根据频率值,计算变频曲线(外部也会调用) /// /// /// /// /// /// /// public static int CalcAnaCurve( Yw.Ahart.CubicCurve MaxCurveInfoQH, Yw.Ahart.CubicCurve MaxCurveInfoQP, double targetH, double freqCurrentFrequ,//频率值 double extendMaxRatio, ref Dispatch.Model.AnaCurveItem ana_data) { if (ana_data == null) ana_data = new Dispatch.Model.AnaCurveItem(); if (freqCurrentFrequ >= 49.9) { ana_data.Frequence = freqCurrentFrequ; ana_data.CurveInfoQH = MaxCurveInfoQH; ana_data.CurveInfoQP = MaxCurveInfoQP; double flow = 0; var pointsQH = ana_data.CurveInfoQH.GetPointListByXRatioRange(0.9,extendMaxRatio, 50); if (!GetFolwByHead(pointsQH, targetH, ref flow)) { ana_data.IsOverMaxH = true; ana_data.Note = "已超出最大可行的流量"; return 0; } flow = Math.Round(flow, 1); var head = ana_data.CurveInfoQH.GetPointY( Math.Round(flow, 1)); head = Math.Round(head, 1); ana_data.WorkPointQ = flow; ana_data.WorkPointH = head; ana_data.WorkPointP = Math.Round(ana_data.CurveInfoQP.GetPointY(ana_data.WorkPointQ), 1); ana_data.WorkPointE = Math.Round(Yw.Pump.CalculationHelper.CalcuE(ana_data.WorkPointQ, ana_data.WorkPointH, ana_data.WorkPointP), 1); ana_data.IsExtendCurve = false; if (flow > ana_data.CurveInfoQH.MaxX) {//在延长线上 ana_data.IsExtendCurve = true; ana_data.RatioExtend = extendMaxRatio; //延长率 double extRatioQ = Math.Round(flow * 100 / ana_data.CurveInfoQH.MaxX, 1); ana_data.Note = string.Format("在延长曲线部分,参数可能不准确,延长率为:{0:0.0}", extRatioQ); } return 1; } else { #region 变频 ana_data.Frequence = Math.Round(freqCurrentFrequ, 1); ana_data.CurveInfoQH = new Yw.Ahart.CubicCurve(Yw.Pump.PerformSimilarNHelper.GetQHPointListByN(MaxCurveInfoQH.GetPointList(50), 50, ana_data.Frequence)) ; ana_data.CurveInfoQP = new Yw.Ahart.CubicCurve(Yw.Pump.PerformSimilarNHelper.GetQPPointListByN(MaxCurveInfoQP.GetPointList(50), 50, ana_data.Frequence)); double flow = 0; var pointsQH = ana_data.CurveInfoQH.GetPointListByXRatioRange(0.9,extendMaxRatio, 50); if (!GetFolwByHead(pointsQH, targetH, ref flow)) { ana_data.IsOverMaxH = true; ana_data.Note = "已超出最大可行的流量"; return 0; } flow = Math.Round(flow, 2); var head = ana_data.CurveInfoQH.GetPointY( Math.Round(flow, 2)); head = Math.Round(head, 1); ana_data.WorkPointQ = flow; ana_data.WorkPointH = head; ana_data.WorkPointP = Math.Round(ana_data.CurveInfoQP.GetPointY(ana_data.WorkPointQ), 3); ana_data.WorkPointE = Math.Round(Yw.Pump.CalculationHelper.CalcuE(ana_data.WorkPointQ, ana_data.WorkPointH, ana_data.WorkPointP), 2); ana_data.IsExtendCurve = false; if (flow > ana_data.CurveInfoQH.MaxX) {//在延长线上 ana_data.IsExtendCurve = true; ana_data.RatioExtend = extendMaxRatio; //延长率 double extRatioQ = Math.Round(flow * 100 / ana_data.CurveInfoQH.MaxX, 1); ana_data.Note = string.Format("在延长曲线部分,参数可能不准确,延长率为:{0:0.0}", extRatioQ); } #endregion return 1; } } //根据压差计算流量 //private static double OtherPressCoeff = 4 * 1000 / Math.PI / 3.6; /// /// /// /// /// /// /// public static bool GetFolwByHead(List curveInfoQH, double h, ref double q) { var listQ = curveInfoQH.GetInterPointsX(h); if (listQ == null || listQ.Count() == 0) { return false; } q = listQ.Last(); return true; } #endregion #region 添加项目 (只有用固频泵) private Dispatch.Model.AnaScheme AddOnlyFixPumpPrj( Dispatch.Model.FixPumpAnaData[] fixPumpAnaDataList, double totalQ) { // var rowPrj = new Dispatch.Model.AnaScheme(); rowPrj.TotalWrkQ = totalQ; rowPrj.TotalWrkH = Math.Round(this._targetH, 2); rowPrj.Items = new List(); foreach (var fixPump in fixPumpAnaDataList) { if (fixPump.AnaItem50Hz.WorkPointQ < 0.01) continue; var itemRow = new Dispatch.Model.AnaSchemeItem(fixPump.MachineDetail, fixPump.AnaItem50Hz); rowPrj.Items.Add(itemRow); } AddScheme(rowPrj, false); return rowPrj; } #endregion #region 添加项目 只有用变频频泵即可 private void AddOnlyFrePumpPrj( Dispatch.Model.FrePumpAnaData[] freqPumpAnaList) { AddSingleFreqPumpPrj1(null, freqPumpAnaList); //有2台变频泵 if (freqPumpAnaList.Count() >= 2) { AddMultiFreqPumpPrj2(null, freqPumpAnaList); } //有3台变频泵 if (freqPumpAnaList.Count() >= 3) { AddMultiFreqPumpPrj3(null, freqPumpAnaList); } } #endregion #region 添加项目 只有1台变频泵:AddOneFreqPumpPrj private int AddSingleFreqPumpPrj1( Dispatch.Model.FixPumpAnaData[] allFixPumpAnaList, Dispatch.Model.FrePumpAnaData[] allFreqPumpAnaList) { if (allFreqPumpAnaList == null || allFreqPumpAnaList.Count() == 0) return 0; //判断最大开机数 if (_max_open_machine_number > 0) { int macine_number = 1; if (allFixPumpAnaList != null) { macine_number = macine_number + allFixPumpAnaList.Count(); } if (macine_number > _max_open_machine_number) return 0; } double fix_pump_total_flow = 0; if (allFixPumpAnaList != null) { fix_pump_total_flow = (from x in allFixPumpAnaList select x.AnaItem50Hz.WorkPointQ).Sum(); } if (fix_pump_total_flow >= this._targetQ * 0.99) return 0; int addPrjNum = 0; foreach (var freqPump in allFreqPumpAnaList) { #region 检查是否符合开机约束 List machine_ids = new List(); machine_ids.Add(freqPump.MachineDetail.MachineID); if (allFixPumpAnaList != null) { foreach (var item in allFixPumpAnaList) machine_ids.Add(item.MachineDetail.MachineID); } if (!IsAccordMachineRunFilter(machine_ids)) { continue; } #endregion double h = Math.Round(this._targetH, 2); var wrkSpeed = freqPump.MachineDetail.MaxCurveInfoQH.GetSimuValue( new Yw.Geometry.Point2d(_targetQ - fix_pump_total_flow, h), 2900); Dispatch.Model.AnaCurveItem currentAna = new Dispatch.Model.AnaCurveItem(); double fre = Math.Round(50 * wrkSpeed / 2900, 1); if (fre > 50) { fre = 50; } int ret = CalcAnaCurve(freqPump.MachineDetail.MaxCurveInfoQH, freqPump.MachineDetail.MaxCurveInfoQP, this._targetH, fre, freqPump.MachineDetail.Percentage, ref currentAna); if (ret == -1) continue; if (ret == 0) continue; currentAna.Speed = freqPump.MachineDetail.CalcSpeedByFrequence(fre); var rowPrj = new Dispatch.Model.AnaScheme(); rowPrj.Items = new List(); #region 加入固频泵开启信息 if (allFixPumpAnaList != null) { foreach (var fixPump in allFixPumpAnaList) { if (fixPump.AnaItem50Hz.WorkPointQ < 0.01) continue; var itemRow = new Dispatch.Model.AnaSchemeItem(fixPump.MachineDetail, fixPump.AnaItem50Hz); rowPrj.Items.Add(itemRow); } } #endregion var itemRowF = new Dispatch.Model.AnaSchemeItem(freqPump.MachineDetail, currentAna); rowPrj.Items.Add(itemRowF); AddScheme(rowPrj, false); addPrjNum++; } if (addPrjNum == 0) { var diff_hz = 0.01; for (int i = 1; i <= 5; i++) { foreach (var freqPump in allFreqPumpAnaList) { double h = Math.Round(this._targetH, 2); var wrkSpeed = freqPump.MachineDetail.MaxCurveInfoQH.GetSimuValue(new Yw.Geometry.Point2d(_targetQ - fix_pump_total_flow, h), 2900); Dispatch.Model.AnaCurveItem currentAna = new Dispatch.Model.AnaCurveItem(); double fre = Math.Round(50 * wrkSpeed / 2900, 1) + diff_hz; if (fre > 50) { fre = 50; } int ret = CalcAnaCurve(freqPump.MachineDetail.MaxCurveInfoQH, freqPump.MachineDetail.MaxCurveInfoQP, this._targetH, fre, freqPump.MachineDetail.Percentage, ref currentAna); if (ret == -1) continue; if (ret == 0) continue; currentAna.Speed = freqPump.MachineDetail.CalcSpeedByFrequence(fre); var rowPrj = new Dispatch.Model.AnaScheme(); rowPrj.Items = new List(); #region 加入固频泵开启信息 if (allFixPumpAnaList != null) { foreach (var fixPump in allFixPumpAnaList) { if (fixPump.AnaItem50Hz.WorkPointQ < 1) continue; var itemRow = new Dispatch.Model.AnaSchemeItem(fixPump.MachineDetail, fixPump.AnaItem50Hz); rowPrj.Items.Add(itemRow); } } #endregion var itemRowF = new Dispatch.Model.AnaSchemeItem(freqPump.MachineDetail, currentAna); rowPrj.Items.Add(itemRowF); AddScheme(rowPrj, true, false); addPrjNum++; } if (addPrjNum>0) { break; } diff_hz += 0.01; } } return addPrjNum; } #endregion #region 添加项目 只有2台变频泵:AddTwoFreqPumpPrj private int AddMultiFreqPumpPrj2( Dispatch.Model.FixPumpAnaData[] allFixPumpAnaList, Dispatch.Model.FrePumpAnaData[] allFreqPumpAnaList) { int addPrjNum = 0; int frePumpNum = 2; if (allFreqPumpAnaList == null || allFreqPumpAnaList.Count() < frePumpNum) return addPrjNum; //判断最大开机数 if (_max_open_machine_number > 0) { int macine_number = 2; if (allFixPumpAnaList != null) { macine_number = macine_number + allFixPumpAnaList.Count(); } if (macine_number > _max_open_machine_number) return 0; } double fix_pump_total_flow = 0; if (allFixPumpAnaList != null) { fix_pump_total_flow = (from x in allFixPumpAnaList select x.AnaItem50Hz.WorkPointQ).Sum(); } var freqPumpAnaCombineList = PermutationAndCombination. GetCombination(allFreqPumpAnaList, frePumpNum); foreach (var freqPumpAnaCombine in freqPumpAnaCombineList) { var freqPump1 = freqPumpAnaCombine[0]; var freqPump2 = freqPumpAnaCombine[1]; #region 检查是否符合开机约束 List machine_ids = new List { freqPump1.MachineDetail.MachineID, freqPump2.MachineDetail.MachineID }; if (allFixPumpAnaList != null) { foreach (var item in allFixPumpAnaList) machine_ids.Add(item.MachineDetail.MachineID); } if (!IsAccordMachineRunFilter(machine_ids)) { continue; } #endregion Dispatch.Model.AnaCurveItem curveData1 = null; Dispatch.Model.AnaCurveItem curveData2 = null; var rowPrj = new Dispatch.Model.AnaScheme(); rowPrj.Items = new List(); #region 加入固频泵开启信息 if (allFixPumpAnaList != null) { foreach (var fixPump in allFixPumpAnaList) { if (fixPump.AnaItem50Hz.WorkPointQ < 1) continue; var itemRow = new Dispatch.Model.AnaSchemeItem(fixPump.MachineDetail, fixPump.AnaItem50Hz); rowPrj.Items.Add(itemRow); } } #endregion bool isActCalc = true; if (freqPump1.MachineDetail.PumpCode == freqPump2.MachineDetail.PumpCode) { //同型号 #region 流量对半分 var fre_pump_total_flow = this._targetQ - fix_pump_total_flow; isActCalc = false; double h = Math.Round(this._targetH, 2); //流量对半分 var wrkSpeed1 = freqPump1.MachineDetail.MaxCurveInfoQH.GetSimuValue( new Yw.Geometry.Point2d((_targetQ - fix_pump_total_flow) * 0.5, h), 2900); curveData1 = new Dispatch.Model.AnaCurveItem(); double fre1 = Math.Round(50 * wrkSpeed1 / 2900, 1); int ret1 = CalcAnaCurve(freqPump1.MachineDetail.MaxCurveInfoQH, freqPump1.MachineDetail.MaxCurveInfoQP, this._targetH, fre1, freqPump1.MachineDetail.Percentage, ref curveData1); if (ret1 == -1) continue; if (ret1 == 0) continue; curveData1.Speed = freqPump1.MachineDetail.CalcSpeedByFrequence(fre1); var wrkSpeed2 = freqPump2.MachineDetail.MaxCurveInfoQH.GetSimuValue( new Yw.Geometry.Point2d((_targetQ - fix_pump_total_flow) * 0.5, h), 2900); curveData2 = new Dispatch.Model.AnaCurveItem(); double fre2 = Math.Round(50 * wrkSpeed2 / 2900, 1); int ret2 = CalcAnaCurve(freqPump2.MachineDetail.MaxCurveInfoQH, freqPump2.MachineDetail.MaxCurveInfoQP, this._targetH, fre2, freqPump2.MachineDetail.Percentage, ref curveData2); if (ret2 == -1) continue; if (ret2 == 0) continue; curveData2.Speed = freqPump2.MachineDetail.CalcSpeedByFrequence(fre2); #endregion } else { isActCalc = true; double minSpanQ = _targetQ; double totalPower = freqPump1.MachineDetail.RatedP + freqPump2.MachineDetail.RatedP; //找到离_targetQ最接近的频率点 for (int index1 = 0; index1 < freqPump1.AnaItemList.Count; index1++) { //频率越来越小,c.WorkPointQ也越来越小 for (int index2 = 0; index2 < freqPump2.AnaItemList.Count; index2++) { var anaItem1 = freqPump1.AnaItemList[index1]; var anaItem2 = freqPump2.AnaItemList[index2]; double freTotalQ = anaItem1.WorkPointQ + anaItem2.WorkPointQ; //频率越来越小,c.WorkPointQ也越来越小 double freTotalP = anaItem1.WorkPointP + anaItem2.WorkPointP; var diffFlow = Math.Abs(fix_pump_total_flow + freTotalQ - _targetQ); if (diffFlow < minSpanQ) { minSpanQ = Math.Abs(fix_pump_total_flow + freTotalQ - _targetQ); curveData1 = anaItem1; curveData2 = anaItem2; totalPower = curveData1.WorkPointP + curveData2.WorkPointP; } if (diffFlow < _targetQ * 0.01 && freTotalP < totalPower) { curveData1 = anaItem1; curveData2 = anaItem2; totalPower = curveData1.WorkPointP + curveData2.WorkPointP; } } } } if (curveData1?.WorkPointQ > 10) { var itemRowF1 = new Dispatch.Model.AnaSchemeItem(freqPump1.MachineDetail, curveData1); rowPrj.Items.Add(itemRowF1); } if (curveData2?.WorkPointQ > 10) { var itemRowF2 = new Dispatch.Model.AnaSchemeItem(freqPump2.MachineDetail, curveData2); rowPrj.Items.Add(itemRowF2); } if (AddScheme(rowPrj, isActCalc)) addPrjNum++; } return addPrjNum; } #endregion #region 添加项目 只有3台变频泵:AddThreeFreqPumpPrj private int AddMultiFreqPumpPrj3( Dispatch.Model.FixPumpAnaData[] allFixPumpAnaList, Dispatch.Model.FrePumpAnaData[] allFreqPumpAnaList) { int addPrjNum = 0; int frePumpNum = 3; if (allFreqPumpAnaList == null || allFreqPumpAnaList.Count() < frePumpNum) return addPrjNum; //判断最大开机数 if (_max_open_machine_number > 0) { int macine_number = 3; if (allFixPumpAnaList != null) { macine_number = macine_number + allFixPumpAnaList.Count(); } if (macine_number > _max_open_machine_number) return 0; } double fix_pump_total_flow = 0; if (allFixPumpAnaList != null) { fix_pump_total_flow = (from x in allFixPumpAnaList select x.AnaItem50Hz.WorkPointQ).Sum(); } List freqPumpAnaCombineList = PermutationAndCombination.GetCombination( allFreqPumpAnaList.ToArray(), frePumpNum); foreach (var freqPumpAnaCombine in freqPumpAnaCombineList) { var freqPump1 = freqPumpAnaCombine[0]; var freqPump2 = freqPumpAnaCombine[1]; var freqPump3 = freqPumpAnaCombine[2]; #region 检查是否符合开机约束 List machine_ids = new List { freqPump1.MachineDetail.MachineID, freqPump2.MachineDetail.MachineID, freqPump3.MachineDetail.MachineID }; if (allFixPumpAnaList != null) { foreach (var item in allFixPumpAnaList) machine_ids.Add(item.MachineDetail.MachineID); } if (!IsAccordMachineRunFilter(machine_ids)) { continue; } #endregion double freTotalQ = fix_pump_total_flow; double minSpanQ = _targetQmax; double totalPower = freqPump1.MachineDetail.RatedP + freqPump2.MachineDetail.RatedP + freqPump3.MachineDetail.RatedP; Dispatch.Model.AnaCurveItem curveData1 = null; Dispatch.Model.AnaCurveItem curveData2 = null; Dispatch.Model.AnaCurveItem curveData3 = null; // var rowPrj = new Dispatch.Model.AnaScheme(); rowPrj.TotalWrkQ = freTotalQ; rowPrj.TotalWrkH = Math.Round(this._targetH, 2); rowPrj.Items = new List(); //找到离_targetQ最接近的频率点 for (int index1 = 0; index1 < freqPump1.AnaItemList.Count; index1++) {//频率越来越小,c.WorkPointQ也越来越小 for (int index2 = 0; index2 < freqPump2.AnaItemList.Count; index2++) {//频率越来越小,c.WorkPointQ也越来越小 for (int index3 = 0; index3 < freqPump3.AnaItemList.Count; index3++) {//频率越来越小,c.WorkPointQ也越来越小 var anaItem1 = freqPump1.AnaItemList[index1]; var anaItem2 = freqPump2.AnaItemList[index2]; var anaItem3 = freqPump3.AnaItemList[index3]; double wrkQ = anaItem1.WorkPointQ + anaItem2.WorkPointQ + anaItem3.WorkPointQ; double freTotalP = anaItem1.WorkPointP + anaItem2.WorkPointP + anaItem3.WorkPointP; var diffFlow = Math.Abs(fix_pump_total_flow + wrkQ - _targetQ); if (diffFlow < minSpanQ) { freTotalQ = fix_pump_total_flow + wrkQ; rowPrj.TotalWrkQ = freTotalQ; minSpanQ = Math.Abs(freTotalQ - _targetQ); curveData1 = anaItem1; curveData2 = anaItem2; curveData3 = anaItem3; totalPower = curveData1.WorkPointP + curveData2.WorkPointP + curveData3.WorkPointP; } if (diffFlow < _targetQ * 0.01 && freTotalP < totalPower) { curveData1 = anaItem1; curveData2 = anaItem2; curveData3 = anaItem3; totalPower = curveData1.WorkPointP + curveData2.WorkPointP + curveData3.WorkPointP; } } } } // if (freTotalQ < _targetQmax && freTotalQ > _targetQmin && curveData1 != null) { #region 加入固频泵开启信息 if (allFixPumpAnaList != null) { foreach (var fixPump in allFixPumpAnaList) { if (fixPump.AnaItem50Hz.WorkPointQ < 1) continue; var itemRow = new Dispatch.Model.AnaSchemeItem(fixPump.MachineDetail, fixPump.AnaItem50Hz); rowPrj.Items.Add(itemRow); } } #endregion if (curveData1.WorkPointQ > 10) { var itemRowF1 = new Dispatch.Model.AnaSchemeItem(freqPump1.MachineDetail, curveData1); rowPrj.Items.Add(itemRowF1); } if (curveData2.WorkPointQ > 10) { var itemRowF2 = new Dispatch.Model.AnaSchemeItem(freqPump2.MachineDetail, curveData2); rowPrj.Items.Add(itemRowF2); } if (curveData3.WorkPointQ > 10) { var itemRowF3 = new Dispatch.Model.AnaSchemeItem(freqPump3.MachineDetail, curveData3); rowPrj.Items.Add(itemRowF3); } AddScheme(rowPrj, true); addPrjNum++; } } return addPrjNum; } #endregion private int _schemeID = 1; private bool AddScheme(Dispatch.Model.AnaScheme project, bool IsAccurateCalc,bool is_valid=true) { if (project.Items == null || !project.Items.Any()) return false; project.TotalWrkQ = (from x in project.Items where x.WorkPointQ > 0 select x.WorkPointQ).Sum(); project.TotalWrkH = Math.Round((from x in project.Items where x.WorkPointH > 0 select x.WorkPointH).Average(), 3); project.TotalWrkP = Math.Round((from x in project.Items where x.WorkPointP > 0 select x.WorkPointP).Sum(), 3); project.TotalWrkE = Yw.Pump.CalculationHelper.CalcuE(project.TotalWrkQ, project.TotalWrkH, project.TotalWrkP); project.UWP = Calcu_UWP(project.TotalWrkP, project.TotalWrkQ, this._targetH); project.WP = Calcu_WP(project.TotalWrkP, project.TotalWrkQ); if (is_valid) { if (project.TotalWrkQ > _targetQmax || project.TotalWrkQ < _targetQmin) { return false; } } if (_machine_flow_limit_max_dict != null) { foreach (var item in project.Items) { if (_machine_flow_limit_max_dict.ContainsKey(item.MachineID)) {//操作开机限制 if (item.WorkPointQ > _machine_flow_limit_max_dict[item.MachineID]) return false; } } } if (_machine_flow_limit_min_dict != null) { foreach (var item in project.Items) { if (_machine_flow_limit_min_dict.ContainsKey(item.MachineID)) {//操作开机限制 if (item.WorkPointQ < _machine_flow_limit_min_dict[item.MachineID]) return false; } } } if (_anaSchemeList == null) _anaSchemeList = new List(); //再精算一下 if (IsAccurateCalc) CalcDetailAccurate(ref project); project.ID = _schemeID; _anaSchemeList.Add(project); _schemeID++; return true; } /// /// 单位水耗 千吨水 /// public static double Calcu_UWP(double P, double Q, double H) { if (Q <= 0.001) return 0; if (H <= 0.00001) return 0; if (P <= 0.001) return 0; return P * 1000f / Q / H; } /// /// 单位水耗 千吨水 /// public static double Calcu_UWP(double P, double Q, double inletPress, double outletPress) { double H = (outletPress - inletPress) * 102; if (Q <= 0.001) return 0; if (H <= 0.00001) return 0; if (P <= 0.001) return 0; return P * 1000f / Q / H; } /// /// 单位水耗 /// public static double Calcu_WP(double P, double Q) { if (Q <= 0.001) return 0; if (P <= 0.001) return 0; return P * 1000f / Q; } } public static class CurveExHeper { /// /// 取Y的最大最小值 /// public static bool GetMinMaxPointY(this List ptList, out double maxY, out double minY) { if (ptList == null) { maxY = minY = 0; return false; } var fitPoints = ptList.ToList(); maxY = fitPoints.Max(x => x.Y); minY = fitPoints.Min(x => x.Y); ; return true; } public static double GetSimuValue( this Yw.Ahart.CubicCurve curve, Yw.Geometry.Point2d pt,double nr) { var qh = new Yw.Pump.CurveQH(Yw.Ahart.eFeatType.Cubic, curve); var sect_pt = Yw.Pump.PerformParabolaHelper.GetQHSectPoint(qh, pt); if (sect_pt == null || sect_pt.IsZeroPoint()) return default; var wrk_speed = sect_pt.Y.CalculateSimuByH(nr, pt.Y); return wrk_speed; } } }