using IStation.Epanet;
|
using IStation.Epanet.Enums;
|
using IStation.Model;
|
using IStation.Untity;
|
using System;
|
using System.Collections.Generic;
|
using System.ComponentModel.DataAnnotations;
|
using System.Drawing;
|
using System.IO;
|
using System.Linq;
|
using System.Text;
|
using static IStation.WinFrmUI.AnalysisHelper;
|
|
namespace IStation.WinFrmUI.Monitor
|
{
|
public partial class ModelCorrectionComparePage : DocumentPage
|
{
|
public ModelCorrectionComparePage()
|
{
|
InitializeComponent();
|
PageTitle.Caption = "模型修正对比";
|
|
|
repositoryItemDateEdit1.SetOnlyShowYearMonth();
|
repositoryItemDateEdit2.SetOnlyShowYearMonth();
|
barEditDateStart.EditValue = new DateTime(2024, 9, 1);
|
barEditDateEnd.EditValue = new DateTime(2024, 9, 1);
|
|
|
barCekUseFlow.Checked = true;
|
|
stationListCtrl1.FocusedChangedEvent += StationListCtrl1_FocusedChangedEvent;
|
monitorDataSourcesTreeList1.FocusedChangedEvent += MonitorDataSourcesListCtrl1_FocusedChangedEvent;
|
timeValueSwiftPlotChartView1.SetTimeAxisX(DevExpress.XtraCharts.DateTimeMeasureUnit.Minute);
|
|
}
|
|
|
#region ViewModel
|
|
public class PumpViewModel
|
{
|
|
[Display(Name = "时间")]
|
public string Time { get; set; }
|
|
[Display(Name = "泵")]
|
public int Flag { get; set; }
|
|
[Display(Name = "转速")]
|
public double Rpm { get; set; }
|
|
[Display(Name = "频率")]
|
public double Hz { get; set; }
|
|
[Display(Name = "频率")]
|
public double Hz0 { get; set; }
|
|
[Display(Name = "水位")]
|
public double WaterLevel { get; set; }
|
|
[Display(Name = "进口压力")]
|
public double InletPressure { get; set; }
|
|
[Display(Name = "出口压力")]
|
public double OutletPressure { get; set; }
|
|
[Display(Name = "模型出口压力")]
|
public double ModelOutletPressure { get; set; }
|
|
[Display(Name = "瞬时流量")]
|
public double Flow { get; set; }
|
|
[Display(Name = "模型流量")]
|
public double ModelFlow { get; set; }
|
|
[Display(Name = "流量差值")]
|
public double FlowDiff { get; set; }
|
|
|
[Display(Name = "压差")]
|
public double PressureDiff { get; set; }
|
|
[Display(Name = "曲线压差")]
|
public double CurvePressureDiff { get; set; }
|
|
[Display(Name = "压差差值")]
|
public double PressureDiffDev { get; set; }
|
|
}
|
|
public class StationViewModel
|
{
|
[Display(Name = "时间")]
|
public DateTime Date { get; set; }
|
|
[Display(Name = "时间")]
|
public string Time { get; set; }
|
|
[Display(Name = "名称")]
|
public string Name { get; set; }
|
|
[Display(Name = "监测压力")]
|
public double ScadaPressure { get; set; }
|
|
[Display(Name = "监测流量")]
|
public double ScadaFlow { get; set; }
|
|
[Display(Name = "模型压力")]
|
public double MonitorPressure { get; set; }
|
|
[Display(Name = "模型流量")]
|
public double MonitorFlow { get; set; }
|
|
[Display(Name = "压力偏差")]
|
public double PressureDiff { get; set; }
|
|
[Display(Name = "流量偏差")]
|
public double FlowDiff { get; set; }
|
|
}
|
|
public class ModelCombineViewModel
|
{
|
public string Time { get; set; }
|
public string RunFlags { get; set; }
|
public double TotalFlow { get; set; }
|
public Dictionary<int, double> PressureDiffDevDict { get; set; }
|
}
|
|
public class PumpFactorViewModel
|
{
|
[Display(Name = "泵")]
|
public int Flag { get; set; }
|
|
[Display(Name = "频率")]
|
public double Hz { get; set; }
|
|
[Display(Name = "总体标准差")]
|
public double? STDP { get; set; }
|
|
[Display(Name = "扬程(STDP)")]
|
public double? STDPHead { get; set; }
|
|
|
[Display(Name = "备注")]
|
public string Note { get; set; }
|
|
public void Round()
|
{
|
if (STDP.HasValue)
|
{
|
STDP = Math.Round(STDP.Value, 5);
|
}
|
if (STDPHead.HasValue)
|
{
|
STDPHead = Math.Round(STDPHead.Value, 5);
|
}
|
|
}
|
}
|
|
|
|
#endregion
|
|
private BLL.StationSignalRecordPacket _bll = new BLL.StationSignalRecordPacket();
|
private Model.Station _station = null;
|
private Model.MonitorDataSources _monitorDataSources = null;
|
|
private List<Model.Equipment<Model.Pump>> _pump_list = null;
|
private List<StationViewModel> _model_diff_vm_list = null;
|
private List<PumpViewModel> _pump_vm_list = null;
|
|
private string _model_file = System.IO.Path.Combine
|
(SettingsD.File.RootDirectory, SettingsD.File.DataFolder, "ch2_v3_20240801(Clear).inp");
|
|
/// <summary>
|
/// 清空数据
|
/// </summary>
|
public void Clear()
|
{
|
_pump_vm_list = new List<PumpViewModel>();
|
_model_diff_vm_list = new List<StationViewModel>();
|
timeValueSwiftPlotChartView1.ClearSeries();
|
}
|
|
|
/// <summary>
|
/// 初始化数据
|
/// </summary>
|
public override void InitialDataSource()
|
{
|
stationListCtrl1.SetBindingData();
|
monitorDataSourcesTreeList1.SetBindingData();
|
}
|
|
//泵站变换
|
private void StationListCtrl1_FocusedChangedEvent(Model.Station obj)
|
{
|
_station = obj;
|
WaitFrmHelper.ShowWaitForm();
|
SetBindingData(_monitorDataSources, _station);
|
WaitFrmHelper.HideWaitForm();
|
|
}
|
|
//来源变换
|
private void MonitorDataSourcesListCtrl1_FocusedChangedEvent(Model.MonitorDataSources obj)
|
{
|
_monitorDataSources = obj;
|
WaitFrmHelper.ShowWaitForm();
|
SetBindingData(_monitorDataSources, _station);
|
WaitFrmHelper.HideWaitForm();
|
}
|
|
|
/// <summary>
|
/// 绑定数据
|
/// </summary>
|
public void SetBindingData(Model.MonitorDataSources monitorDataSources, Model.Station station)
|
{
|
|
Clear();
|
if (monitorDataSources == null || station == null)
|
{
|
return;
|
}
|
if (barCekLoad.Checked)
|
{
|
return;
|
}
|
|
|
var station_index = station.SortCode;
|
var dt_start = Convert.ToDateTime(barEditDateStart.EditValue);
|
var dt_end = Convert.ToDateTime(barEditDateEnd.EditValue);
|
var packets = _bll.Get(monitorDataSources.ID, station.ID);
|
packets = packets?.Where(x => (x.Year >= dt_start.Year && x.Year <= dt_end.Year) && (x.Month >= dt_start.Month && x.Month <= dt_end.Month)).ToList();
|
if (packets == null || !packets.Any())
|
return;
|
|
_pump_list = new BLL.Equipment().GetPumpListByBelongTypeAndBelongID(IStation.ObjectType.Station, station.ID);
|
if (_pump_list == null || !_pump_list.Any())
|
{
|
return;
|
}
|
var flag_pump_dict = _pump_list.ToDictionary(x => x.SortCode, x => x.RatedParas);
|
var flag_list = _pump_list.Select(x => x.SortCode).OrderBy(x => x).ToList();
|
var record_list = packets.SelectMany(x => x.StationSignalRecords).ToList();
|
|
var root_folder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "分析");
|
List<AnalysisHelper.AnalysisFactorDto> ana_factor_list = null;
|
var fileName = root_folder + "\\" + "AnalysisFactor.json";
|
if (File.Exists(fileName))
|
{
|
var json = File.ReadAllText(fileName);
|
ana_factor_list = JsonHelper.Json2Object<List<AnalysisHelper.AnalysisFactorDto>>(json);
|
}
|
|
List<AnalysisHelper.AnalysisDeviationDto> ana_deviation_list = null;
|
var fileName_2 = root_folder + "\\" + "AnalysisDeviation.json";
|
if (File.Exists(fileName_2))
|
{
|
var json = File.ReadAllText(fileName_2);
|
ana_deviation_list = JsonHelper.Json2Object<List<AnalysisHelper.AnalysisDeviationDto>>(json);
|
}
|
|
|
var pump_mapping_list = AnalysisHelper.GetPumpModelMappingList();
|
var station_mapping_list = AnalysisHelper.GetStationMappingList();
|
var pump_mapping_dict = pump_mapping_list.ToDictionary(x => x.Flag, x => x);
|
var flag_qh_curve_dict = GetFlagCurveDict();
|
|
|
Set(_model_file, record_list, station_mapping_list, pump_mapping_dict, flag_pump_dict, flag_qh_curve_dict, ana_factor_list, ana_deviation_list);
|
}
|
|
|
#region Color
|
|
private List<Color> ColorArray = new List<Color>()
|
{ Color.Red, Color.Blue, Color.Green, Color.DodgerBlue,
|
Color.Fuchsia, Color.MidnightBlue, Color.Maroon,
|
Color.Aquamarine, Color.Bisque, Color.BurlyWood
|
};
|
|
/// <summary>
|
/// 获取随机颜色
|
/// </summary>
|
/// <returns></returns>
|
private Color GetRandomColor(int count)
|
{
|
if (count < ColorArray.Count)
|
{
|
return ColorArray[count];
|
}
|
|
return ColorHelper.GetRandomColor();
|
}
|
#endregion
|
|
private bool CheckFitPointList(List<CurvePoint> fit_point_list, int nPoints)
|
{
|
var arr = fit_point_list.ToArray();
|
var max_y = fit_point_list[0].Y;
|
for (int j = 1; j < nPoints; j++)
|
{
|
if (arr[j].Y > max_y)
|
{
|
return false;
|
}
|
else
|
{
|
max_y = fit_point_list.Take(j).Max(x => x.Y);
|
}
|
}
|
return true;
|
}
|
|
|
private Dictionary<int, Model.CurveExpress> GetFlagCurveDict()
|
{
|
var dict = new Dictionary<int, Model.CurveExpress>();
|
var bll_curve = new BLL.PumpCurve();
|
var station_list = new BLL.Station().GetAll();
|
foreach (var station in station_list)
|
{
|
var eq_list = new BLL.Equipment().GetPumpListByBelongTypeAndBelongID(IStation.ObjectType.Station, station.ID);
|
if (eq_list == null || !eq_list.Any())
|
{
|
return default;
|
}
|
|
foreach (var eq in eq_list)
|
{
|
Model.CurveExpress qh = null;
|
var curve_info = bll_curve.GetDefaultWorkingByPumpID(eq.ID)?.CurveInfo;
|
if (curve_info != null)
|
{
|
qh = curve_info.CurveQH;
|
}
|
dict.Add(eq.SortCode, qh);
|
}
|
}
|
|
return dict;
|
}
|
|
|
//加载
|
private void barCekLoad_CheckedChanged(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
|
{
|
WaitFrmHelper.ShowWaitForm();
|
SetBindingData(_monitorDataSources, _station);
|
WaitFrmHelper.HideWaitForm();
|
}
|
|
|
// 刷新数据
|
private void barBtnRefresh_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
|
{
|
InitialDataSource();
|
}
|
|
|
|
/// <summary>
|
///模型验证得出分析系数
|
// 用分析系数分析模型组合偏差
|
// 再用分析系数和模型组合偏差分析得出对比
|
/// </summary>
|
public void Set
|
(
|
string model_inp,
|
List<Model.StationSignalRecord> station_record_list,
|
List<StationMapping> station_mapping_list,
|
Dictionary<int, PumpMapping> pump_mapping_dict,
|
Dictionary<int, Model.Pump> flag_pump_dict,
|
Dictionary<int, Model.CurveExpress> flag_qh_curve_dict,
|
List<AnalysisHelper.AnalysisFactorDto> ana_factor_list,
|
List<AnalysisHelper.AnalysisDeviationDto> ana_deviation_list
|
)
|
{
|
if (ana_factor_list == null || !ana_factor_list.Any())
|
{
|
Clear();
|
return;
|
}
|
|
var flag_hz_head_dev_dict = ana_factor_list.GroupBy(x => x.Flag).ToDictionary(x => x.Key, y => y.ToDictionary(k => k.Hz, ky => ky.HeadDeviation ?? 0));
|
var second_tuple = ModelSet(model_inp, station_record_list, station_mapping_list, pump_mapping_dict, flag_pump_dict, flag_qh_curve_dict, flag_hz_head_dev_dict);
|
if (second_tuple == null)
|
{
|
Clear();
|
return;
|
}
|
|
var second_vm_pump_list = second_tuple.Item1;
|
var second_vm_station_list = second_tuple.Item2;
|
|
if (ana_deviation_list == null || !ana_deviation_list.Any())
|
{
|
Clear();
|
return;
|
}
|
|
var third_tuple = ModelSet(model_inp, station_record_list, station_mapping_list, pump_mapping_dict, flag_pump_dict, flag_qh_curve_dict, flag_hz_head_dev_dict, ana_deviation_list);
|
if (third_tuple == null)
|
{
|
Clear();
|
return;
|
}
|
|
var third_vm_pump_list = third_tuple.Item1;
|
var third_vm_station_list = third_tuple.Item2;
|
|
int first_count = 0;
|
int second_count = 0;
|
|
var second_group = second_vm_station_list.GroupBy(x => x.Name);
|
for (int i = 0; i < second_group.Count(); i++)
|
{
|
var color = GetRandomColor(i + first_count);
|
var item = second_group.ElementAt(i);
|
var name = item.Key;
|
var pressure_diff_list = item.Select(x => x.PressureDiff).ToList();
|
|
FilterOutliersHelper.STDEV(pressure_diff_list.ToArray(), out double std_dev, out double stdp);
|
|
var list = item
|
.Where(x => !(Math.Abs(x.PressureDiff) > stdp * 3))
|
.Select(x => new TimeValue(x.Date, x.PressureDiff))
|
.ToList();
|
|
var er_list = item
|
.Where(x => Math.Abs(x.PressureDiff) > stdp * 3)
|
.Select(x => new TimeValue(x.Date, x.PressureDiff))
|
.ToList();
|
|
timeValueSwiftPlotChartView1.AddSwiftPlotSeries(name, color, name + "(修正)", "压力", list);
|
}
|
second_count = second_group.Count();
|
|
var third_group = third_vm_station_list.GroupBy(x => x.Name);
|
for (int i = 0; i < third_group.Count(); i++)
|
{
|
var color = GetRandomColor(i + first_count + second_count);
|
var item = third_group.ElementAt(i);
|
var name = item.Key;
|
var pressure_diff_list = item.Select(x => x.PressureDiff).ToList();
|
|
FilterOutliersHelper.STDEV(pressure_diff_list.ToArray(), out double std_dev, out double stdp);
|
|
var list = item
|
.Where(x => !(Math.Abs(x.PressureDiff) > stdp * 3))
|
.Select(x => new TimeValue(x.Date, x.PressureDiff))
|
.ToList();
|
|
var er_list = item
|
.Where(x => Math.Abs(x.PressureDiff) > stdp * 4)
|
.Select(x => new TimeValue(x.Date, x.PressureDiff))
|
.ToList();
|
|
timeValueSwiftPlotChartView1.AddSwiftPlotSeries(name, color, name + "(二次修正)", "压力", list);
|
|
}
|
|
}
|
|
|
private Tuple<List<PumpViewModel>, List<StationViewModel>> ModelSet
|
(
|
string model_inp,
|
List<Model.StationSignalRecord> station_record_list,
|
List<StationMapping> station_mapping_list,
|
Dictionary<int, PumpMapping> pump_mapping_dict,
|
Dictionary<int, Model.Pump> flag_pump_dict,
|
Dictionary<int, Model.CurveExpress> flag_qh_curve_dict,
|
Dictionary<int, Dictionary<double, double>> flag_hz_head_dev_dict = null,
|
List<AnalysisDeviationDto> ana_dev_list = null,
|
int fit_point_count = 100
|
)
|
{
|
var model_id_builder = new StringBuilder(31);
|
var err = EpanetMethods.ENopen(model_inp, "", "");
|
if ((int)err > 6)
|
{
|
throw new Exception($"ENopen:{err}");
|
}
|
|
err = EpanetMethods.ENopenH();
|
if ((int)err > 6)
|
{
|
throw new Exception($"ENopenH:{err}");
|
}
|
|
foreach (var item in pump_mapping_dict)
|
{
|
var flag = item.Key;
|
var mapping = item.Value;
|
|
if (EpanetMethods.ENgetlinkindex(mapping.PumpId, out int pump_index) != ErrorCode.Ok)
|
throw new Exception($"ENgetlinkindex:{err}");
|
|
if (!string.IsNullOrEmpty(mapping.FlowId))
|
{
|
if (EpanetMethods.ENgetlinkindex(mapping.FlowId, out int flow_index) != ErrorCode.Ok)
|
throw new Exception($"ENgetlinkindex:{err}");
|
mapping.FlowIndex = flow_index;
|
}
|
|
if (EpanetMethods.ENgetnodeindex(mapping.PressureId, out int pressure_index) != ErrorCode.Ok)
|
throw new Exception($"ENgetnodeindex:{err}");
|
|
if (EpanetMethods.ENgetcurveindex(mapping.CurveId, out int curve_index) != ErrorCode.Ok)
|
throw new Exception($"ENgetcurveindex:{err}");
|
|
mapping.PumpIndex = pump_index;
|
mapping.PressureIndex = pressure_index;
|
mapping.CurveIndex = curve_index;
|
|
|
var qh = flag_qh_curve_dict[flag];
|
var fit_point_list = qh.GetFitPoints(fit_point_count);
|
var flow_list = fit_point_list.Select(x => (float)x.X).ToArray();
|
var head_list = fit_point_list.Select(x => (float)x.Y).ToArray();
|
|
var cek = CheckFitPointList(fit_point_list, fit_point_count);
|
if (!cek)
|
{
|
throw new Exception($"CheckFitPointList: false");
|
}
|
err = EpanetMethods.ENsetcurve(mapping.CurveIndex, flow_list, head_list, fit_point_count);
|
if (err != 0)
|
{
|
throw new Exception($"ENsetcurve:{err}");
|
}
|
}
|
|
foreach (var mapping in station_mapping_list)
|
{
|
if (EpanetMethods.ENgetlinkindex(mapping.FlowId, out int flow_index) != ErrorCode.Ok)
|
throw new Exception($"ENgetlinkindex:{err}");
|
|
if (EpanetMethods.ENgetnodeindex(mapping.PressureId, out int pressure_index) != ErrorCode.Ok)
|
throw new Exception($"ENgetnodeindex:{err}");
|
|
mapping.PressureIndex = pressure_index;
|
mapping.FlowIndex = flow_index;
|
}
|
|
var pattern_id_list = AnalysisHelper.GetPatternIdList();
|
var pattern_id_dict = new Dictionary<string, int>();
|
foreach (var id in pattern_id_list)
|
{
|
if (EpanetMethods.ENgetpatternindex(id, out int index) != ErrorCode.Ok)
|
continue;
|
pattern_id_dict.Add(id, index);
|
}
|
|
var vm_pump_list = new List<PumpViewModel>();
|
var vm_station_list = new List<StationViewModel>();
|
foreach (var station_record in station_record_list)
|
{
|
var time = station_record.Time.ToString("G");
|
var model_record_dict = station_record.ModelRecordDict;
|
var pump_record_list = station_record.PumpSignalRecords;
|
if (pump_record_list.Exists(x => x.Flag != 15 && x.Flag != 16 && x.Rpm < 1))
|
{
|
continue;
|
}
|
|
if (pump_record_list.Exists(x => x.OutletPressure > 50))
|
{
|
continue;
|
}
|
|
|
|
//设置模式
|
foreach (var pattern in pattern_id_dict)
|
{
|
var pattern_id = pattern.Key;
|
var pattern_index = pattern.Value;
|
var pattern_value = 0f;
|
if (model_record_dict.ContainsKey(pattern_id))
|
{
|
pattern_value = (float)model_record_dict[pattern_id];
|
}
|
err = EpanetMethods.ENsetpattern(pattern_index, new float[] { pattern_value }, 1);
|
if ((int)err > 6)
|
{
|
throw new Exception($"ENsetpattern:{err}");
|
}
|
}
|
|
//是否使用修正系数更新曲线
|
if (flag_hz_head_dev_dict != null && flag_hz_head_dev_dict.Any())
|
{
|
AnalysisDeviationDto ana_dev = null;
|
if (ana_dev_list != null && ana_dev_list.Any())
|
{
|
var run_flags = pump_record_list.Select(x => x.Flag).OrderBy(x => x).ToList();
|
ana_dev = ana_dev_list.Find(x => x.RunFlags.SequenceEqual(run_flags));
|
}
|
foreach (var pump_record in pump_record_list)
|
{
|
var flag = pump_record.Flag;
|
var pump = flag_pump_dict[flag];
|
var mapping = pump_mapping_dict[flag];
|
var rpm_ratio = pump_record.Rpm / pump.Nr;
|
if (!pump.IsBp)
|
rpm_ratio = 1;
|
if (rpm_ratio <= 0.1)
|
continue;
|
|
var hz0 = Math.Round(rpm_ratio * 50, 0);
|
if (hz0 > 50)
|
hz0 = 50;
|
|
if (!flag_hz_head_dev_dict.ContainsKey(flag))
|
throw new Exception($"!flag_hz_head_dev.ContainsKey(flag):{flag}");
|
if (!flag_hz_head_dev_dict[flag].ContainsKey(hz0))
|
throw new Exception($"!flag_hz_head_dev[flag].ContainsKey(hz0):{flag} {hz0}");
|
|
var qh = flag_qh_curve_dict[flag];
|
var fit_pt_list = qh.GetFitPoints(fit_point_count);
|
|
var head_dev = (float)flag_hz_head_dev_dict[flag][hz0];
|
if (head_dev != 0)
|
{
|
var head_dev_v = head_dev;
|
if (ana_dev != null)
|
{
|
head_dev_v -= (float)ana_dev.PressureDiff[flag];
|
}
|
var pt_list = qh.DefinePoints.Select(x => new Model.CurvePoint(x.X, x.Y + head_dev_v)).ToList();
|
|
var qh_ct = Model.FitCurveHelper.BuildCurveExpress(pt_list, Model.eCurveFitType.CubicCurve);
|
fit_pt_list = qh_ct.GetFitPoints(fit_point_count);
|
}
|
|
var x_array = fit_pt_list.Select(x => (float)x.X).ToArray();
|
var y_array = fit_pt_list.Select(x => (float)x.Y).ToArray();
|
|
err = EpanetMethods.ENsetcurve(mapping.CurveIndex, x_array, y_array, fit_point_count);
|
if ((int)err > 6)
|
{
|
throw new Exception($"ENsetcurve:{err}");
|
}
|
}
|
}
|
|
err = EpanetMethods.ENinitH(0);
|
if ((int)err > 6)
|
{
|
throw new Exception($"ENinitH:{err}");
|
}
|
|
err = EpanetMethods.ENrunH(out _);
|
if ((int)err > 6)
|
{
|
throw new Exception($"ENrunH:{err}");
|
}
|
|
foreach (var pump_record in pump_record_list)
|
{
|
var flag = pump_record.Flag;
|
var pump = flag_pump_dict[flag];
|
var qh = flag_qh_curve_dict[flag];
|
var mapping = pump_mapping_dict[flag];
|
var rpm = pump_record.Rpm;
|
if (!pump.IsBp)
|
rpm = pump.Nr;
|
if (rpm == 0)
|
break;
|
|
var hz = Math.Round(rpm / pump.Nr * 50, 2);
|
if (hz > 50)
|
hz = 50;
|
var hz0 = Math.Round(hz, 0);
|
var wl = pump_record.WaterLevel;
|
var inlet_pressure = Model.CurveCalcuHelper.Mpa2M(pump_record.InletPressure);
|
var outlet_pressure = Model.CurveCalcuHelper.Mpa2M(pump_record.OutletPressure);
|
var pressure_diff = outlet_pressure - inlet_pressure;
|
var flow = pump_record.FlowRate;
|
var curve_head = pump_record.Head;
|
|
err = EpanetMethods.ENgetlinkvalue(mapping.PumpIndex, LinkValue.Flow, out float model_flow);
|
if ((int)err > 6)
|
throw new Exception($"ENgetnodevalue:{err}");
|
if (Math.Abs(model_flow) < 1)
|
break;
|
|
err = EpanetMethods.ENgetnodevalue(mapping.PressureIndex, NodeValue.Pressure, out float model_outlet_pressure);
|
if ((int)err > 6)
|
throw new Exception($"ENgetnodevalue:{err}");
|
if (Math.Abs(model_outlet_pressure) > 45)
|
break;
|
|
model_flow = Math.Abs(model_flow);
|
model_outlet_pressure = Math.Abs(model_outlet_pressure);
|
var model_pressure_diff = model_outlet_pressure - inlet_pressure;
|
var flow_diff = flow - model_flow;
|
|
var vm = new PumpViewModel();
|
vm.Time = time;
|
vm.Rpm = rpm;
|
vm.Flag = flag;
|
vm.Hz = hz;
|
vm.Hz0 = hz0;
|
vm.WaterLevel = wl;
|
vm.InletPressure = Math.Round(inlet_pressure, 2);
|
vm.OutletPressure = Math.Round(outlet_pressure, 2);
|
vm.PressureDiff = Math.Round(pressure_diff, 2);
|
|
vm.Flow = Math.Round(flow, 1);
|
vm.ModelFlow = Math.Round(model_flow, 1);
|
vm.ModelOutletPressure = Math.Round(model_outlet_pressure, 2);
|
vm.CurvePressureDiff = Math.Round(model_pressure_diff, 2);
|
vm.PressureDiffDev = Math.Round(model_pressure_diff - pressure_diff, 3);
|
vm.FlowDiff = Math.Round(flow_diff, 1);
|
vm_pump_list.Add(vm);
|
|
}
|
|
foreach (var mapping in station_mapping_list)
|
{
|
if (!model_record_dict.ContainsKey(mapping.ScadaPressureId))
|
continue;
|
if (!model_record_dict.ContainsKey(mapping.ScadaFlowId))
|
continue;
|
|
var flow = model_record_dict[mapping.ScadaFlowId];
|
var outlet_pressure = model_record_dict[mapping.ScadaPressureId];
|
|
err = EpanetMethods.ENgetlinkvalue(mapping.FlowIndex, LinkValue.Flow, out float model_flow);
|
if ((int)err > 6)
|
throw new Exception($"ENgetnodevalue:{err}");
|
|
err = EpanetMethods.ENgetnodevalue(mapping.PressureIndex, NodeValue.Pressure, out float model_outlet_pressure);
|
if ((int)err > 6)
|
throw new Exception($"ENgetnodevalue:{err}");
|
|
var flow_diff = flow - model_flow;
|
var pressure_diff = outlet_pressure - model_outlet_pressure;
|
|
var vm = new StationViewModel();
|
vm.Date = station_record.Time;
|
vm.Time = time;
|
vm.Name = mapping.Name;
|
vm.ScadaFlow = Math.Round(flow, 1);
|
vm.ScadaPressure = Math.Round(outlet_pressure, 3);
|
vm.MonitorFlow = Math.Round(model_flow, 1);
|
vm.MonitorPressure = Math.Round(model_outlet_pressure, 3);
|
vm.FlowDiff = Math.Round(flow_diff, 1);
|
vm.PressureDiff = Math.Round(pressure_diff, 3);
|
vm_station_list.Add(vm);
|
}
|
}
|
|
err = EpanetMethods.ENcloseH();
|
if ((int)err > 6)
|
throw new Exception($"ENcloseH:{err}");
|
err = EpanetMethods.ENclose();
|
if ((int)err > 6)
|
throw new Exception($"ENclose:{err}");
|
|
return new Tuple<List<PumpViewModel>, List<StationViewModel>>(vm_pump_list, vm_station_list);
|
|
}
|
|
|
public List<AnalysisHelper.AnalysisFactorDto> AnalysisFactorSet
|
(
|
Dictionary<int, Model.Pump> flag_pump_dict,
|
List<Tuple<int, double, double, double>> flag_hz_pressure_diff_list,
|
bool use_flow = false
|
)
|
{
|
if (flag_pump_dict == null || !flag_pump_dict.Any())
|
return default;
|
if (flag_hz_pressure_diff_list == null || !flag_hz_pressure_diff_list.Any())
|
return default;
|
|
var opt_std_dev_pop = 0.3;
|
var range_hz = 5;
|
|
//分析范围内的系数
|
var flag_range_hz_pressure_diff_dict = new Dictionary<int, Dictionary<double, Tuple<double, double, int>>>();
|
var group_by_flag = flag_hz_pressure_diff_list.GroupBy(x => x.Item1);
|
foreach (var item in group_by_flag)
|
{
|
var flag = item.Key;
|
var pump = flag_pump_dict[flag];
|
if (!pump.IsBp)
|
continue;
|
|
for (double i = 20; i <= 50; i += range_hz)
|
{
|
var min_hz = i - range_hz;
|
var max_hz = i;
|
|
var list = item.Where(x => x.Item2 >= min_hz && x.Item2 <= max_hz).ToList();
|
if (list == null || list.Count() < 10)
|
continue;
|
|
var pressure_diff_list = list.Select(x => x.Item3).ToList();
|
var pressure_diff_filter_tuple = AnalysisHelper.GetFilterBySTDP(pressure_diff_list.ToArray(), opt_std_dev_pop, 0, 2);
|
var pressure_diff_filter_array = pressure_diff_filter_tuple.Item1;
|
var pressure_diff_std_dev_pop = pressure_diff_filter_tuple.Item2;
|
var pressure_diff_std_dev_pop_head_avg = pressure_diff_filter_array.Average();
|
|
|
|
var std_dev_pop = pressure_diff_std_dev_pop;
|
var diff_avg = pressure_diff_std_dev_pop_head_avg;
|
var count = pressure_diff_filter_array.Count();
|
|
if (use_flow)
|
{
|
var flow_list = list.Select(x => x.Item4).ToList();
|
var flow_filter_tuple = AnalysisHelper.GetFilterBySTDP(flow_list.ToArray(), 50, 0, 2);
|
var flow_filter_array = flow_filter_tuple.Item1;
|
var flow_std_dev_pop = flow_filter_tuple.Item2;
|
var flow_std_dev_pop_head_avg = flow_filter_array.Average();
|
|
var diff_V = Model.CurveCalcuHelper.CalculateOtherPress(flow_std_dev_pop_head_avg, pump.Ic, pump.Oc, null, null);
|
var head_diff_avg = -(pressure_diff_std_dev_pop_head_avg + diff_V);
|
|
diff_avg = head_diff_avg;
|
}
|
|
if (!flag_range_hz_pressure_diff_dict.ContainsKey(flag))
|
flag_range_hz_pressure_diff_dict.Add(flag, new Dictionary<double, Tuple<double, double, int>>());
|
|
flag_range_hz_pressure_diff_dict[flag].Add(max_hz, new Tuple<double, double, int>(std_dev_pop, diff_avg, count));
|
|
}
|
}
|
|
if (!flag_range_hz_pressure_diff_dict.Any())
|
{
|
return default;
|
}
|
|
//分析1hz范围内的系数
|
var exist_data_dto_list = new List<AnalysisHelper.AnalysisFactorDto>();
|
var group_by_flag_hz = flag_hz_pressure_diff_list.GroupBy(x => new { x.Item1, x.Item2 });
|
foreach (var item in group_by_flag_hz)
|
{
|
var hz = item.Key.Item2;
|
if (hz < 20)
|
continue;
|
var list = item.ToList();
|
if (list.Count() < 5)
|
continue;
|
|
|
var flag = item.Key.Item1;
|
var pump = flag_pump_dict[flag];
|
var pressure_diff_list = list.Select(x => x.Item3).ToList();
|
var pressure_diff_filter_tuple = AnalysisHelper.GetFilterBySTDP(pressure_diff_list.ToArray(), opt_std_dev_pop);
|
var pressure_diff_filter_array = pressure_diff_filter_tuple.Item1;
|
var pressure_diff_std_dev_pop = pressure_diff_filter_tuple.Item2;
|
var pressure_diff_std_dev_pop_head_avg = pressure_diff_filter_array.Average();
|
|
if (Math.Abs(pressure_diff_std_dev_pop) > 1)
|
continue;
|
if (Math.Abs(pressure_diff_std_dev_pop) > 0.5 && list.Count() < 10)
|
continue;
|
if (Math.Abs(pressure_diff_std_dev_pop_head_avg) > 5)
|
continue;
|
|
|
var std_dev_pop = pressure_diff_std_dev_pop;
|
var diff_avg = pressure_diff_std_dev_pop_head_avg;
|
var count = pressure_diff_filter_array.Count();
|
|
|
if (use_flow)
|
{
|
var flow_list = list.Select(x => x.Item4).ToList();
|
var flow_filter_tuple = AnalysisHelper.GetFilterBySTDP(flow_list.ToArray(), 50, 0, 2);
|
var flow_filter_array = flow_filter_tuple.Item1;
|
var flow_std_dev_pop = flow_filter_tuple.Item2;
|
var flow_std_dev_pop_head_avg = flow_filter_array.Average();
|
|
var diff_V = Model.CurveCalcuHelper.CalculateOtherPress(flow_std_dev_pop_head_avg, pump.Ic, pump.Oc, null, null);
|
var head_diff_avg = -(pressure_diff_std_dev_pop_head_avg + diff_V);
|
|
diff_avg = head_diff_avg;
|
}
|
|
var dto = new AnalysisHelper.AnalysisFactorDto();
|
dto.Flag = flag;
|
dto.Hz = hz;
|
dto.HeadSTDP = std_dev_pop;
|
dto.HeadDeviation = diff_avg;
|
dto.Accuracy = 0;
|
dto.Count = count;
|
exist_data_dto_list.Add(dto);
|
|
}
|
|
exist_data_dto_list = exist_data_dto_list.OrderBy(x => x.Flag).ThenBy(x => x.Hz).ToList();
|
|
//相似换算修正系数(不存在监测数据的频率)
|
var similar_dto_list = new List<AnalysisHelper.AnalysisFactorDto>();
|
foreach (var item_pump in flag_pump_dict)
|
{
|
var flag = item_pump.Key;
|
var pump = item_pump.Value;
|
if (!pump.IsBp)
|
continue;
|
if (!flag_range_hz_pressure_diff_dict.ContainsKey(flag))
|
continue;
|
var item_hz = flag_range_hz_pressure_diff_dict[flag];
|
for (int hz = 1; hz <= 50; hz++)
|
{
|
if (exist_data_dto_list.Exists(x => x.Flag == flag && x.Hz == hz))
|
continue;
|
|
var hz0 = (hz / range_hz + 1) * range_hz;
|
if (hz0 > 50)
|
hz0 = 50;
|
if (item_hz.ContainsKey(hz0))
|
{
|
var tuple = item_hz[hz0];
|
var analysis_facotr = new AnalysisHelper.AnalysisFactorDto();
|
analysis_facotr.Flag = flag;
|
analysis_facotr.Hz = hz;
|
analysis_facotr.HeadSTDP = tuple.Item1;
|
analysis_facotr.HeadDeviation = tuple.Item2;
|
analysis_facotr.Accuracy = 0;
|
similar_dto_list.Add(analysis_facotr);
|
}
|
else
|
{
|
var hz_list = item_hz.Select(x => x.Key).ToList();
|
var similar_hz = hz_list.Where(x => x >= hz0)?.OrderBy(x => x).FirstOrDefault();
|
if (similar_hz == null || similar_hz.Value == 0)
|
similar_hz = hz_list.OrderByDescending(x => x).FirstOrDefault();
|
if (similar_hz == null)
|
throw new Exception("similar_hz error");
|
|
var tuple = item_hz[similar_hz.Value];
|
var similar_ratio = hz / similar_hz.Value;
|
var head_dev = tuple.Item2 * similar_ratio;
|
var head_stdp = tuple.Item1 * similar_ratio;
|
|
var analysis_facotr = new AnalysisHelper.AnalysisFactorDto();
|
analysis_facotr.Flag = flag;
|
analysis_facotr.Hz = hz;
|
analysis_facotr.HeadSTDP = head_stdp;
|
analysis_facotr.HeadDeviation = head_dev;
|
analysis_facotr.Accuracy = -1;
|
similar_dto_list.Add(analysis_facotr);
|
}
|
}
|
}
|
|
var all_analysis_factor_list = new List<AnalysisHelper.AnalysisFactorDto>();
|
all_analysis_factor_list.AddRange(exist_data_dto_list);
|
all_analysis_factor_list.AddRange(similar_dto_list);
|
all_analysis_factor_list = all_analysis_factor_list.OrderBy(x => x.Flag).ThenBy(x => x.Hz).ToList();
|
|
return all_analysis_factor_list;
|
}
|
|
|
public List<AnalysisDeviationDto> AnalysisDeviationSet
|
(
|
Dictionary<int, Model.Pump> flag_pump_dict,
|
List<Tuple<string, double, Dictionary<int, double>>> run_flags_flow_pressure_diff_dev_dict,
|
double minQ = 0,
|
double maxQ = 100000,
|
double spaceQ = 1000
|
)
|
{
|
if (flag_pump_dict == null || !flag_pump_dict.Any())
|
return default;
|
if (run_flags_flow_pressure_diff_dev_dict == null || !run_flags_flow_pressure_diff_dev_dict.Any())
|
return default;
|
|
var list = new List<AnalysisDeviationDto>();
|
var is_error_value = false;
|
for (double current_minQ = minQ; current_minQ <= maxQ; current_minQ += spaceQ)
|
{
|
var current_maxQ = current_minQ + spaceQ;
|
var combine_list = run_flags_flow_pressure_diff_dev_dict.Where(x => x.Item2 >= current_minQ && x.Item2 <= current_maxQ).ToList();
|
if (combine_list == null || !combine_list.Any())
|
continue;
|
var group_by_run_flags = combine_list.GroupBy(x => x.Item1);
|
foreach (var item_run_flags in group_by_run_flags)
|
{
|
if (item_run_flags.Count() < 5)
|
continue;
|
var flags = item_run_flags.Key;
|
|
var dev_dict = new Dictionary<int, double>();
|
var flag_dev_list = item_run_flags.SelectMany(x => x.Item3.Select(d => new Tuple<int, double>(d.Key, d.Value))).ToList();
|
var group_by_flag = flag_dev_list.GroupBy(x => x.Item1);
|
foreach (var flag_item in group_by_flag)
|
{
|
var flag = flag_item.Key;
|
var dev_array = flag_item.Select(x => x.Item2).ToArray();
|
var filter_std_dev_pop_tuple = AnalysisHelper.GetFilterBySTDP(dev_array);
|
var filter_std_dev_pop_array = filter_std_dev_pop_tuple.Item1;
|
var std_dev_pop = filter_std_dev_pop_tuple.Item2;
|
var std_dev_pop_pressure_diff_dev_avg = filter_std_dev_pop_array.Average();
|
|
var dev_avg = std_dev_pop_pressure_diff_dev_avg;
|
dev_avg = Math.Round(dev_avg, 5);
|
dev_dict.Add(flag, dev_avg);
|
}
|
|
is_error_value = false;
|
foreach (var dev in dev_dict)
|
{
|
if (Math.Abs(dev.Value) > 3)
|
{
|
is_error_value = true;
|
break;
|
}
|
}
|
if (is_error_value)
|
continue;
|
|
var vm = new AnalysisDeviationDto();
|
vm.RunFlags = IStation.Untity.IntListHelper.ToList(flags);
|
vm.MinFlow = current_minQ;
|
vm.MaxFlow = current_maxQ;
|
vm.Count = item_run_flags.Count();
|
vm.PressureDiff = dev_dict;
|
list.Add(vm);
|
}
|
}
|
|
return list;
|
|
}
|
|
|
}
|
}
|