using IStation.CalcModel;
|
using IStation.Model;
|
using System;
|
using System.Collections.Generic;
|
using System.Linq;
|
using System.Runtime.CompilerServices;
|
|
namespace IStation.Calc
|
{
|
internal partial class ErQuCalcBaseHelper
|
{
|
/// <summary>
|
///
|
/// </summary>
|
/// <returns></returns>
|
public static IStation.Calc.ErQuCalcBaseHelper Build(IStation.CalcModel.AnaRequest anaRequest)
|
{
|
if (anaRequest.MaxLimitWaterBoxLevel != null)
|
{
|
DateTime? limit_time = GetMaxLimitWaterBoxTime(anaRequest);
|
|
if(limit_time == null)
|
{
|
var calc = new IStation.Calc.ErQuCalcHelper_2_递归_定水位_任意时间();
|
calc.SetMaxReservoirHeight(anaRequest.MaxLimitWaterBoxLevel.Value);
|
|
return calc;
|
}
|
else
|
{
|
var calc = new IStation.Calc.ErQuCalcHelper_2_递归_定水位_指定时间();
|
calc.SetMaxReservoirHeight(anaRequest.MaxLimitWaterBoxLevel.Value, limit_time.Value);
|
return calc;
|
}
|
}
|
else
|
{
|
return new IStation.Calc.ErQuCalcHelper_2_递归_定水量();
|
}
|
|
}
|
|
private static DateTime? GetMaxLimitWaterBoxTime(IStation.CalcModel.AnaRequest anaRequest)
|
{
|
if (string.IsNullOrEmpty(anaRequest.MaxLimitWaterBoxTime))
|
{
|
return null;
|
}
|
|
|
DateTime time;
|
if (DateTime.TryParse(anaRequest.MaxLimitWaterBoxTime, out time))
|
{
|
return time;
|
}
|
|
if (anaRequest.MaxLimitWaterBoxTime.Contains(":"))
|
{
|
var sss = anaRequest.MaxLimitWaterBoxTime.Split(':');
|
if(sss.Count() == 2)
|
{
|
int hour = 0;
|
int miut = 0;
|
if (int.TryParse(sss[0], out hour) && int.TryParse(sss[1], out miut))
|
{
|
if (hour < anaRequest.StartTime.Hour)
|
return new DateTime(anaRequest.EndTime.Year, anaRequest.EndTime.Month, anaRequest.EndTime.Day, hour, miut, 0);
|
else
|
return new DateTime(anaRequest.StartTime.Year, anaRequest.StartTime.Month, anaRequest.StartTime.Day, hour, miut, 0);
|
}
|
}
|
}
|
else
|
{
|
int hour = 0;
|
if (int.TryParse(anaRequest.MaxLimitWaterBoxTime, out hour))
|
{
|
if (hour < anaRequest.StartTime.Hour)
|
return new DateTime(anaRequest.EndTime.Year, anaRequest.EndTime.Month, anaRequest.EndTime.Day, hour, 0, 0);
|
else
|
return new DateTime(anaRequest.StartTime.Year, anaRequest.StartTime.Month, anaRequest.StartTime.Day, hour, 0, 0);
|
}
|
|
|
}
|
|
return null;
|
}
|
|
/// <summary>
|
///
|
/// </summary>
|
public class RunBlock
|
{
|
public int PumpCount;
|
public int StartIndx;
|
public int EndIndx;
|
public double TotalCompare;
|
public double TotalFlow;
|
public double ReservoirStartHeight;//水库水位
|
public double ReservoirEndHeight;
|
}
|
|
/// <summary>
|
///
|
/// </summary>
|
protected ErQuCalcBaseHelper()
|
{
|
_calStartTime = DateTime.Now;
|
_calEndTime = DateTime.Now.AddDays(1);
|
}
|
public void SetCalcTimeRange(DateTime calStartTime, DateTime calEndTime)
|
{
|
this._calStartTime = calStartTime;
|
this._calEndTime = calEndTime;
|
}
|
//
|
public Action<string> OnShowDebugInfo = null;
|
|
//排序方式
|
protected IStation.CalcModel.eCalcOptType _clacOptType = CalcModel.eCalcOptType.功率;
|
|
/// <summary>
|
///
|
/// </summary>
|
protected double _stationTotalFlow = 0;//供水总量(不一定有值 单位: 吨)
|
|
/// <summary>
|
///
|
/// </summary>
|
/// <param name="anaRequest"></param>
|
public void SetAnaRequest(IStation.CalcModel.AnaRequest anaRequest)
|
{
|
this._start_level水库水位 = anaRequest.CurrentWaterBoxLevel;
|
this._startOpenCount = anaRequest.StartOpenCount;
|
this._clacOptType = anaRequest.CalcOptType;
|
|
|
|
|
if (anaRequest.TotalFlow取水总量 != null)
|
this._stationTotalFlow = anaRequest.TotalFlow取水总量.Value;
|
|
this.Initial水库参数(anaRequest);
|
|
this.SetRiverWaterLevels(anaRequest.WaterLevels长江);
|
}
|
/// <summary>
|
/// 计算最优
|
/// </summary>
|
/// <param name="TargetFlowTotal"></param>
|
/// <param name="error_info"></param>
|
/// <returns></returns>
|
public virtual List<AnaPrj> CalcOptPrjs(out string error_info)
|
{
|
error_info = null;
|
|
#region 检查数据
|
if (this._calStartTime >= this._calEndTime)
|
{
|
error_info = "时间范围不对";
|
return null;
|
}
|
if (this._allPumpInfo == null || this._allPumpInfo.Count() != 5)
|
{
|
error_info = "泵台数不正确";
|
return null;
|
}
|
if (this._riverWaterLevels == null || this._riverWaterLevels.Count() < 1)
|
{
|
error_info = "长江水位未赋值";
|
return null;
|
}
|
|
if (_listRiverWaterLevelDrop == null)
|
{
|
_listRiverWaterLevelDrop = IStation.AnaGlobalParas.RiverWaterLevelDropList;
|
if (_listRiverWaterLevelDrop == null || _listRiverWaterLevelDrop.Count() == 0)
|
{
|
error_info = "无法读取长江水位与水池落差的关系数据";
|
return null;
|
}
|
}
|
#endregion
|
|
|
|
|
|
|
|
|
List<AnaPrj> listPrj;
|
System.Diagnostics.Stopwatch sw2 = new System.Diagnostics.Stopwatch();
|
sw2.Start();
|
|
//迭代浮动, 不要每次都从0开始, 可能差几分钟更优, 后面此变量也要迭代
|
int dd_minute = 0;
|
//
|
CalcTimeData(dd_minute);
|
|
// 真正开始分析
|
listPrj = CalcOptPrjsCore();
|
sw2.Stop();
|
|
|
var seconds = (int)(sw2.ElapsedMilliseconds / 1000);
|
//故意加1分钟
|
//if (this._calcSpaceMinute >= 5)
|
//{
|
// seconds += 50;
|
// Thread.Sleep(50 * 1000);
|
//}
|
//if (this._calcSpaceMinute == 4)
|
//{
|
// seconds += 20;
|
// Thread.Sleep(20 * 1000);
|
//}
|
|
if (listPrj == null || listPrj.Count == 0)
|
{
|
error_info = "未找到合适的调度方案";
|
return null;
|
}
|
foreach (var prj in listPrj)
|
{
|
prj.StartTime = this._calStartTime;
|
prj.EndTime = this._calEndTime;
|
}
|
|
|
OnShowDebugInfo.Invoke(string.Format("计算用时: {0} 秒", seconds));
|
|
return listPrj;
|
}
|
|
|
/// <summary>
|
///
|
/// </summary>
|
/// <returns></returns>
|
protected virtual List<AnaPrj> CalcOptPrjsCore()
|
{
|
return null;
|
}
|
/// <summary>
|
///
|
/// </summary>
|
protected ulong _totalCalcCount = 0;//计算次数
|
protected ulong _totalCacheCount = 0;//缓存使用次数
|
|
|
|
//时间范围
|
protected DateTime _calStartTime;
|
protected DateTime _calEndTime;
|
|
|
//泵信息
|
internal List<IStation.CalcModel.PumpCurveInfo> _allPumpInfo = null;
|
public void SetPumpInfo(List<IStation.CalcModel.PumpInfo> allPumpInfo)
|
{
|
if (allPumpInfo == null)
|
return;
|
|
this._allPumpInfo = new List<CalcModel.PumpCurveInfo>();
|
for (int k = 0; k < allPumpInfo.Count; k++)
|
{
|
var pump = allPumpInfo[k];
|
|
CalcModel.PumpCurveInfo pumpCurveInfo = new CalcModel.PumpCurveInfo();
|
pumpCurveInfo.ID = pump.ID;
|
pumpCurveInfo.PumpIndex = k;
|
pumpCurveInfo.Name = pump.Name;
|
pumpCurveInfo.CurveInfo = pump.CurveInfo;
|
pumpCurveInfo.RatedParas = pump.RatedParas;
|
|
double spaceQ = (pump.CurveInfo.CurveQH.Max - pump.CurveInfo.CurveQH.Min) / 99;
|
|
List<IStation.Model.GroupPoint> groupPoints = new List<GroupPoint>();
|
for (int i = 0; i < 100; i++)
|
{
|
var q = pump.CurveInfo.CurveQH.Min + spaceQ * i;
|
var h = IStation.Common.FitCurveHelper.GetFitPointY(pump.CurveInfo.CurveQH, q);
|
double eta = 0; // IStation.Common.FitCurveHelper.GetFitPointY(pump.CurveInfo.CurveQE, q);
|
var p = IStation.Common.FitCurveHelper.GetFitPointY(pump.CurveInfo.CurveQP, q);
|
|
groupPoints.Add(new GroupPoint() { Q = q, H = h, E = eta, P = p });
|
}
|
pumpCurveInfo.GroupPoints = groupPoints;
|
|
_allPumpInfo.Add(pumpCurveInfo);
|
}
|
}
|
|
//计算时间跨度
|
protected int _calcSpaceMinute = 5;
|
public int CalcSpaceMinute { get { return _calcSpaceMinute; } set { _calcSpaceMinute = value; } }
|
|
/// <summary>
|
/// 中间最多切换次数
|
/// </summary>
|
protected int _maxPumpSwitchCount = 3;
|
public int MaxPumpSwitchCount { get { return _maxPumpSwitchCount; } set { _maxPumpSwitchCount = value; } }
|
|
/// <summary>
|
/// 不许切泵时间
|
/// </summary>
|
protected List<IStation.CalcModel.TimeRange> _limitSwitchPumpTimes = null;
|
public List<IStation.CalcModel.TimeRange> LimitSwitchPumpTimes { get { return _limitSwitchPumpTimes; } set { _limitSwitchPumpTimes = value; } }
|
|
|
/// <summary>
|
/// 不许开泵时间
|
/// </summary>
|
protected List<IStation.CalcModel.TimeRange> _limitOpenPumpTimes = null;
|
public List<IStation.CalcModel.TimeRange> LimitOpenPumpTimes { get { return _limitOpenPumpTimes; } set { _limitOpenPumpTimes = value; } }
|
|
|
|
|
#region 泵出口压力
|
|
//private void InitialPumpOutletPress()
|
//{
|
// _outBoxLevels = new List<Model.TimeWaterLevel>();
|
// _outBoxLevels.Add(new Model.TimeWaterLevel() { Level = 0.068 * 100 });
|
//}
|
|
///// <summary>
|
///// 出水水池水位
|
///// </summary>
|
//protected List<IStation.Model.TimeWaterLevel> _outBoxLevels = null;
|
|
//暂时固定
|
protected double CalcPumpOutletPressM(DateTime time)
|
{//返回m的单位数值
|
return 0.068 * 100;
|
//return _outBoxLevels.First().Level;
|
}
|
#endregion
|
|
|
/// <summary>
|
/// 获取扬程(暂时简单处理)
|
/// </summary>
|
/// <param name="time"></param>
|
/// <returns></returns>
|
internal double GetPipeHead(DateTime time, TimeDataBundle timeDataBundle)
|
{
|
int openPumpCount = timeDataBundle.OpenPumpInfos.Count;
|
var m2 = CalcPumpOutletPressM(time);
|
var m1 = GetRiverWaterLevelByTime(time);
|
double dropHeight = 0;
|
if (openPumpCount >= 4)
|
{
|
dropHeight = 2.5;
|
}
|
else if (openPumpCount == 3)
|
{
|
dropHeight = 1.54;
|
}
|
else if (openPumpCount == 3)
|
{
|
dropHeight = 0.81;
|
}
|
else if (openPumpCount == 2)
|
{
|
dropHeight = 0.32;
|
}
|
//double totalFlow = 0;
|
//double dropHeight = _listRiverWaterLevelDrop.Last().DropHeight;
|
//if (totalFlow < _listRiverWaterLevelDrop.Last().Flow)
|
//{
|
// for (int i = 0; i < _listRiverWaterLevelDrop.Count; i++)
|
// {
|
// if (totalFlow < _listRiverWaterLevelDrop[i].Flow)
|
// {
|
// dropHeight = _listRiverWaterLevelDrop[i].DropHeight; break;
|
// }
|
// }
|
//}
|
|
|
m1 = m1 - dropHeight;
|
|
|
return (m2 - m1);
|
}
|
|
//电费
|
protected List<ElecPriceMonthSetting> _elecPrice = null;
|
public List<ElecPriceMonthSetting> ElecPrice { get => _elecPrice; set => _elecPrice = value; }
|
public double CalcMoney(DateTime time, double power)
|
{
|
var month = time.Month;
|
var hour = time.Hour;
|
var monthSettings = _elecPrice.Find(x => month >= x.StartMonth && month <= x.EndMonth);
|
var hourList = monthSettings.HourList;
|
//if (hour == 23)
|
//{
|
// var item = hourList.Find(x => x.EndHour == 23);
|
// return power * item.Price;
|
//}
|
//else
|
{
|
var item = hourList.Find(x => hour >= x.StartHour && hour < x.EndHour);
|
return power * item.Price;
|
}
|
}
|
|
|
/// <summary>
|
/// 最少开泵时间
|
/// </summary>
|
public int MinOpenPumpMinute = 30;
|
protected int _minTimeCountOpenPump = 0;
|
public int MinSwitchPumpMinute = 30;
|
protected int _minTimeCountSwitch = 0;
|
|
/// <summary>
|
/// 初始化开机台数
|
/// </summary>
|
protected int _startOpenCount = -1;
|
public int StartOpenCount { get => _startOpenCount; set => _startOpenCount = value; }
|
|
/// <summary>
|
///
|
/// </summary>
|
protected bool isDispDebug = false;
|
public bool IsDispDebug { get => isDispDebug; set => isDispDebug = value; }
|
|
/// <summary>
|
///
|
/// </summary>
|
/// <param name="prj"></param>
|
/// <returns></returns>
|
protected bool CheckPrjItemTimeAble(List<AnaPrjBlockTime> time_items)
|
{
|
if (time_items == null)
|
return false;
|
//if (time_items.Count == 1)
|
//{
|
// for (int i = 0; i < 5; i++)
|
// {
|
// if (time_items[0].OpenPumpIndexs.Contains(i))
|
// {
|
// if ((time_items[0].EndTime - time_items[0].StartTime).TotalMinutes < MinOpenPumpMinute)
|
// return false;
|
// }
|
// }
|
//}
|
|
//if (time_items.Count == 2)
|
//{
|
// for (int i = 0; i < 5; i++)
|
// {
|
// if (time_items[0].OpenPumpIndexs.Contains(i) && time_items[1].OpenPumpIndexs.Contains(i))
|
// {
|
// if ((time_items[1].EndTime - time_items[0].StartTime).TotalMinutes < MinOpenPumpMinute)
|
// return false;
|
// }
|
// if (time_items[0].OpenPumpIndexs.Contains(i) && !time_items[1].OpenPumpIndexs.Contains(i))
|
// {
|
// if ((time_items[0].EndTime - time_items[0].StartTime).TotalMinutes < MinOpenPumpMinute)
|
// return false;
|
// }
|
// if (!time_items[0].OpenPumpIndexs.Contains(i) && time_items[1].OpenPumpIndexs.Contains(i))
|
// {
|
// if ((time_items[1].EndTime - time_items[1].StartTime).TotalMinutes < MinOpenPumpMinute)
|
// return false;
|
// }
|
// }
|
//}
|
|
return true;
|
}
|
}
|
}
|