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 override AnaPrj CalcOptPrjsCore() { _minTimeCountOpenPump = this.MinOpenPumpMinute / this.CalcSpaceMinute; _minTimeCountSwitch = this.MinSwitchPumpMinute / this.CalcSpaceMinute; //this._maxPumpSwitchCount = 5; var result定水量 = CalcOptPrjsBlockItems定水量(); if (result定水量 == null) return null; foreach (var item in result定水量.Items) { if (item.ReservoirStartHeight >= _maxReservoirHeight || item.ReservoirEndHeight >= _maxReservoirHeight) { return ToAnaPrj(result定水量); } } var result = CalcOptPrjsBlockItems_定水位_任意时间(); if (result == null) return null; return ToAnaPrj(result); } /// /// /// /// private BlockItemList CalcOptPrjsBlockItems_定水位_任意时间() { 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; } /// /// /// /// public void SetMaxReservoirHeight(double level水库水位) { _maxReservoirHeight = level水库水位 - 0.02; //放点余量 } protected double _maxReservoirHeight = 0; private bool CheckMaxLevel(double start_level, double end_level) { if (start_level >= this._maxReservoirHeight || end_level >= this._maxReservoirHeight) return true; else return false; } private bool CheckMaxLevel(double start_level, List Items) { if (start_level >= this._maxReservoirHeight) return true; if (Items != null) { foreach (var item in Items) { if (item.ReservoirStartHeight >= this._maxReservoirHeight || item.ReservoirEndHeight >= this._maxReservoirHeight) return true; } } return false; } private bool CheckMaxLevel(double start_level, double middle_level, double end_level) { if (start_level >= this._maxReservoirHeight || middle_level >= this._maxReservoirHeight || end_level >= this._maxReservoirHeight) return true; else return false; } /// /// /// /// 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 <= _maxOpenPumpCount; pumpNum_left++) { if (this._startOpenPumpCount >= 0) { if (this._startOpenPumpCount != 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) { // 结束时的水位 var end_level = CalcReservoirHeight( 0, _timeDataListCount - 1, sumFlowWhole, this._start_level水库水位); if (!CheckMaxLevel(_start_level水库水位, end_level)) {//检查水位 continue; } 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, ReservoirStartHeight = _start_level水库水位, ReservoirEndHeight = end_level } }; } } } #endregion #region 开始 不开机 情况 if (this._startOpenPumpCount == 0 || this._startOpenPumpCount == -1) { for (int splitIndx = startSwitchTimeIndx; splitIndx < _timeDataListCount - _minTimeCountSwitch; splitIndx++) {//_timeList[i].IsLimitSwitch if (!_timeList[splitIndx].IsSwitchPumpAble) continue; //右侧继续迭代 var end_level = CalcReservoirHeight(// 结束时的水位 0, splitIndx, 0, this._start_level水库水位); BlockItemList right_solutions = RecursionFindRight_定水位_任意时间( 0, end_level, this._start_level水库水位, 1, 0, splitIndx); if (right_solutions == null) {//没有找到合适的 continue; } if (current_best_solution.TotalCompare > right_solutions.TotalCompare) { if (!CheckMaxLevel(_start_level水库水位, right_solutions.Items)) {//检查水位 continue; } current_best_solution.TotalCompare = right_solutions.TotalCompare; current_best_solution.TotalFlow = right_solutions.TotalFlow; current_best_solution.Items = new List(right_solutions.Items); } } } #endregion #region 开机 for (int pumpNum_left = 1; pumpNum_left <= _maxOpenPumpCount; pumpNum_left++) { if (this._startOpenPumpCount >= 0) { if (this._startOpenPumpCount != 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) { #region 左侧已经能达到要求了,右边的全关机 if (current_best_solution.TotalCompare > sumCompareLeft) { //左侧结束时的水位 var left_end_level = CalcReservoirHeight( 0, splitIndx, sumFlowLeft, this._start_level水库水位); if (!CheckMaxLevel(_start_level水库水位, left_end_level)) {//检查水位 continue; } 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, ReservoirStartHeight = _start_level水库水位, ReservoirEndHeight = left_end_level } }; } #endregion break;//不用再继续了,再继续 功率只会越来越大 } else { //左侧结束时的水位 var left_end_level = CalcReservoirHeight( 0, splitIndx, sumFlowLeft, this._start_level水库水位); //右侧继续迭代 var left_max_level = Math.Max(_start_level水库水位, left_end_level); BlockItemList right_solutions = RecursionFindRight_定水位_任意时间( sumFlowLeft, left_end_level, left_max_level, 1, pumpNum_left, splitIndx); if (right_solutions == null) {//没有找到合适的 continue; } double cur_sumPower = sumCompareLeft + right_solutions.TotalCompare; if (current_best_solution.TotalCompare > cur_sumPower) { if (!CheckMaxLevel(left_max_level, right_solutions.Items)) {//检查水位 continue; } 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, ReservoirStartHeight = _start_level水库水位, ReservoirEndHeight = left_end_level }); } } } } #endregion if (current_best_solution.TotalCompare == double.MaxValue) return null; return current_best_solution; } /// /// 递归 /// /// 当前的流量(左侧时间块流量) /// 当前的水库水位(左侧时间块) /// 当前切换次数 /// 开始时间段角标 /// BlockItemList RecursionFindRight_定水位_任意时间( double lastTotalFlow, double lastReservoirHeight,//结束时的水位,本次迭代开始时水位 double lastMaxReservoirHeight,//以前的最高水位 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); } if (lastMaxReservoirHeight > this._maxReservoirHeight) { 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; 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; } } } //else //{ // 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; // if (cache_model.TotalFlow + lastTotalFlow >= this._stationTotalFlow && cache_model.Items) // { // 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 <= _maxOpenPumpCount; 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) { //左侧结束时的水位 var left_end_level = CalcReservoirHeight( startTimeIndx, _timeDataListCount - 1, sumFlowWhole, lastReservoirHeight); if (!this.CheckMaxLevel(lastMaxReservoirHeight, left_end_level)) { continue; } 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, ReservoirStartHeight = lastReservoirHeight, ReservoirEndHeight = left_end_level } }; } } #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++; //左侧结束时的水位(右侧开始时) var left_end_level = CalcReservoirHeight( startTimeIndx, splitIndx, 0, lastReservoirHeight); //右侧继续迭代 BlockItemList right_solutions = RecursionFindRight_定水位_任意时间( lastTotalFlow, left_end_level, lastMaxReservoirHeight, lastSwitchCount + 1, 0, splitIndx); if (right_solutions == null || right_solutions.TotalCompare == double.MaxValue) {//没有找到合适的 continue; } if (current_best_solution.TotalCompare > right_solutions.TotalCompare) { if (!this.CheckMaxLevel(lastMaxReservoirHeight, right_solutions.Items)) { continue; } 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, ReservoirStartHeight = lastReservoirHeight, ReservoirEndHeight = left_end_level }); current_best_solution.Items.AddRange(right_solutions.Items); } } } #endregion #region 左侧 开机 { for (int pumpNum_left = 1; pumpNum_left <= _maxOpenPumpCount; 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 left_sumCompareLeft = 0; double left_sumFlowLeft = 0; // 获取从开始时间,到结束时间,开pumpNum台泵的流量 //获取从开始时间,到结束时间,开pumpNum台泵的费用 var td = GetTimeDataBundle(pumpNum_left); td.GetRangeData1(startTimeIndx, splitIndx, out left_sumFlowLeft, out left_sumCompareLeft); if (left_sumCompareLeft == double.MaxValue) continue; var total_current_flow = left_sumFlowLeft + lastTotalFlow; if (total_current_flow >= this._stationTotalFlow) {//左侧已经能达到要求了 if (current_best_solution.TotalCompare > left_sumCompareLeft) { //左侧结束时的水位(右侧开始时) var left_end_level = CalcReservoirHeight( startTimeIndx, splitIndx, left_sumFlowLeft, lastReservoirHeight); if (!this.CheckMaxLevel(lastMaxReservoirHeight, left_end_level)) { continue; } current_best_solution.TotalCompare = left_sumCompareLeft; current_best_solution.TotalFlow = left_sumFlowLeft; current_best_solution.Items = new List() { new RunBlock(){ PumpCount = pumpNum_left , StartIndx = startTimeIndx, EndIndx = splitIndx , TotalCompare = left_sumCompareLeft, TotalFlow = left_sumFlowLeft, ReservoirStartHeight = lastReservoirHeight, ReservoirEndHeight = left_end_level } }; } //break;//不用再继续了,再继续 功率只会越来越大 } else { //左侧结束时的水位 var left_end_level = CalcReservoirHeight( startTimeIndx, splitIndx, left_sumFlowLeft, lastReservoirHeight); var mmm = Math.Max(left_end_level, lastMaxReservoirHeight); //右侧继续迭代 BlockItemList right_solutions = RecursionFindRight_定水位_任意时间( total_current_flow, left_end_level, mmm, lastSwitchCount + 1, pumpNum_left, splitIndx); if (right_solutions == null || right_solutions.TotalCompare == double.MaxValue) {//没有找到合适的 continue; } double cur_sumPower = left_sumCompareLeft + right_solutions.TotalCompare; if (current_best_solution.TotalCompare > cur_sumPower) { if (!this.CheckMaxLevel(mmm, current_best_solution.Items)) { continue; } current_best_solution.TotalCompare = cur_sumPower; current_best_solution.TotalFlow = left_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 = left_sumCompareLeft, TotalFlow = left_sumFlowLeft, ReservoirStartHeight = lastReservoirHeight, ReservoirEndHeight = left_end_level }); } } } } } #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; } } } }