namespace IStation.Algorithm
{
#region ViewModel
///
///
///
public class FreCombine
{
public FreCombine() { }
public List Flags { get; set; }
public int RunCount { get; set; }
public double Frequency { get; set; }
public double Flow { get; set; }
public double Power { get; set; }
}
///
/// 分析泵项
///
public class OptimalCombine
{
public OptimalCombine() { }
public double Flow { get; set; }
public double Head { get; set; }
public double Power { get; set; }
public List Combines { get; set; }
public List Flags { get; set; }
public int FlagCount { get; set; }
public string Remark { get; set; }
public double MeritRatio { get; set; }
}
#endregion
///
/// 调度分析辅助类
///
public class SchedulingHelper
{
decimal _frequency_min = 25;
decimal _frequency_max = 50;
decimal _frequency_space = 0.1m;//频率间隔
double _start_stop_loss_coefficient = 0.95;//泵启停损失系数
double _sel_opt_flow_deviation_ratio = 0.05;//可选方案的流量偏差比
double _sel_opt_reasonable_flow_deviation_ratio = 0.005;//合理的方案的流量偏差比
#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 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();
public OptimalCombine AnaOptimalCombine(List pumps, List flags_part1, List flags_part2, double target_flow, double target_head, List current_open_pump_flags, List must_open_pump_flags, List must_not_open_pump_flags)
{
if (pumps == null || !pumps.Any())
{
return default;
}
target_flow = Math.Round(target_flow, 1);
target_head = Math.Round(target_head, 1);
#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();
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.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;
}
int start_stop_count = 0;//启停数量
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();
start_stop_count = start_pump_count + close_pump_count;//启停数量
}
else
{
start_stop_count = combine.Count();
if (exist_must_open_pump_flags)
{
start_stop_count = combine.Except(must_open_pump_flags).Count();
}
}
var total_loss_ratio = Math.Pow(_start_stop_loss_coefficient, start_stop_count);//启停一次损失些能耗
combine_merit_ratio *= total_loss_ratio;
List combine_flag_list_part1 = new List();
List combine_flag_list_part2 = new List();
foreach (var pump in combine)
{
if (flags_part1.Contains(pump))
{
combine_flag_list_part1.Add(pump);
}
else
{
combine_flag_list_part2.Add(pump);
}
}
//区分同型号泵
List fre_combine_list_part1 = new List();
List fre_combine_list_part2 = new List();
if (combine_flag_list_part1.Count > 0)
{
var conclusion_list_dic = new Dictionary>();
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();
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>();
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();
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 total_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 < total_flow_deviation)
{
optimal_combine_part1 = fre_combine1;
total_power = fre_combine1.Power;
total_flow = current_flow;
total_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 < total_flow_deviation)
{
optimal_combine_part1 = fre_combine1;
optimal_combine_part2 = fre_combine2;
total_power = fre_combine1.Power + fre_combine2.Power;
total_flow = current_flow;
total_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)
continue;
var total_flow_deviation_ratio = Math.Abs((1 - Math.Abs((total_flow / target_flow))));
if (total_flow_deviation_ratio > _sel_opt_flow_deviation_ratio)
continue;
if (total_flow_deviation_ratio > _sel_opt_reasonable_flow_deviation_ratio)
{
combine_merit_ratio -= total_flow_deviation_ratio;
}
#region 分析最优组合方案
var optimal_combine = new OptimalCombine();
optimal_combine.Combines = new List();
optimal_combine.Flags = new List();
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 = Math.Round(total_flow, 1);
optimal_combine.Power = Math.Round(total_power, 1);
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.MeritRatio = combine_merit_ratio;
optimal_combine.Head = Math.Round(target_head, 1);
optimal_combine_list.Add(optimal_combine);
#endregion
}
}
if (optimal_combine_list.Count < 1)
return default;
optimal_combine_list = optimal_combine_list.OrderByDescending(x => x.MeritRatio).ToList();
return optimal_combine_list.First();
}
public string Ana(List pumps, List flags_part1, List flags_part2, double target_flow, double target_head, List current_open_pump_flags, List must_open_pump_flags, List 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);
#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();
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.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;
}
int start_stop_count = 0;//启停数量
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();
start_stop_count = start_pump_count + close_pump_count;//启停数量
}
else
{
start_stop_count = combine.Count();
if (exist_must_open_pump_flags)
{
start_stop_count = combine.Except(must_open_pump_flags).Count();
}
}
var total_loss_ratio = Math.Pow(_start_stop_loss_coefficient, start_stop_count);//启停一次损失些能耗
combine_merit_ratio *= total_loss_ratio;
List combine_flag_list_part1 = new List();
List combine_flag_list_part2 = new List();
foreach (var pump in combine)
{
if (flags_part1.Contains(pump))
{
combine_flag_list_part1.Add(pump);
}
else
{
combine_flag_list_part2.Add(pump);
}
}
//区分同型号泵
List fre_combine_list_part1 = new List();
List fre_combine_list_part2 = new List();
if (combine_flag_list_part1.Count > 0)
{
var conclusion_list_dic = new Dictionary>();
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();
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>();
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();
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 total_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 < total_flow_deviation)
{
optimal_combine_part1 = fre_combine1;
total_power = fre_combine1.Power;
total_flow = current_flow;
total_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 < total_flow_deviation)
{
optimal_combine_part1 = fre_combine1;
optimal_combine_part2 = fre_combine2;
total_power = fre_combine1.Power + fre_combine2.Power;
total_flow = current_flow;
total_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)
continue;
var total_flow_deviation_ratio = Math.Abs((1 - Math.Abs((total_flow / target_flow))));
if (total_flow_deviation_ratio > _sel_opt_flow_deviation_ratio)
continue;
if (total_flow_deviation_ratio > _sel_opt_reasonable_flow_deviation_ratio)
{
combine_merit_ratio -= total_flow_deviation_ratio;
}
#region 分析最优组合方案
var optimal_combine = new OptimalCombine();
optimal_combine.Combines = new List();
optimal_combine.Flags = new List();
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.FlagCount = optimal_combine.Flags.Count;
optimal_combine.Remark = IntListHelper.ToString(optimal_combine.Flags);
optimal_combine.MeritRatio = combine_merit_ratio;
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.MeritRatio).ToList();
foreach (var opt in optimal_combine_list)
{
sb.AppendLine($"MeritRatio:{opt.MeritRatio.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 void InsertAnaLog(string info)
{
var entity = new Entity.ScheduleAnaLog(info);
_dalAnaLog.Insert(entity);
}
///
/// 判断表是否存在
///
public bool ExistTable(string runFlag)
{
return _dal.ExistTable(runFlag);
}
}
}