namespace IStation.Service
|
{
|
/// <summary>
|
/// 调度分析辅助类
|
/// </summary>
|
public partial class ScheduleHelper
|
{
|
|
#region ViewModel
|
private class AnalysisConclusionViewModel : Model.AnalysisParameter
|
{
|
public AnalysisConclusionViewModel() { }
|
public AnalysisConclusionViewModel(Model.AnalysisParameter rhs) : base(rhs) { }
|
public AnalysisConclusionViewModel(Model.AnalysisParameter rhs, int flag) : base(rhs)
|
{
|
this.Flag = flag;
|
}
|
public int Flag { get; set; }
|
}
|
#endregion
|
|
#region Private Variable
|
|
private readonly decimal _frequency_min = 25;
|
private readonly decimal _frequency_max = 50;
|
private readonly decimal _frequency_space = 1;//频率间隔
|
|
private readonly double _start_stop_loss_coefficient = 0.95;//泵启停损失系数
|
|
private double _sel_opt_flow_excess = 1;//可选方案的流量余量
|
private readonly double _sel_opt_pump_pressure_excess = 0;//可选方案的单泵扬程默认抬升余量
|
|
private readonly double _sel_opt_flow_deviation_ratio = 0.05;//可选方案的流量偏差比
|
private readonly double _sel_opt_reasonable_flow_deviation_ratio = 0.005;//合理的方案的流量偏差比
|
|
private readonly Service.AnalysisParameter _service_analysis_parameter = new();
|
private readonly Service.AnalysisDeviation _service_analysis_deviation = new();
|
private readonly Service.AnalysisFactor _service_analysis_factor = new();
|
|
private int _min_open_count;//最小开泵数量
|
private int _max_open_count;//最大开泵数量
|
private List<int> _current_open_flag_list = null;// 当前开泵列表
|
private List<int> _must_open_flag_list = null; // 必开泵列表
|
private List<int> _must_close_flag_list = null; // 必关泵列表
|
private List<List<int>> _forbidden_flag_combine_list = null; // 禁用泵组合
|
private List<List<int>> _associative_flag_combine_list = null; // 关联泵组合
|
private List<List<int>> _same_section_flag_combine_list = null; // 同段泵组合
|
private List<Model.WaterSupplyLimit> _water_supply_limit_list = null; //供水限制列表
|
private List<Model.FrequencyLimit> _frequency_limit_list = null; // 频率限制列表
|
private Dictionary<int, double> _flag_cumulative_runtime_dict = null; // 泵累计运行时长字典
|
private List<int> _priority_open_flag_list = null; // 优先开泵列表
|
|
|
private List<Model.AnalysisDeviation> _analysis_deviation_list = null;//分析偏差
|
|
#endregion
|
|
/// <summary>
|
/// 初始化
|
/// </summary>
|
public void Initial(List<int> current_open_flag_list, Model.ScheduleConfig schedule_config, List<Model.AnalysisDeviation> analysis_deviation_list)
|
{
|
|
_current_open_flag_list = current_open_flag_list;
|
_min_open_count = 1;
|
_max_open_count = 0;
|
_must_open_flag_list = null;
|
_must_close_flag_list = null;
|
_forbidden_flag_combine_list = null;
|
_associative_flag_combine_list = null;
|
_same_section_flag_combine_list = null;
|
_water_supply_limit_list = null;
|
_frequency_limit_list = null;
|
_flag_cumulative_runtime_dict = null;
|
_priority_open_flag_list = null;
|
if (schedule_config != null)
|
{
|
_min_open_count = schedule_config.MinOpenCount;
|
_max_open_count = schedule_config.MaxOpenCount;
|
_must_open_flag_list = schedule_config.MustOpenFlagList;
|
_must_close_flag_list = schedule_config.MustCloseFlagList;
|
_forbidden_flag_combine_list = schedule_config.ForbiddenFlagCombineList;
|
_associative_flag_combine_list = schedule_config.AssociativeFlagCombineList;
|
_same_section_flag_combine_list = schedule_config.SameSectionFlagCombineList;
|
_water_supply_limit_list = schedule_config.WaterSupplyLimitList;
|
_frequency_limit_list = schedule_config.FrequencyLimitList;
|
_flag_cumulative_runtime_dict = schedule_config.FlagCumulativeRuntimeDict;
|
_priority_open_flag_list = schedule_config.PriorityOpenFlagList;
|
}
|
|
_analysis_deviation_list = analysis_deviation_list;
|
|
}
|
|
|
#region OptAnaCombine
|
|
/// <summary>
|
/// 获取最优组合
|
/// </summary>
|
/// <param name="pump_list"></param>
|
/// <param name="flag_inlet_water_level_dict"></param>
|
/// <param name="target_flow"></param>
|
/// <param name="target_pressure"></param>
|
/// <returns></returns>
|
public AnaCombine GetOptAnaCombine
|
(
|
List<Model.Pump> pump_list,
|
Dictionary<int, double> flag_inlet_water_level_dict,
|
double target_flow,
|
double target_pressure
|
)
|
{
|
|
#region 初始化参数
|
if (pump_list == null || !pump_list.Any())
|
{
|
return default;
|
}
|
|
var current_open_flag_list = _current_open_flag_list;
|
var min_open_count = _min_open_count;
|
var max_open_count = _max_open_count < 1 ? pump_list.Count : _max_open_count;
|
var must_open_flag_list = _must_open_flag_list;
|
var must_close_flag_list = _must_close_flag_list;
|
var forbidden_flag_combine_list = _forbidden_flag_combine_list;
|
var associative_flag_combine_list = _associative_flag_combine_list;
|
var same_section_flag_combine_list = _same_section_flag_combine_list;
|
var water_supply_limit_list = _water_supply_limit_list;
|
var frequency_limit_list = _frequency_limit_list;
|
var flag_cumulative_runtime_dict = _flag_cumulative_runtime_dict;
|
var priority_open_flag_list = _priority_open_flag_list;
|
|
var pump_bp_dict = pump_list.ToDictionary(x => x.Flag, x => x.IsBp);
|
var pump_nr_dict = pump_list.ToDictionary(x => x.Flag, x => x.Nr);
|
var pump_flag_list = pump_list.Select(x => x.Flag).ToList();
|
|
var combine_merit_ratio = 1d;//组合择优率
|
|
target_flow = Math.Round(target_flow, 1);
|
target_pressure = Math.Round(target_pressure, 1);
|
|
#endregion
|
|
#region 初始化规则
|
|
#region 存在-必开泵列表
|
|
var must_open_flag_list_remark = string.Empty;
|
var exist_must_open_flag_list = must_open_flag_list != null && must_open_flag_list.Count > 0;
|
if (exist_must_open_flag_list)
|
{
|
must_open_flag_list = must_open_flag_list.OrderBy(x => x).ToList();
|
must_open_flag_list_remark = IntListHelper.ToString(must_open_flag_list);
|
}
|
|
#endregion
|
|
#region 存在-必关泵列表
|
|
var exist_must_close_flag_list = must_close_flag_list != null && must_close_flag_list.Count > 0;
|
|
#endregion
|
|
#region 存在-禁用组合
|
|
var exist_forbidden_flag_combine_list = forbidden_flag_combine_list != null && forbidden_flag_combine_list.Count > 0;
|
|
#endregion
|
|
#region 存在-关联组合
|
|
var exist_associative_flag_combine_list = associative_flag_combine_list != null && associative_flag_combine_list.Count > 0;
|
|
#endregion
|
|
#region 存在-同段泵组合
|
|
Dictionary<int, List<int[]>> same_section_combine_dict = new();
|
var exist_same_section_flag_combine_list = same_section_flag_combine_list != null && same_section_flag_combine_list.Count > 0;
|
if (exist_same_section_flag_combine_list)
|
{
|
same_section_combine_dict = GetSameSectionCombineDict(same_section_flag_combine_list, pump_list.Count);
|
}
|
|
#endregion
|
|
#region 存在-供水限制
|
|
var exist_water_supply_limit_list = water_supply_limit_list != null && water_supply_limit_list.Count > 0;
|
if (exist_water_supply_limit_list)
|
{
|
var water_supply_min = water_supply_limit_list.Min(x => x.Min);
|
var water_supply_max = water_supply_limit_list.Max(x => x.Max);
|
|
#if DEBUG
|
water_supply_min = 0;
|
#endif
|
if (target_flow < water_supply_min || target_flow > water_supply_max)
|
{
|
return default;
|
}
|
}
|
|
#endregion
|
|
#region 存在-频率限制
|
|
var frequency_limit_flag_dict = new Dictionary<int, Model.FrequencyLimit>();
|
var exist_frequency_limit_list = frequency_limit_list != null && frequency_limit_list.Count > 0;
|
if (exist_frequency_limit_list)
|
{
|
frequency_limit_flag_dict = frequency_limit_list.ToDictionary(x => x.Flag, x => x);
|
}
|
|
#endregion
|
|
#region 存在-泵累计运行时长字典
|
|
var flag_cumulative_runtime_loss_ratio_dict = new Dictionary<int, double>();
|
var exist_flag_cumulative_runtime_dict = flag_cumulative_runtime_dict != null && flag_cumulative_runtime_dict.Count > 0;
|
if (exist_flag_cumulative_runtime_dict)
|
{
|
flag_cumulative_runtime_loss_ratio_dict = GetFlagCumulativeRuntimeLossRatioDict(flag_cumulative_runtime_dict);
|
}
|
#endregion
|
|
#region 存在-优先开泵列表
|
|
var priority_open_flag_list_remark = string.Empty;
|
var exist_priority_open_flag_list = priority_open_flag_list != null && priority_open_flag_list.Count > 0;
|
if (exist_priority_open_flag_list)
|
{
|
priority_open_flag_list = priority_open_flag_list.OrderBy(x => x).ToList();
|
priority_open_flag_list_remark = IntListHelper.ToString(priority_open_flag_list);
|
}
|
|
#endregion
|
|
#region 存在-当前开泵列表 (是否切泵)
|
|
var exist_current_open_flag_list = current_open_flag_list != null && current_open_flag_list.Count > 0;
|
if (exist_current_open_flag_list)
|
{
|
//供水限制
|
var exist_limit = false;
|
if (exist_water_supply_limit_list)
|
{
|
var limit = water_supply_limit_list.Find(x => x.PumpCount == current_open_flag_list.Count);
|
if (limit != null)
|
{
|
if (target_flow < limit.Min || target_flow > limit.Max)
|
{
|
exist_limit = true;
|
}
|
}
|
}
|
if (!exist_limit)
|
{
|
var opt_ana_combine = GetOptAnaCombine
|
(
|
current_open_flag_list,
|
combine_merit_ratio,
|
flag_inlet_water_level_dict,
|
pump_nr_dict,
|
pump_bp_dict,
|
exist_frequency_limit_list,
|
frequency_limit_flag_dict,
|
target_flow,
|
target_pressure
|
);
|
if (opt_ana_combine != null)
|
return opt_ana_combine;
|
}
|
}
|
|
#endregion
|
|
|
#endregion
|
|
#region 调度分析
|
|
var opt_ana_combine_list = new List<AnaCombine>();
|
for (int pump_count = min_open_count; pump_count <= max_open_count; pump_count++)
|
{
|
if (pump_count == 1)
|
{
|
var max_total_flow = pump_list.Max(x => x.Qr);
|
if (max_total_flow < target_flow)
|
continue;
|
}
|
|
#region 供水限制
|
|
//供水限制
|
if (exist_water_supply_limit_list)
|
{
|
var exist_limit = false;
|
foreach (var limit in water_supply_limit_list)
|
{
|
if (limit.PumpCount == pump_count)
|
{
|
if (target_flow < limit.Min || target_flow > limit.Max)
|
{
|
exist_limit = true;
|
break;
|
}
|
}
|
}
|
if (exist_limit)
|
continue;
|
}
|
|
#endregion
|
|
var combine_list = GetCombineList(pump_flag_list, pump_count);//排列组合
|
foreach (var combine in combine_list)
|
{
|
combine_merit_ratio = 1;
|
|
#region 规则过滤
|
//必开
|
if (exist_must_open_flag_list)
|
{
|
var combine_remark = IntListHelper.ToString(combine.OrderBy(x => x));
|
if (!combine_remark.Contains(must_open_flag_list_remark))
|
continue;
|
}
|
|
//必关
|
if (exist_must_close_flag_list)
|
{
|
var exist_intersected = combine.Intersect(must_close_flag_list).Count() > 0;
|
if (exist_intersected)
|
continue;
|
}
|
|
|
//禁用组合
|
if (exist_forbidden_flag_combine_list)
|
{
|
var exist_equal = false;
|
foreach (var flag_list in forbidden_flag_combine_list)
|
{
|
if (combine.SequenceEqual(flag_list))
|
{
|
exist_equal = true;
|
break;
|
}
|
}
|
if (exist_equal)
|
continue;
|
}
|
|
//同段泵组合
|
if (exist_same_section_flag_combine_list)
|
{
|
var exist_equal = false;
|
foreach (var flag_list in same_section_combine_dict[pump_count])
|
{
|
//相同
|
if (combine.SequenceEqual(flag_list))
|
{
|
exist_equal = true;
|
break;
|
}
|
|
//包含
|
if (flag_list.Intersect(combine).Count() == flag_list.Length)
|
{
|
exist_equal = true;
|
break;
|
}
|
}
|
if (exist_equal)
|
continue;
|
}
|
|
//关联组合
|
if (exist_associative_flag_combine_list)
|
{
|
var exist_intersected = false;
|
foreach (var flag_list in associative_flag_combine_list)
|
{
|
var except_count = combine.Except(flag_list).Count();
|
if (except_count != flag_list.Count && except_count > 0)
|
{
|
exist_intersected = true;
|
}
|
}
|
if (exist_intersected)
|
continue;
|
}
|
|
//当前开泵列表
|
int start_stop_count = 0;//启停数量
|
if (exist_current_open_flag_list)
|
{
|
var start_pump_count = combine.Except(current_open_flag_list).Count();
|
var close_pump_count = current_open_flag_list.Except(combine).Count();
|
start_stop_count = start_pump_count + close_pump_count;//启停数量
|
}
|
else
|
{
|
start_stop_count = combine.Count();
|
if (exist_must_open_flag_list)
|
{
|
start_stop_count = combine.Except(must_open_flag_list).Count();
|
}
|
}
|
|
//泵累计运行时长(待验证)
|
if (exist_flag_cumulative_runtime_dict)
|
{
|
flag_cumulative_runtime_loss_ratio_dict = GetFlagCumulativeRuntimeLossRatioDict(flag_cumulative_runtime_dict);
|
foreach (var flag in combine)
|
{
|
var loss_ratio = flag_cumulative_runtime_loss_ratio_dict[flag];
|
combine_merit_ratio *= loss_ratio;
|
}
|
}
|
|
//优先开泵列表
|
if (exist_priority_open_flag_list)
|
{
|
//foreach (var flag in priority_open_flag_list)
|
//{
|
// if (combine.Contains(flag))
|
// {
|
// combine_merit_ratio *= 1.05;
|
// }
|
//}
|
|
//目前逻辑 优先开泵==必开方案
|
var combine_remark = IntListHelper.ToString(combine.OrderBy(x => x));
|
if (!combine_remark.Contains(priority_open_flag_list_remark))
|
continue;
|
}
|
|
#endregion
|
|
var total_loss_ratio = Math.Pow(_start_stop_loss_coefficient, start_stop_count);//启停一次损失些能耗
|
combine_merit_ratio *= total_loss_ratio;
|
|
var opt_ana_combine = GetOptAnaCombine
|
(
|
combine,
|
combine_merit_ratio,
|
flag_inlet_water_level_dict,
|
pump_nr_dict,
|
pump_bp_dict,
|
exist_frequency_limit_list,
|
frequency_limit_flag_dict,
|
target_flow,
|
target_pressure
|
);
|
if (opt_ana_combine == null)
|
continue;
|
opt_ana_combine_list.Add(opt_ana_combine);
|
}
|
|
//如果当前循环已经满足,不需要再加泵
|
if (opt_ana_combine_list.Any())
|
{
|
break;
|
}
|
}
|
|
if (opt_ana_combine_list.Count < 1)
|
return default;
|
|
opt_ana_combine_list = opt_ana_combine_list.OrderBy(x => x.TotalPower).OrderByDescending(x => x.MeritRatio).ToList();
|
var opt = opt_ana_combine_list.First();
|
opt.Round();
|
return opt;
|
|
#endregion
|
|
}
|
|
|
/// <summary>
|
/// 获取最优组合
|
/// </summary>
|
/// <param name="combine"></param>
|
/// <param name="combine_merit_ratio"></param>
|
/// <param name="flag_inlet_water_level_dict"></param>
|
/// <param name="pump_nr_dict"></param>
|
/// <param name="pump_bp_dict"></param>
|
/// <param name="exist_frequency_limit_list"></param>
|
/// <param name="frequency_limit_flag_dict"></param>
|
/// <param name="target_flow"></param>
|
/// <param name="target_pressure"></param>
|
/// <returns></returns>
|
private AnaCombine GetOptAnaCombine
|
(
|
IEnumerable<int> combine,
|
double combine_merit_ratio,
|
Dictionary<int, double> flag_inlet_water_level_dict,
|
Dictionary<int, double> pump_nr_dict,
|
Dictionary<int, bool> pump_bp_dict,
|
bool exist_frequency_limit_list,
|
Dictionary<int, Model.FrequencyLimit> frequency_limit_flag_dict,
|
double target_flow,
|
double target_pressure
|
)
|
{
|
if (combine == null || !combine.Any())
|
return default;
|
|
//先修正组合曲线和模型的偏差扬程
|
var combine_deviation_factor_dict = GetCombineDeviationFactorDict(target_flow, combine);
|
var conclusion_ex_list_list = new List<List<AnalysisConclusionViewModel>>();
|
var conclusion_ex_list_dict = new Dictionary<int, List<AnalysisConclusionViewModel>>();
|
double max_supply_flow = 0;
|
foreach (var flag in combine)
|
{
|
var run_flag = RunFlagHelper.Get(flag, pump_bp_dict[flag]);
|
|
//进口水位
|
var inlet_water_level = flag_inlet_water_level_dict[flag];
|
|
//组合偏差系数
|
var combine_deviation_factor = combine_deviation_factor_dict[flag];
|
var current_pressure_diff = target_pressure - inlet_water_level + combine_deviation_factor + _sel_opt_pump_pressure_excess;
|
current_pressure_diff = Math.Round(current_pressure_diff, 1);
|
|
//频率限制
|
var conclusion_list = new List<Model.AnalysisParameter>();
|
if (exist_frequency_limit_list && frequency_limit_flag_dict.ContainsKey(flag))
|
{
|
var limit = frequency_limit_flag_dict[flag];
|
conclusion_list = _service_analysis_parameter.GetList(run_flag, limit.Min, limit.Max, current_pressure_diff);
|
}
|
else
|
{
|
|
//定频泵 可能最小压差超过目标压差
|
var min_pressure_diff_conclusion = _service_analysis_parameter.GetMinPressureDiff(run_flag);
|
if (min_pressure_diff_conclusion != null && min_pressure_diff_conclusion.PressureDiff > current_pressure_diff)
|
{
|
conclusion_list = new List<Model.AnalysisParameter>() { min_pressure_diff_conclusion };
|
}
|
else
|
{
|
var is_bp = pump_bp_dict[flag];
|
if (is_bp)
|
{
|
conclusion_list = _service_analysis_parameter.GetList(run_flag, current_pressure_diff);
|
}
|
else
|
{
|
conclusion_list = new List<Model.AnalysisParameter>() { min_pressure_diff_conclusion };
|
}
|
}
|
}
|
if (conclusion_list == null || !conclusion_list.Any())
|
{
|
break;
|
}
|
max_supply_flow += conclusion_list.Max(x => x.Flow);
|
var conclusion_ex_list = conclusion_list.Select(x => new AnalysisConclusionViewModel(x, flag)).ToList();
|
conclusion_ex_list_list.Add(conclusion_ex_list);
|
conclusion_ex_list_dict[flag] = conclusion_ex_list;
|
}
|
|
if (conclusion_ex_list_list.Count != combine.Count())
|
return default;
|
|
if (max_supply_flow < target_flow * _sel_opt_flow_excess)
|
{
|
if (GlobalHelper.IsStation1(combine))
|
{
|
_sel_opt_flow_excess= 0.995;
|
}
|
var flow_excess = target_flow * _sel_opt_flow_excess;
|
if (max_supply_flow < flow_excess)
|
return default;
|
|
}
|
|
var opt_ana_combine = GetOptAnaCombine(conclusion_ex_list_dict, pump_nr_dict, pump_bp_dict, target_flow);
|
if (opt_ana_combine == null)
|
return default;
|
|
var total_flow = opt_ana_combine.TotalFlow;
|
var total_power = opt_ana_combine.TotalPower;
|
if (total_flow < target_flow * _sel_opt_flow_excess)
|
return default;
|
|
|
var total_flow_deviation_ratio = Math.Abs(1 - Math.Abs(total_flow / target_flow));
|
if (total_flow_deviation_ratio > _sel_opt_flow_deviation_ratio)
|
return default;
|
if (total_flow_deviation_ratio > _sel_opt_reasonable_flow_deviation_ratio)
|
{
|
combine_merit_ratio -= total_flow_deviation_ratio;
|
}
|
|
double eff = 0, wp = 0, uwp = 0;
|
wp = Curve.PumpCalculateHelper.CalculateWP(total_power, total_flow);
|
foreach (var ana_pump in opt_ana_combine.AnaFrePumps)
|
{
|
var pump_flow = ana_pump.Flow;
|
var pump_eff = ana_pump.Eff;
|
var pump_uwp = ana_pump.UWP;
|
|
eff += pump_eff * pump_flow / total_flow;
|
uwp += pump_uwp * pump_flow / total_flow;
|
}
|
|
opt_ana_combine.TotalFlow = total_flow;
|
opt_ana_combine.TotalPressure = target_pressure;
|
opt_ana_combine.TotalPower = total_power;
|
opt_ana_combine.TotalEfficiency = eff;
|
opt_ana_combine.WP = wp;
|
opt_ana_combine.UWP = uwp;
|
opt_ana_combine.MeritRatio = combine_merit_ratio;
|
return opt_ana_combine;
|
|
}
|
|
|
/// <summary>
|
/// 获取最优组合
|
/// </summary>
|
/// <param name="conclusion_ex_list_dict"></param>
|
/// <param name="pump_nr_dict"></param>
|
/// <param name="pump_bp_dict"></param>
|
/// <param name="target_flow"></param>
|
/// <returns></returns>
|
private AnaCombine GetOptAnaCombine(
|
Dictionary<int, List<AnalysisConclusionViewModel>> conclusion_ex_list_dict,
|
Dictionary<int, double> pump_nr_dict,
|
Dictionary<int, bool> pump_bp_dict,
|
double target_flow
|
)
|
{
|
if (conclusion_ex_list_dict == null || !conclusion_ex_list_dict.Any())
|
return default;
|
var frequency_min = (double)_frequency_min;
|
var frequency_max = (double)_frequency_max;
|
var frequency_space = (double)_frequency_space;
|
|
var all_fre_conclusion_ex_list_list = new List<List<AnalysisConclusionViewModel>>();
|
var all_fix_conclusion_ex_list_list = new List<List<AnalysisConclusionViewModel>>();
|
foreach (var item in conclusion_ex_list_dict)
|
{
|
var flag = item.Key;
|
var cl_list = item.Value;
|
if (pump_bp_dict[flag])
|
{
|
all_fre_conclusion_ex_list_list.Add(cl_list);
|
}
|
else
|
{
|
all_fix_conclusion_ex_list_list.Add(cl_list);
|
}
|
}
|
var cl_ex_list_list_list = new List<List<List<AnalysisConclusionViewModel>>>();
|
|
|
//默认1hz内能求出满足目标需求的排列组合,不满足继续迭代
|
var frequency_iteration_count = 5;//频率迭代次数
|
var frequency_iteration_space = 1d;//频率迭代间隔
|
for (int i = 0; i < frequency_iteration_count; i++)
|
{
|
var current_frequency_space = frequency_space + (i * frequency_iteration_space);
|
cl_ex_list_list_list = FrequencyFilters(target_flow, frequency_min, frequency_max, current_frequency_space, all_fre_conclusion_ex_list_list, all_fix_conclusion_ex_list_list);
|
if (cl_ex_list_list_list.Any())
|
{
|
break;
|
}
|
}
|
|
if (!cl_ex_list_list_list.Any())
|
{
|
return default;
|
}
|
|
//分组排列组合求最优
|
var ana_combine_list = new List<AnaCombine>();
|
foreach (var item_cl_ex_list_list in cl_ex_list_list_list)
|
{
|
var cl_ex_list_list = CartesianProduct(item_cl_ex_list_list, target_flow);
|
var opt_cl_ex_list = cl_ex_list_list.OrderBy(x => x.Sum(x => x.Power)).FirstOrDefault();
|
if (opt_cl_ex_list != null && opt_cl_ex_list.Any())
|
{
|
var ana_combine = new AnaCombine();
|
ana_combine.Flags = new List<int>();
|
ana_combine.AnaFrePumps = new List<AnaFrePump>();
|
foreach (var opt_cl_ex in opt_cl_ex_list)
|
{
|
var flag = opt_cl_ex.Flag;
|
ana_combine.Flags.Add(flag);
|
ana_combine.TotalFlow += opt_cl_ex.Flow;
|
ana_combine.TotalPower += opt_cl_ex.Power;
|
|
var ana_fre_pump = new AnaFrePump();
|
ana_fre_pump.Flag = flag;
|
ana_fre_pump.Flow = opt_cl_ex.Flow;
|
ana_fre_pump.Head = opt_cl_ex.Head;
|
ana_fre_pump.PressureDiff = opt_cl_ex.PressureDiff;
|
ana_fre_pump.Power = opt_cl_ex.Power;
|
ana_fre_pump.Eff = PumpCalculateHelper.CalculateE(ana_fre_pump.Flow, ana_fre_pump.Head, ana_fre_pump.Power);
|
ana_fre_pump.WP = PumpCalculateHelper.CalculateWP(ana_fre_pump.Power, ana_fre_pump.Flow);
|
ana_fre_pump.UWP = PumpCalculateHelper.CalculateUWP(ana_fre_pump.Power, ana_fre_pump.Flow, ana_fre_pump.Head);
|
ana_fre_pump.Frequency = opt_cl_ex.Hz;
|
ana_fre_pump.Speed = opt_cl_ex.Hz / 50 * pump_nr_dict[flag];
|
ana_combine.AnaFrePumps.Add(ana_fre_pump);
|
}
|
|
ana_combine.FlagCount = opt_cl_ex_list.Count;
|
ana_combine.Remark = IntListHelper.ToString(ana_combine.Flags);
|
ana_combine_list.Add(ana_combine);
|
}
|
}
|
if (!ana_combine_list.Any())
|
return default;
|
var opt_ana_combine = ana_combine_list.OrderBy(x => x.TotalPower).First();
|
return opt_ana_combine;
|
}
|
|
|
/// <summary>
|
/// 获取同段泵组合
|
/// </summary>
|
/// <param name="same_section_flag_combine_list"></param>
|
/// <param name="pump_list_count"></param>
|
/// <returns></returns>
|
public Dictionary<int, List<int[]>> GetSameSectionCombineDict(List<List<int>> same_section_flag_combine_list, int pump_list_count)
|
{
|
Dictionary<int, List<int[]>> same_section_combine_dict = new();
|
for (int pump_count = 1; pump_count <= pump_list_count; pump_count++)
|
{
|
same_section_combine_dict[pump_count] = new List<int[]>();
|
switch (pump_count)
|
{
|
case 2:
|
{
|
foreach (var same_section_flag_combine in same_section_flag_combine_list)
|
{
|
var combine_list = GetCombineList(same_section_flag_combine, 2);
|
same_section_combine_dict[pump_count].AddRange(combine_list);
|
}
|
}
|
break;
|
case 3:
|
{
|
foreach (var same_section in same_section_flag_combine_list)
|
{
|
var combine_list = GetCombineList(same_section, 3);
|
same_section_combine_dict[pump_count].AddRange(combine_list);
|
}
|
}
|
break;
|
case 4:
|
{
|
foreach (var same_section in same_section_flag_combine_list)
|
{
|
var combine_list3 = GetCombineList(same_section, 3);
|
same_section_combine_dict[pump_count].AddRange(combine_list3);
|
if (same_section.Count > 3)
|
{
|
var combine_list = GetCombineList(same_section, 4);
|
same_section_combine_dict[pump_count].AddRange(combine_list);
|
}
|
}
|
}
|
break;
|
case 5:
|
{
|
foreach (var same_section in same_section_flag_combine_list)
|
{
|
if (same_section.Count > 3)
|
{
|
var combine_list = GetCombineList(same_section, 4);
|
same_section_combine_dict[pump_count].AddRange(combine_list);
|
}
|
}
|
}
|
break;
|
case 6:
|
{
|
foreach (var same_section in same_section_flag_combine_list)
|
{
|
if (same_section.Count > 3)
|
{
|
var combine_list = GetCombineList(same_section, 4);
|
same_section_combine_dict[pump_count].AddRange(combine_list);
|
}
|
}
|
}
|
break;
|
default:
|
break;
|
}
|
}
|
|
return same_section_combine_dict;
|
}
|
|
/// <summary>
|
/// 获取泵累计运行时长损失系数字典
|
/// </summary>
|
/// <param name="flag_cumulative_runtime_dict"></param>
|
/// <returns></returns>
|
public Dictionary<int, double> GetFlagCumulativeRuntimeLossRatioDict(Dictionary<int, double> flag_cumulative_runtime_dict)
|
{
|
var rating_value = 24 * 5;
|
var flag_cumulative_runtime_loss_ratio_dict = new Dictionary<int, double>();
|
foreach (var item in flag_cumulative_runtime_dict)
|
{
|
var flag = item.Key;
|
var cumulative_runtime = item.Value;
|
var level = cumulative_runtime / rating_value / 100;
|
var loss_ratio = 1 - level;
|
flag_cumulative_runtime_loss_ratio_dict.Add(flag, loss_ratio);
|
}
|
return flag_cumulative_runtime_loss_ratio_dict;
|
}
|
|
/// <summary>
|
/// 过滤频率分组
|
/// </summary>
|
/// <param name="target_flow"></param>
|
/// <param name="frequency_min"></param>
|
/// <param name="frequency_max"></param>
|
/// <param name="frequency_space"></param>
|
/// <param name="all_fre_conclusion_ex_list_list"></param>
|
/// <param name="all_fix_conclusion_ex_list_list"></param>
|
/// <returns></returns>
|
private List<List<List<AnalysisConclusionViewModel>>> FrequencyFilters(
|
double target_flow,
|
double frequency_min,
|
double frequency_max,
|
double frequency_space,
|
List<List<AnalysisConclusionViewModel>> all_fre_conclusion_ex_list_list,
|
List<List<AnalysisConclusionViewModel>> all_fix_conclusion_ex_list_list)
|
{
|
double fix_total_flow = 0;
|
var exist_all_fix_conclusion_ex_list_list = all_fix_conclusion_ex_list_list.Any();
|
if (exist_all_fix_conclusion_ex_list_list)
|
{
|
fix_total_flow = all_fix_conclusion_ex_list_list.Sum(x => x.Sum(x => x.Flow));
|
}
|
|
//频率按间隔分组
|
var cl_ex_list_list_list = new List<List<List<AnalysisConclusionViewModel>>>();
|
for (double fre_current_min = frequency_min; fre_current_min <= frequency_max; fre_current_min++)
|
{
|
var fre_current_max = fre_current_min + frequency_space;
|
var skip_current = false;
|
var total_flow_current = 0d;
|
var cl_ex_list_list = new List<List<AnalysisConclusionViewModel>>();
|
foreach (var conclusion_ex_list in all_fre_conclusion_ex_list_list)
|
{
|
var cl_ex_list = conclusion_ex_list.Where(x => x.Hz <= fre_current_max && x.Hz >= fre_current_min).ToList();
|
if (cl_ex_list == null || !cl_ex_list.Any())
|
{
|
skip_current = true;
|
break;
|
}
|
total_flow_current += cl_ex_list.Max(x => x.Flow);
|
cl_ex_list_list.Add(cl_ex_list);
|
}
|
if (skip_current)
|
continue;
|
if (exist_all_fix_conclusion_ex_list_list)
|
{
|
total_flow_current += fix_total_flow;
|
cl_ex_list_list.AddRange(all_fix_conclusion_ex_list_list);
|
}
|
if (total_flow_current < target_flow * _sel_opt_flow_excess)
|
continue;
|
cl_ex_list_list_list.Add(cl_ex_list_list);
|
}
|
return cl_ex_list_list_list;
|
}
|
|
|
/// <summary>
|
/// 获取排列组合列表(笛卡尔乘积)
|
/// </summary>
|
private List<List<AnalysisConclusionViewModel>> CartesianProduct(List<List<AnalysisConclusionViewModel>> lstSplit, double target_flow)
|
{
|
long count = 1;
|
lstSplit.ForEach(item => count *= item.Count);
|
var lstResult = new List<List<AnalysisConclusionViewModel>>();
|
for (long i = 0; i < count; ++i)
|
{
|
var lstTemp = new List<AnalysisConclusionViewModel>();
|
long j = 1;
|
var lstFre = new List<double>();
|
double totalFlow = 0;
|
lstSplit.ForEach(item =>
|
{
|
j *= item.Count;
|
var index = (i / (count / j)) % item.Count;
|
var index_int = (int)index;
|
var obj = item[index_int];
|
totalFlow += obj.Flow;
|
lstTemp.Add(obj);
|
});
|
if (totalFlow < target_flow * _sel_opt_flow_excess)
|
continue;
|
lstResult.Add(lstTemp);
|
}
|
return lstResult;
|
}
|
|
|
/// <summary>
|
/// 获取排列组合
|
/// </summary>
|
/// <param name="flags"></param>
|
/// <param name="count"></param>
|
/// <returns></returns>
|
private List<int[]> GetCombineList(List<int> flags, int count)
|
{
|
var combine = IStation.Curve.PermutationAndCombination<int>.GetCombination(flags.ToArray(), count);
|
return combine;
|
}
|
|
/// <summary>
|
/// 获取组合偏差系数字典
|
/// </summary>
|
/// <param name="flow">总流量</param>
|
/// <param name="flags">组合标志</param>
|
/// <returns></returns>
|
private Dictionary<int, double> GetCombineDeviationFactorDict(double flow, IEnumerable<int> flags)
|
{
|
var deviation_factor_dict = new Dictionary<int, double>();
|
foreach (var flag in flags)
|
{
|
deviation_factor_dict.Add(flag, 0);
|
}
|
|
var analysis_deviation_list = _analysis_deviation_list?.Where(x => x.RunFlags.SequenceEqual(flags)).ToList();
|
if (analysis_deviation_list == null || !analysis_deviation_list.Any())
|
{
|
Yw.LogHelper.Error($"[{Yw.Untity.IntListHelper.ToString(flags)}]组合不存在偏差系数!");
|
return deviation_factor_dict;
|
}
|
|
var a = flow;
|
var flow_dev = flow;
|
Model.AnalysisDeviation analysis_deviation = null;
|
for (int i = 0; i < 6; i++)
|
{
|
flow_dev += i * 50;
|
analysis_deviation = analysis_deviation_list.Where(x => x.MinFlow <= flow_dev && flow_dev <= x.MaxFlow).FirstOrDefault();
|
if (analysis_deviation != null)
|
break;
|
}
|
|
if (analysis_deviation == null)
|
{
|
Yw.LogHelper.Error($"[{Yw.Untity.IntListHelper.ToString(flags)}]组合不存在偏差系数!");
|
return deviation_factor_dict;
|
}
|
foreach (var flag in flags)
|
{
|
var pressure_diff = 0d;
|
if (analysis_deviation.PressureDiff != null && analysis_deviation.PressureDiff.ContainsKey(flag))
|
{
|
pressure_diff = analysis_deviation.PressureDiff[flag];
|
}
|
|
deviation_factor_dict[flag] = pressure_diff;
|
}
|
return deviation_factor_dict;
|
}
|
|
|
#endregion
|
|
#region Expand
|
|
/// <summary>
|
/// 获取变频泵列表 根据工况计算
|
/// </summary>
|
/// <param name="pumps"></param>
|
/// <param name="flag_rpm_dic"></param>
|
/// <param name="flag_inlet_water_level_dict"></param>
|
/// <param name="flag_head_dic"></param>
|
/// <param name="total_flow"></param>
|
/// <param name="ues_deviation_factor"></param>
|
/// <returns></returns>
|
public List<AnaFrePump> GetAnaFrePumpListByWorking(
|
List<Model.Pump> pumps,
|
Dictionary<int, double> flag_rpm_dic,
|
Dictionary<int, double> flag_inlet_water_level_dict,
|
Dictionary<int, double> flag_head_dic,
|
double total_flow,
|
bool ues_deviation_factor = false
|
)
|
{
|
if (pumps == null || !pumps.Any())
|
{
|
return default;
|
}
|
|
if (flag_rpm_dic == null || !flag_rpm_dic.Any())
|
{
|
return default;
|
}
|
|
var run_flag_list = flag_rpm_dic.Where(x => x.Value > 1).Select(x => x.Key).OrderBy(x => x).ToList();
|
var ana_fre_pump_list = new List<AnaFrePump>();
|
foreach (var flag in run_flag_list)
|
{
|
var pump = pumps.Find(x => x.Flag == flag);
|
if (pump == null)
|
continue;
|
var rpm = flag_rpm_dic[flag];
|
if (rpm < 1)
|
continue;
|
|
var curveQH = Curve.PumpCalculateHelper.CalculateSimilarQH(pump.CurveQH, pump.Nr, rpm);
|
var curveQP = Curve.PumpCalculateHelper.CalculateSimilarQP(pump.CurveQP, pump.Nr, rpm);
|
|
double flow = 0, head = 0;
|
if (flag_head_dic != null && flag_head_dic.ContainsKey(pump.Flag))
|
{
|
head = flag_head_dic[pump.Flag];
|
}
|
|
if (flag_inlet_water_level_dict != null && flag_inlet_water_level_dict.ContainsKey(pump.Flag))
|
{
|
head -= flag_inlet_water_level_dict[pump.Flag];
|
}
|
|
if (ues_deviation_factor)
|
{
|
var combine_deviation_factor_dict = GetCombineDeviationFactorDict(total_flow, run_flag_list);//修正组合曲线和模型的偏差扬程
|
if (combine_deviation_factor_dict != null && combine_deviation_factor_dict.ContainsKey(flag))
|
{
|
var combine_deviation_factor = combine_deviation_factor_dict[flag]; //组合偏差系数
|
head -= combine_deviation_factor;
|
}
|
}
|
|
flow = curveQH.GetInterPointLastX(head) ?? 0;
|
if (flow < 0)
|
continue;
|
|
|
var fre_pump = new AnaFrePump();
|
fre_pump.Flag = flag;
|
fre_pump.Flow = flow;
|
fre_pump.Head = head;
|
fre_pump.Power = curveQP.GetFitPointY(flow);
|
fre_pump.PressureDiff = head - Curve.PumpCalculateHelper.CalculateOtherPress(flow, pump.Ic, pump.Oc, null, null);
|
fre_pump.Eff = Curve.PumpCalculateHelper.CalculateE(fre_pump.Flow, fre_pump.Head, fre_pump.Power);
|
fre_pump.Frequency = rpm / pump.Nr * 50;
|
fre_pump.Speed = rpm;
|
|
ana_fre_pump_list.Add(fre_pump);
|
}
|
|
|
return ana_fre_pump_list;
|
}
|
|
/// <summary>
|
/// 获取变频泵列表 根据工况计算
|
/// </summary>
|
/// <param name="pumps"></param>
|
/// <param name="flag_rpm_dic"></param>
|
/// <param name="flag_inlet_water_level_dict"></param>
|
/// <param name="flag_flow_dic"></param>
|
/// <param name="flag_head_dic"></param>
|
/// <param name="flag_curve_head_dic"></param>
|
/// <param name="total_flow"></param>
|
/// <param name="ues_deviation_factor"></param>
|
/// <returns></returns>
|
public List<AnaFrePump> GetAnaFrePumpListByWorking(
|
List<Model.Pump> pumps,
|
Dictionary<int, double> flag_rpm_dic,
|
Dictionary<int, double> flag_inlet_water_level_dict,
|
Dictionary<int, double> flag_flow_dic,
|
Dictionary<int, double> flag_head_dic,
|
double total_flow,
|
out Dictionary<int, double> flag_curve_head_dic,
|
bool ues_deviation_factor = false
|
)
|
{
|
flag_curve_head_dic = new Dictionary<int, double>();
|
if (pumps == null || !pumps.Any())
|
{
|
return default;
|
}
|
|
if (flag_rpm_dic == null || !flag_rpm_dic.Any())
|
{
|
return default;
|
}
|
|
var run_flag_list = flag_rpm_dic.Where(x => x.Value > 1).Select(x => x.Key).OrderBy(x => x).ToList();
|
var ana_fre_pump_list = new List<AnaFrePump>();
|
foreach (var flag in run_flag_list)
|
{
|
var pump = pumps.Find(x => x.Flag == flag);
|
if (pump == null)
|
continue;
|
var rpm = flag_rpm_dic[flag];
|
if (rpm < 1)
|
continue;
|
|
var hz = Math.Round(rpm / pump.Nr * 50, 1);
|
|
|
var CurveQH50 = pump.CurveQH;
|
var CurveQP50 = pump.CurveQP;
|
|
|
var curveQH = Curve.PumpCalculateHelper.CalculateSimilarQH(CurveQH50, pump.Nr, rpm);
|
var curveQP = Curve.PumpCalculateHelper.CalculateSimilarQP(CurveQP50, pump.Nr, rpm);
|
|
double flow = 0, head = 0;
|
if (flag_head_dic != null && flag_head_dic.ContainsKey(pump.Flag))
|
{
|
head = flag_head_dic[pump.Flag];
|
}
|
|
if (flag_inlet_water_level_dict != null && flag_inlet_water_level_dict.ContainsKey(pump.Flag))
|
{
|
head -= flag_inlet_water_level_dict[pump.Flag];
|
}
|
|
if (ues_deviation_factor)
|
{
|
//var combine_deviation_factor_dict = GetCombineDeviationFactorDict(total_flow, run_flag_list);//修正组合曲线和模型的偏差扬程
|
//if (combine_deviation_factor_dict != null && combine_deviation_factor_dict.ContainsKey(flag))
|
//{
|
// var combine_deviation_factor = combine_deviation_factor_dict[flag]; //组合偏差系数
|
// head -= combine_deviation_factor;
|
//}
|
}
|
|
flow = curveQH.GetInterPointLastX(head) ?? 0;
|
if (flow < 0)
|
continue;
|
|
var working_flow = flag_flow_dic[flag];
|
flag_curve_head_dic[flag] = curveQH.GetFitPointY(working_flow);
|
|
var fre_pump = new AnaFrePump();
|
fre_pump.Flag = flag;
|
fre_pump.Flow = flow;
|
fre_pump.Head = head;
|
fre_pump.Power = curveQP.GetFitPointY(flow);
|
fre_pump.PressureDiff = head - Curve.PumpCalculateHelper.CalculateOtherPress(flow, pump.Ic, pump.Oc, null, null);
|
fre_pump.Eff = Curve.PumpCalculateHelper.CalculateE(fre_pump.Flow, fre_pump.Head, fre_pump.Power);
|
fre_pump.Frequency = rpm / pump.Nr * 50;
|
fre_pump.Speed = rpm;
|
|
ana_fre_pump_list.Add(fre_pump);
|
}
|
|
|
return ana_fre_pump_list;
|
}
|
|
|
|
#endregion
|
|
}
|
}
|