namespace IStation.Algorithm
|
{
|
|
#region ViewModel
|
|
/// <summary>
|
///
|
/// </summary>
|
public class FreCombine
|
{
|
public FreCombine() { }
|
public List<int> Flags { get; set; }
|
public int RunCount { get; set; }
|
public double Frequency { get; set; }
|
public double Flow { get; set; }
|
public double Power { get; set; }
|
}
|
|
|
|
/// <summary>
|
/// 分析泵项
|
/// </summary>
|
public class OptimalCombine
|
{
|
public OptimalCombine() { }
|
public double Flow { get; set; }
|
public double Head { get; set; }
|
public double Power { get; set; }
|
public List<FreCombine> Combines { get; set; }
|
public List<int> Flags { get; set; }
|
public int FlagCount { get; set; }
|
public string Remark { get; set; }
|
public double Scale { get; set; }
|
public double OpenPumpRatio { get; set; }
|
}
|
|
#endregion
|
|
/// <summary>
|
/// 调度分析辅助类
|
/// </summary>
|
public class SchedulingHelper
|
{
|
decimal _frequency_min = 25;
|
decimal _frequency_max = 50;
|
decimal _frequency_space = 0.1m;//频率间隔
|
|
double _start_stop_loss_coefficient = 0.95;//泵启停损失系数
|
|
|
#region RunFlag
|
string _falgFrePumpTag = "B";
|
string _falgFixPumpTag = "G";
|
string _falgSpaceMark = "_";
|
|
|
string GetRunFlag(int[] flags)
|
{
|
var runFlag = string.Empty;
|
var index = 0;
|
var count = flags.Length;
|
foreach (var flag in flags)
|
{
|
runFlag += GetGFlag(flag);
|
index++;
|
if (index != count)
|
{
|
runFlag += _falgSpaceMark;
|
}
|
}
|
return runFlag;
|
}
|
|
string GetRunFlag(List<int> flags)
|
{
|
var runFlag = string.Empty;
|
var index = 0;
|
var count = flags.Count;
|
foreach (var flag in flags)
|
{
|
runFlag += GetGFlag(flag);
|
index++;
|
if (index != count)
|
{
|
runFlag += _falgSpaceMark;
|
}
|
}
|
return runFlag;
|
}
|
|
string GetGFlag(int flag)
|
{
|
return _falgFrePumpTag + flag;
|
}
|
|
#endregion
|
|
DAL.ScheduleCombine _dal = new DAL.ScheduleCombine();
|
DAL.ScheduleConclusion _dalScheduleConclusion = new DAL.ScheduleConclusion();
|
DAL.ScheduleAnaLog _dalAnaLog = new DAL.ScheduleAnaLog();
|
|
|
private List<int> _combineFlags1 = new List<int>() { 11, 12, 13, 14, 16, 17, 18 };
|
private List<int> _combineFlags2 = new List<int>() { 15 };
|
|
public string Ana(List<Pump> pumps, double target_flow, double target_head, List<int> current_open_pump_flags, List<int> must_open_pump_flags, List<int> must_not_open_pump_flags)
|
{
|
if (pumps == null || !pumps.Any())
|
{
|
return "无方案:pumps is null";
|
}
|
target_flow = Math.Round(target_flow, 1);
|
target_head = Math.Round(target_head, 1);
|
|
var open_pump_factor = 1 / pumps.Count;
|
|
#region 存在-当前开泵列表
|
|
var exist_current_open_pump_flags = current_open_pump_flags != null && current_open_pump_flags.Count > 0;
|
|
#endregion
|
|
#region 存在-必开泵列表
|
|
var must_open_pump_flags_remark = string.Empty;
|
var exist_must_open_pump_flags = must_open_pump_flags != null && must_open_pump_flags.Count > 0;
|
if (exist_must_open_pump_flags)
|
{
|
must_open_pump_flags = must_open_pump_flags.OrderBy(x => x).ToList();
|
must_open_pump_flags_remark = IntListHelper.ToString(must_open_pump_flags);
|
}
|
|
#endregion
|
|
#region 存在-必不能开泵列表
|
|
var exist_must_not_open_pump_flags = must_not_open_pump_flags != null && must_not_open_pump_flags.Count > 0;
|
|
#endregion
|
|
var pump_flag_list = pumps.Select(x => x.ID).ToList();
|
var optimal_combine_list = new List<OptimalCombine>();
|
for (int pumpCount = 1; pumpCount <= pumps.Count; pumpCount++)
|
{
|
if (pumpCount == 1)
|
{
|
var max_total_flow = pumps.Max(x => x.Qr);
|
if (max_total_flow < target_flow)
|
continue;
|
}
|
var combine_list = PermutationAndCombination<int>.GetCombination(pump_flag_list.ToArray(), pumpCount);//排列组合
|
foreach (var combine in combine_list)
|
{
|
double combine_merit_ratio = 1;//组合择优率
|
if (exist_must_open_pump_flags)
|
{
|
var combine_remark = IntListHelper.ToString(combine.OrderBy(x => x));
|
if (!combine_remark.Contains(must_open_pump_flags_remark))
|
continue;
|
}
|
if (exist_must_not_open_pump_flags)
|
{
|
var exist_intersected = combine.Intersect(must_not_open_pump_flags).Count() > 0;
|
if (exist_intersected)
|
continue;
|
}
|
if (exist_current_open_pump_flags)
|
{
|
var start_pump_count = combine.Except(current_open_pump_flags).Count();
|
var close_pump_count = current_open_pump_flags.Except(combine).Count();
|
var start_stop_count = start_pump_count + close_pump_count;//启停数量
|
var total_loss_ratio = Math.Pow(_start_stop_loss_coefficient, start_stop_count);//启停一次损失些能耗
|
combine_merit_ratio *= total_loss_ratio;
|
}
|
|
List<int> combine_flag_list_part1 = new List<int>();
|
List<int> combine_flag_list_part2 = new List<int>();
|
foreach (var pump in combine)
|
{
|
if (_combineFlags1.Contains(pump))
|
{
|
combine_flag_list_part1.Add(pump);
|
}
|
else
|
{
|
combine_flag_list_part2.Add(pump);
|
}
|
}
|
|
//区分同型号泵
|
List<FreCombine> fre_combine_list_part1 = new List<FreCombine>();
|
List<FreCombine> fre_combine_list_part2 = new List<FreCombine>();
|
|
if (combine_flag_list_part1.Count > 0)
|
{
|
var conclusion_list_dic = new Dictionary<int, List<Entity.ScheduleConclusion>>();
|
foreach (var flag in combine_flag_list_part1)
|
{
|
var runFlag = GetGFlag(flag);
|
if (conclusion_list_dic.ContainsKey(flag))
|
continue;
|
var conclusionList = _dalScheduleConclusion.GetList(runFlag, target_head);
|
conclusion_list_dic[flag] = conclusionList;
|
}
|
|
if (conclusion_list_dic.Count < 1)
|
{
|
continue;
|
}
|
|
for (decimal fre = _frequency_max; fre >= _frequency_min; fre -= _frequency_space)
|
{
|
var freCombine = new FreCombine();
|
freCombine.Frequency = (double)fre;
|
freCombine.Flags = new List<int>();
|
foreach (var item in conclusion_list_dic)
|
{
|
var conclusion = item.Value.Find(x => x.Pump1 == (double)fre);
|
if (conclusion != null)
|
{
|
freCombine.Flags.Add(item.Key);
|
freCombine.Flow += conclusion.Flow;
|
freCombine.Power += conclusion.Power;
|
freCombine.RunCount++;
|
}
|
}
|
if (freCombine.Flags.Count < 1)
|
continue;
|
fre_combine_list_part1.Add(freCombine);
|
}
|
}
|
if (combine_flag_list_part2.Count > 0)
|
{
|
var conclusion_list_dic = new Dictionary<int, List<Entity.ScheduleConclusion>>();
|
foreach (var flag in combine_flag_list_part2)
|
{
|
var runFlag = GetGFlag(flag);
|
if (conclusion_list_dic.ContainsKey(flag))
|
continue;
|
var conclusionList = _dalScheduleConclusion.GetList(runFlag, target_head);
|
conclusion_list_dic[flag] = conclusionList;
|
}
|
|
if (conclusion_list_dic.Count < 1)
|
{
|
continue;
|
}
|
|
for (decimal fre = _frequency_max; fre >= _frequency_min; fre -= _frequency_space)
|
{
|
var freCombine = new FreCombine();
|
freCombine.Frequency = (double)fre;
|
freCombine.Flags = new List<int>();
|
foreach (var item in conclusion_list_dic)
|
{
|
var conclusion = item.Value.Find(x => x.Pump1 == (double)fre);
|
if (conclusion != null)
|
{
|
freCombine.Flags.Add(item.Key);
|
freCombine.Flow += conclusion.Flow;
|
freCombine.Power += conclusion.Power;
|
freCombine.RunCount++;
|
}
|
}
|
if (freCombine.Flags.Count < 1)
|
continue;
|
fre_combine_list_part2.Add(freCombine);
|
}
|
}
|
|
if (fre_combine_list_part1.Count == 0 && fre_combine_list_part2.Count == 0)
|
continue;
|
|
double flow_deviation = target_flow;//流量偏差
|
double total_power = double.MaxValue;//总功率
|
double total_flow = double.MaxValue;//总流量
|
|
FreCombine optimal_combine_part1 = null;
|
FreCombine optimal_combine_part2 = null;
|
if (fre_combine_list_part1.Count < 1 || fre_combine_list_part2.Count < 1)
|
{
|
if (fre_combine_list_part1.Count < 1)
|
{
|
fre_combine_list_part1 = fre_combine_list_part2;
|
}
|
for (int Index_part1 = 0; Index_part1 < fre_combine_list_part1.Count; Index_part1++)
|
{
|
var fre_combine1 = fre_combine_list_part1[Index_part1];
|
var current_flow = fre_combine1.Flow;
|
var current_power = fre_combine1.Power;
|
|
var diff_flow = Math.Abs(current_flow - target_flow);
|
if (diff_flow < flow_deviation)
|
{
|
optimal_combine_part1 = fre_combine1;
|
total_power = fre_combine1.Power;
|
total_flow = current_flow;
|
flow_deviation = diff_flow;
|
}
|
|
if (diff_flow < target_flow * 0.01 && current_power < total_power)
|
{
|
optimal_combine_part1 = fre_combine1;
|
total_power = fre_combine1.Power;
|
total_flow = current_flow;
|
}
|
}
|
}
|
else
|
{
|
for (int Index_part1 = 0; Index_part1 < fre_combine_list_part1.Count; Index_part1++)
|
{
|
for (int Index_part2 = 0; Index_part2 < fre_combine_list_part2.Count; Index_part2++)
|
{
|
var fre_combine1 = fre_combine_list_part1[Index_part1];
|
var fre_combine2 = fre_combine_list_part2[Index_part2];
|
|
var current_flow = fre_combine1.Flow + fre_combine2.Flow;
|
var current_power = fre_combine1.Power + fre_combine2.Power;
|
|
var diff_flow = Math.Abs(current_flow - target_flow);
|
if (diff_flow < flow_deviation)
|
{
|
optimal_combine_part1 = fre_combine1;
|
optimal_combine_part2 = fre_combine2;
|
total_power = fre_combine1.Power + fre_combine2.Power;
|
total_flow = current_flow;
|
flow_deviation = diff_flow;
|
}
|
|
if (diff_flow < target_flow * 0.01 && current_power < total_power)
|
{
|
optimal_combine_part1 = fre_combine1;
|
optimal_combine_part2 = fre_combine2;
|
total_power = fre_combine1.Power + fre_combine2.Power;
|
total_flow = current_flow;
|
}
|
|
}
|
}
|
}
|
|
if (optimal_combine_part1 == null && optimal_combine_part2 == null)
|
return default;
|
|
#region 分析最优组合方案
|
|
var optimal_combine = new OptimalCombine();
|
optimal_combine.Combines = new List<FreCombine>();
|
optimal_combine.Flags = new List<int>();
|
if (optimal_combine_part1 != null)
|
{
|
optimal_combine.Combines.Add(optimal_combine_part1);
|
optimal_combine.Flags.AddRange(optimal_combine_part1.Flags);
|
}
|
if (optimal_combine_part2 != null)
|
{
|
optimal_combine.Combines.Add(optimal_combine_part2);
|
optimal_combine.Flags.AddRange(optimal_combine_part2.Flags);
|
}
|
optimal_combine.OpenPumpRatio = optimal_combine.Flags.Count * open_pump_factor;
|
optimal_combine.Flow = total_flow;
|
optimal_combine.Power = total_power;
|
optimal_combine.Flags = optimal_combine.Flags.OrderBy(x => x).ToList();
|
optimal_combine.FlagCount = optimal_combine.Flags.Count;
|
optimal_combine.Remark = IntListHelper.ToString(optimal_combine.Flags);
|
optimal_combine.Scale = combine_merit_ratio - Math.Abs((1 - Math.Abs((total_flow / target_flow))));
|
|
//if (exist_must_open_pump_flags)
|
//{
|
// var optimal_combine_flag_count = optimal_combine.FlagCount;
|
// var must_open_pump_flag_count = must_open_pump_flags.Count;
|
|
// var open_pump_excess_count = optimal_combine_flag_count - must_open_pump_flag_count;
|
// optimal_combine.Scale *= (1 - (open_pump_excess_count * open_pump_factor));
|
//}
|
optimal_combine.Head = target_head;
|
optimal_combine_list.Add(optimal_combine);
|
|
#endregion
|
}
|
}
|
|
if (optimal_combine_list.Count < 1)
|
return "无方案";
|
|
var sb = new StringBuilder();
|
optimal_combine_list = optimal_combine_list.OrderByDescending(x => x.Scale).ToList();
|
foreach (var opt in optimal_combine_list)
|
{
|
sb.AppendLine($"Scale:{opt.Scale.ToString("N5")},Flow:{opt.Flow.ToString("N1")},Power:{opt.Power.ToString("N1")}," +
|
$"Flags:{opt.Remark};FlowDeviation:{(opt.Flow - target_flow).ToString("N1")}");
|
}
|
return sb.ToString();
|
|
}
|
|
|
private OptimalCombine AnaOptimalCombine(double target_flow, List<FreCombine> fre_combine_list_part1, List<FreCombine> fre_combine_list_part2, List<int> must_open_pump_flags, List<int> must_not_open_pump_flags)
|
{
|
double flow_deviation = target_flow;
|
double total_power = double.MaxValue;
|
double total_flow = double.MaxValue;
|
|
FreCombine optimal_combine_part1 = null;
|
FreCombine optimal_combine_part2 = null;
|
if (fre_combine_list_part1.Count < 1 || fre_combine_list_part2.Count < 1)
|
{
|
for (int Index_part1 = 0; Index_part1 < fre_combine_list_part1.Count; Index_part1++)
|
{
|
var fre_combine1 = fre_combine_list_part1[Index_part1];
|
|
var current_flow = fre_combine1.Flow;
|
var current_power = fre_combine1.Power;
|
|
var diff_flow = Math.Abs(current_flow - target_flow);
|
if (diff_flow < flow_deviation)
|
{
|
optimal_combine_part1 = fre_combine1;
|
total_power = fre_combine1.Power;
|
total_flow = current_flow;
|
flow_deviation = diff_flow;
|
}
|
|
if (diff_flow < target_flow * 0.01 && current_power < total_power)
|
{
|
optimal_combine_part1 = fre_combine1;
|
total_power = fre_combine1.Power;
|
total_flow = current_flow;
|
}
|
}
|
}
|
else
|
{
|
for (int Index_part1 = 0; Index_part1 < fre_combine_list_part1.Count; Index_part1++)
|
{
|
for (int Index_part2 = 0; Index_part2 < fre_combine_list_part2.Count; Index_part2++)
|
{
|
var fre_combine1 = fre_combine_list_part1[Index_part1];
|
var fre_combine2 = fre_combine_list_part2[Index_part2];
|
|
var current_flow = fre_combine1.Flow + fre_combine2.Flow;
|
var current_power = fre_combine1.Power + fre_combine2.Power;
|
|
var diff_flow = Math.Abs(current_flow - target_flow);
|
if (diff_flow < flow_deviation)
|
{
|
optimal_combine_part1 = fre_combine1;
|
optimal_combine_part2 = fre_combine2;
|
total_power = fre_combine1.Power + fre_combine2.Power;
|
total_flow = current_flow;
|
flow_deviation = diff_flow;
|
}
|
|
if (diff_flow < target_flow * 0.01 && current_power < total_power)
|
{
|
optimal_combine_part1 = fre_combine1;
|
optimal_combine_part2 = fre_combine2;
|
total_power = fre_combine1.Power + fre_combine2.Power;
|
total_flow = current_flow;
|
}
|
|
}
|
}
|
}
|
|
if (optimal_combine_part1 == null && optimal_combine_part2 == null)
|
return default;
|
|
var optimal_combine = new OptimalCombine();
|
optimal_combine.Combines = new List<FreCombine>();
|
optimal_combine.Flags = new List<int>();
|
if (optimal_combine_part1 != null)
|
{
|
optimal_combine.Combines.Add(optimal_combine_part1);
|
optimal_combine.Flags.AddRange(optimal_combine_part1.Flags);
|
}
|
if (optimal_combine_part2 != null)
|
{
|
optimal_combine.Combines.Add(optimal_combine_part2);
|
optimal_combine.Flags.AddRange(optimal_combine_part2.Flags);
|
}
|
|
optimal_combine.Flow = total_flow;
|
optimal_combine.Power = total_power;
|
optimal_combine.Flags = optimal_combine.Flags.OrderBy(x => x).ToList();
|
optimal_combine.Remark = IntListHelper.ToString(optimal_combine.Flags);
|
optimal_combine.Scale = 1 * Math.Abs((total_flow / target_flow));
|
return optimal_combine;
|
}
|
|
/// <summary>
|
/// 插入分析日志
|
/// </summary>
|
private void InsertAnaLog(string info)
|
{
|
var entity = new Entity.ScheduleAnaLog(info);
|
_dalAnaLog.Insert(entity);
|
}
|
|
|
/// <summary>
|
/// 判断表是否存在
|
/// </summary>
|
public bool ExistTable(string runFlag)
|
{
|
return _dal.ExistTable(runFlag);
|
}
|
|
}
|
}
|