using IStation.CalcModel; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; namespace IStation.Calc { internal partial class ErQuCalcHelper_2_递归_定水量 : ErQuCalcHelper_2_递归 { protected List>> _dictCalcCache定水量; /// /// /// /// protected override List CalcOptPrjsCore() { _minTimeCountOpenPump = this.MinOpenPumpMinute / this.CalcSpaceMinute; _minTimeCountSwitch = this.MinSwitchPumpMinute / this.CalcSpaceMinute; //this._maxPumpSwitchCount = 5; var result = CalcOptPrjsBlockItems定水量(); if (result == null) return null; OnShowDebugInfo.Invoke(string.Format("计算次数:{0:N0}, 缓存使用次数:{1:N0}", this._totalCalcCount, this._totalCacheCount)); return ToAnaPrj(result); } /// /// /// /// protected BlockItemList CalcOptPrjsBlockItems定水量() { _dictCalcCache定水量 = new List>>(_timeDataListCount + 1); for (int i = 0; i < _timeDataListCount + 1; i++) { var ak = new List>(_timeDataListCount + 1); for (int j = 0; j < this.MaxPumpSwitchCount + 2; j++) { ak.Add(new Dictionary()); } _dictCalcCache定水量.Add(ak); } var result = RecursionFind初始_定水量(); if (result == null || result.Items == null) return null; if (result.Items.First().StartIndx > 0) { var empty_0 = new RunBlock(); empty_0.PumpCount = 0; empty_0.StartIndx = 0; empty_0.EndIndx = result.Items.First().StartIndx; empty_0.ReservoirStartHeight = this._start_level水库水位; empty_0.ReservoirEndHeight = CalcReservoirHeight(//下次开始时的水位 empty_0.StartIndx, empty_0.EndIndx, 0, this._start_level水库水位); result.Items.Insert(0, empty_0); } double lastLevelHeight = this._start_level水库水位; foreach (var s in from x in result.Items orderby x.StartIndx select x) { if (s.PumpCount == 0) { var end = CalcReservoirHeight(//下次开始时的水位 s.StartIndx, s.EndIndx, 0, lastLevelHeight); s.ReservoirStartHeight = lastLevelHeight; s.ReservoirEndHeight = end; lastLevelHeight = end; } else { var td = GetTimeDataBundle(s.PumpCount); double sumFlow = 0; for (int i = s.StartIndx; i < s.EndIndx; i++) { sumFlow += td.TimeDatas[i].SumFlow; } var end = CalcReservoirHeight(//下次开始时的水位 s.StartIndx, s.EndIndx, sumFlow, lastLevelHeight); s.ReservoirStartHeight = lastLevelHeight; s.ReservoirEndHeight = end; lastLevelHeight = end; } } if (result.Items.Last().EndIndx < this._timeDataListCount - 3) { var empty_l = new RunBlock(); empty_l.PumpCount = 0; empty_l.StartIndx = result.Items.Last().EndIndx; empty_l.EndIndx = this._timeDataListCount - 1; empty_l.ReservoirStartHeight = result.Items.Last().ReservoirEndHeight; empty_l.ReservoirEndHeight = CalcReservoirHeight(//下次开始时的水位 empty_l.StartIndx, empty_l.EndIndx, 0, result.Items.Last().ReservoirEndHeight); result.Items.Add(empty_l); } return result; } /// /// /// /// private BlockItemList RecursionFind初始_定水量() { int startSwitchTimeIndx = _minTimeCountSwitch;//保证不是一开始就进行泵切换 BlockItemList current_best_solution = new BlockItemList(); current_best_solution.TotalCompare = double.MaxValue; current_best_solution.Items = null; #region 判断: 全部都一样(不切换泵), 是否可以 for (int pumpNum_left = 1; pumpNum_left <= 4; pumpNum_left++) { if (this._startOpenCount >= 0) { if (this._startOpenCount != pumpNum_left) continue; } _totalCalcCount++; // double sumCompareWhole = 0; double sumFlowWhole = 0; var td = GetTimeDataBundle(pumpNum_left); td.GetRangeDataStart1(0, out sumFlowWhole, out sumCompareWhole); if (sumFlowWhole >= this._stationTotalFlow) { if (sumCompareWhole < current_best_solution.TotalCompare) { current_best_solution.TotalCompare = sumCompareWhole; current_best_solution.TotalFlow = sumFlowWhole; current_best_solution.Items = new List() { new RunBlock() { PumpCount = pumpNum_left , StartIndx = 0, EndIndx = _timeDataListCount-1, TotalCompare = sumCompareWhole, TotalFlow = sumFlowWhole } }; } } } #endregion #region 不开机 if (this._startOpenCount == 0 || this._startOpenCount == -1) { for (int splitIndx = startSwitchTimeIndx; splitIndx < _timeDataListCount - _minTimeCountSwitch; splitIndx++) {//_timeList[i].IsLimitSwitch if (!_timeList[splitIndx].IsSwitchPumpAble) continue; //右侧继续迭代 BlockItemList right_solutions = RecursionFindRight_定水量( 0, 1, 0, splitIndx); if (right_solutions == null) {//没有找到合适的 continue; } if (current_best_solution.TotalCompare > right_solutions.TotalCompare) { current_best_solution.TotalCompare = right_solutions.TotalCompare; current_best_solution.Items = new List(right_solutions.Items); } } } #endregion #region 开机 //int opt_num = 0; for (int pumpNum_left = 1; pumpNum_left <= 4; pumpNum_left++) { if (this._startOpenCount >= 0) { if (this._startOpenCount != pumpNum_left) continue; } for (int splitIndx = startSwitchTimeIndx; splitIndx < _timeDataListCount - _minTimeCountSwitch; splitIndx++) { //没有 splitIndx = endTimeIndx的情况,前面已考虑 if (!_timeList[splitIndx].IsSwitchPumpAble) continue; _totalCalcCount++; double sumCompareLeft = 0; double sumFlowLeft = 0; // 获取从开始时间,到结束时间,开pumpNum台泵的流量 //获取从开始时间,到结束时间,开pumpNum台泵的费用 var td = GetTimeDataBundle(pumpNum_left); td.GetRangeData1(0, splitIndx, out sumFlowLeft, out sumCompareLeft); if (sumFlowLeft >= this._stationTotalFlow) {//左侧已经能达到要求了 if (current_best_solution.TotalCompare > sumCompareLeft) { current_best_solution.TotalCompare = sumCompareLeft; current_best_solution.TotalFlow = sumFlowLeft; current_best_solution.Items = new List() { new RunBlock(){ PumpCount = pumpNum_left , StartIndx = 0, EndIndx = splitIndx, TotalCompare = sumCompareLeft, TotalFlow = sumFlowLeft } }; } break;//不用再继续了,再继续 功率只会越来越大 } else { //右侧继续迭代 BlockItemList right_solutions = RecursionFindRight_定水量( sumFlowLeft, 1, pumpNum_left, splitIndx); if (right_solutions == null) {//没有找到合适的 continue; } double cur_sumPower = sumCompareLeft + right_solutions.TotalCompare; if (current_best_solution.TotalCompare > cur_sumPower) { //opt_num++; current_best_solution.TotalCompare = cur_sumPower; current_best_solution.TotalFlow = sumFlowLeft + right_solutions.TotalFlow; current_best_solution.Items = new List(right_solutions.Items); current_best_solution.Items.Insert(0,//在前面插入左侧时间块 new RunBlock() { PumpCount = pumpNum_left, StartIndx = 0, EndIndx = splitIndx, TotalCompare = sumCompareLeft, TotalFlow = sumFlowLeft }); //if (opt_num == 3)//临时 // return current_best_solution; } } } } #endregion if (current_best_solution.TotalCompare == double.MaxValue) return null; return current_best_solution; } /// /// 递归 /// /// 当前的流量(左侧时间块流量) /// 当前切换次数 /// 开始时间段角标 /// private BlockItemList RecursionFindRight_定水量( double lastTotalFlow, int lastSwitchCount, int lastOpenPumpCount, int startTimeIndx) { if (lastSwitchCount > this.MaxPumpSwitchCount) {//不能再切换泵了:基本上不会出现,进入前已判断 return null; } if (lastTotalFlow > this._stationTotalFlow) {//已达到流量:基本上不会出现,进入前已判断 return null; } if (!_timeList[startTimeIndx].IsSwitchPumpAble) return null; // int flowKey = 0; if (lastTotalFlow > 0) { flowKey = (int)(lastTotalFlow / 2000); } bool isNeedInsertCache = true; if (_dictCalcCache定水量[startTimeIndx][lastSwitchCount].ContainsKey(flowKey)) { _totalCacheCount++; var cache_model = _dictCalcCache定水量[startTimeIndx][lastSwitchCount][flowKey]; if (cache_model == null) return null; if (cache_model.Items.First().PumpCount == lastOpenPumpCount) return null; isNeedInsertCache = false; if (cache_model.TotalFlow + lastTotalFlow >= this._stationTotalFlow) { BlockItemList cache_model_copy = new BlockItemList(); cache_model_copy.TotalCompare = cache_model.TotalCompare; cache_model_copy.TotalFlow = cache_model.TotalFlow; cache_model_copy.Items = new List(cache_model.Items); return cache_model_copy; } } BlockItemList current_best_solution = new BlockItemList(); current_best_solution.TotalCompare = double.MaxValue; current_best_solution.TotalFlow = 0; current_best_solution.Items = null; #region 判断: 全部都一样(不切换泵), 是否可以 for (int pumpNum_left = 1; pumpNum_left <= 4; pumpNum_left++) { if (pumpNum_left == lastOpenPumpCount) continue; _totalCalcCount++; double sumCompareWhole = 0; double sumFlowWhole = 0; // 获取从开始时间,到结束时间,开pumpNum台泵的流量 //获取从开始时间,到结束时间,开pumpNum台泵的费用 var td = GetTimeDataBundle(pumpNum_left); td.GetRangeDataStart1(startTimeIndx, out sumFlowWhole, out sumCompareWhole); if (sumCompareWhole == double.MaxValue) continue; if (sumFlowWhole + lastTotalFlow >= this._stationTotalFlow && sumCompareWhole < current_best_solution.TotalCompare) { current_best_solution.TotalCompare = sumCompareWhole; current_best_solution.TotalFlow = sumFlowWhole; current_best_solution.Items = new List() { new RunBlock() { PumpCount = pumpNum_left, StartIndx = startTimeIndx, EndIndx = _timeDataListCount - 1, TotalCompare = sumCompareWhole, TotalFlow = sumFlowWhole, } }; } } #endregion if (startTimeIndx < this._timeDataListCount - _minTimeCountSwitch) { #region 不开机 if (0 != lastOpenPumpCount) { for (int splitIndx = startTimeIndx + _minTimeCountSwitch; splitIndx < _timeDataListCount - _minTimeCountSwitch; splitIndx++) { if (!_timeList[splitIndx].IsSwitchPumpAble) continue; _totalCalcCount++; //右侧继续迭代 BlockItemList right_solutions = RecursionFindRight_定水量( lastTotalFlow, lastSwitchCount + 1, 0, splitIndx); if (right_solutions == null || right_solutions.TotalCompare == double.MaxValue) {//没有找到合适的 continue; } if (current_best_solution.TotalCompare > right_solutions.TotalCompare) { current_best_solution.TotalCompare = right_solutions.TotalCompare; current_best_solution.TotalFlow = right_solutions.TotalFlow; current_best_solution.Items = new List(right_solutions.Items.Count + 1); current_best_solution.Items.Add(new RunBlock() { PumpCount = 0, StartIndx = startTimeIndx, EndIndx = splitIndx }); current_best_solution.Items.AddRange(right_solutions.Items); } } } #endregion #region 开机 { for (int pumpNum_left = 1; pumpNum_left <= 4; pumpNum_left++) { if (pumpNum_left == lastOpenPumpCount) continue; for (int splitIndx = startTimeIndx + _minTimeCountSwitch; splitIndx < _timeDataListCount - _minTimeCountSwitch; splitIndx++) { //没有 splitIndx = endTimeIndx的情况,前面已考虑 if (!_timeList[splitIndx].IsSwitchPumpAble) continue; _totalCalcCount++; double sumCompareLeft = 0; double sumFlowLeft = 0; // 获取从开始时间,到结束时间,开pumpNum台泵的流量 //获取从开始时间,到结束时间,开pumpNum台泵的费用 var td = GetTimeDataBundle(pumpNum_left); td.GetRangeData1(startTimeIndx, splitIndx, out sumFlowLeft, out sumCompareLeft); if (sumCompareLeft == double.MaxValue) continue; var total_current_flow = sumFlowLeft + lastTotalFlow; if (total_current_flow >= this._stationTotalFlow) {//左侧已经能达到要求了 if (current_best_solution.TotalCompare > sumCompareLeft) { current_best_solution.TotalCompare = sumCompareLeft; current_best_solution.TotalFlow = sumFlowLeft; current_best_solution.Items = new List() { new RunBlock(){ PumpCount = pumpNum_left , StartIndx = startTimeIndx, EndIndx = splitIndx , TotalCompare = sumCompareLeft, TotalFlow = sumFlowLeft } }; } break;//不用再继续了,再继续 功率只会越来越大 } else { //右侧继续迭代 BlockItemList right_solutions = RecursionFindRight_定水量( total_current_flow, lastSwitchCount + 1, pumpNum_left, splitIndx); if (right_solutions == null || right_solutions.TotalCompare == double.MaxValue) {//没有找到合适的 continue; } double cur_sumPower = sumCompareLeft + right_solutions.TotalCompare; if (current_best_solution.TotalCompare > cur_sumPower) { current_best_solution.TotalCompare = cur_sumPower; current_best_solution.TotalFlow = sumFlowLeft + right_solutions.TotalFlow; current_best_solution.Items = new List(right_solutions.Items); current_best_solution.Items.Insert(0,//在前面插入左侧时间块 new RunBlock() { PumpCount = pumpNum_left, StartIndx = startTimeIndx, EndIndx = splitIndx, TotalCompare = sumCompareLeft, TotalFlow = sumFlowLeft }); } } } } } #endregion } else { } if (current_best_solution.TotalCompare == double.MaxValue) { if (isNeedInsertCache) { _dictCalcCache定水量[startTimeIndx][lastSwitchCount][flowKey] = null; } return null; } else { if (isNeedInsertCache) { _dictCalcCache定水量[startTimeIndx][lastSwitchCount][flowKey] = current_best_solution; } return current_best_solution; } } } }