using IStation.CalcModel;
|
using System;
|
using System.Collections.Generic;
|
using System.ComponentModel;
|
using System.Linq;
|
|
namespace IStation.Calc
|
{
|
/// <summary>
|
/// 定取水总量
|
/// </summary>
|
internal partial class ErQuCalcHelper_2_递归_定水量 : ErQuCalcHelper_2_递归
|
{
|
protected List<List<Dictionary<int, BlockItemList>>> _dictCalcCache定水量;
|
|
/// <summary>
|
///
|
/// </summary>
|
/// <returns></returns>
|
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;
|
|
OnShowDebugInfo.Invoke(string.Format("计算次数:{0:N0}, 缓存使用次数:{1:N0}", this._totalCalcCount, this._totalCacheCount));
|
|
return ToAnaPrj(result);
|
}
|
|
/// <summary>
|
///
|
/// </summary>
|
/// <returns></returns>
|
protected BlockItemList CalcOptPrjsBlockItems定水量()
|
{
|
_dictCalcCache定水量 = new List<List<Dictionary<int, BlockItemList>>>(_timeDataListCount + 1);
|
for (int i = 0; i < _timeDataListCount + 1; i++)
|
{
|
var ak = new List<Dictionary<int, BlockItemList>>(_timeDataListCount + 1);
|
for (int j = 0; j < this.MaxPumpSwitchCount + 2; j++)
|
{
|
ak.Add(new Dictionary<int, BlockItemList>());
|
}
|
_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;
|
}
|
|
/// <summary>
|
///
|
/// </summary>
|
/// <returns></returns>
|
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._flowInTotalFlow)
|
{
|
if (sumCompareWhole < current_best_solution.TotalCompare)
|
{
|
current_best_solution.TotalCompare = sumCompareWhole;
|
current_best_solution.TotalFlow = sumFlowWhole;
|
current_best_solution.Items = new List<RunBlock>()
|
{
|
new RunBlock()
|
{
|
PumpCount = pumpNum_left ,
|
StartIndx = 0,
|
EndIndx = _timeDataListCount-1,
|
TotalCompare = sumCompareWhole,
|
TotalFlow = sumFlowWhole
|
}
|
};
|
}
|
}
|
}
|
|
#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;
|
//右侧继续迭代
|
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<RunBlock>(right_solutions.Items);
|
}
|
}
|
}
|
#endregion
|
|
|
#region 开机
|
//int opt_num = 0;
|
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._flowInTotalFlow)
|
{//左侧已经能达到要求了
|
if (current_best_solution.TotalCompare > sumCompareLeft)
|
{
|
current_best_solution.TotalCompare = sumCompareLeft;
|
current_best_solution.TotalFlow = sumFlowLeft;
|
current_best_solution.Items = new List<RunBlock>() {
|
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<RunBlock>(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;
|
}
|
|
|
/// <summary>
|
/// 递归
|
/// </summary>
|
/// <param name="lastTotalFlow">当前的流量(左侧时间块流量)</param>
|
/// <param name="lastSwitchCount">当前切换次数</param>
|
/// <param name="startTimeIndx">开始时间段角标</param>
|
/// <returns></returns>
|
private BlockItemList RecursionFindRight_定水量(
|
double lastTotalFlow,
|
int lastSwitchCount,
|
int lastOpenPumpCount,
|
int startTimeIndx)
|
{
|
if (lastSwitchCount > this.MaxPumpSwitchCount)
|
{//不能再切换泵了:基本上不会出现,进入前已判断
|
return null;
|
}
|
|
if (lastTotalFlow > this._flowInTotalFlow)
|
{//已达到流量:基本上不会出现,进入前已判断
|
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._flowInTotalFlow)
|
{
|
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<RunBlock>(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._flowInTotalFlow &&
|
sumCompareWhole < current_best_solution.TotalCompare)
|
{
|
current_best_solution.TotalCompare = sumCompareWhole;
|
current_best_solution.TotalFlow = sumFlowWhole;
|
current_best_solution.Items = new List<RunBlock>()
|
{
|
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<RunBlock>(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 <= _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 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._flowInTotalFlow)
|
{//左侧已经能达到要求了
|
if (current_best_solution.TotalCompare > sumCompareLeft)
|
{
|
current_best_solution.TotalCompare = sumCompareLeft;
|
current_best_solution.TotalFlow = sumFlowLeft;
|
current_best_solution.Items = new List<RunBlock>() {
|
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<RunBlock>(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;
|
}
|
}
|
|
}
|
|
|
|
}
|