namespace IStation.Application { /// /// /// [Route("ChenHang/Dispatch/HydraulicModel")] [ApiDescriptionSettings("Web", Name = "水力模型", Order = 1)] public class HydraulicModel_Controller : IDynamicApiController { private readonly Service.Station _service_station = new(); private readonly Service.Scada _service_scada = new(); private readonly Service.ScheduleConfig _service_schedule_config = new(); private readonly Service.HydraulicModelValidationConfig _service_hydraulic_model_validation_config = new IStation.Service.HydraulicModelValidationConfig(); private static readonly Dictionary _pump_nr_dict = new() { { "Pump11",590}, { "Pump12",590}, { "Pump13",590}, { "Pump14",590}, //{ "Pump15",590}, //{ "Pump16",590}, { "Pump17",590}, { "Pump18",590}, { "Pump21",740}, { "Pump22",495}, { "Pump23",495}, { "Pump24",495}, { "Pump25",495}, { "Pump26",495}, { "Pump27",740} }; private static readonly Dictionary _pump_flag_dict = new() { { 11,"Pump11"}, { 12,"Pump12"}, { 13,"Pump13"}, { 14,"Pump14"}, { 15,"Pump15"}, { 16,"Pump16"}, { 17,"Pump17"}, { 18,"Pump18"}, { 21,"Pump21"}, { 22,"Pump22"}, { 23,"Pump23"}, { 24,"Pump24"}, { 25,"Pump25"}, { 26,"Pump26"}, { 27,"Pump27"} }; private static readonly string _hydraulic_model_file = Path.Combine( Settings.ParasHelper.LocalFile.DataFolderDirectory, Settings.ParasHelper.LocalFile.HydraulicModelFile); /// /// 获取水力模型 /// [Route("Get@V1.0")] [HttpGet] public Dto.Epanet.HydraulicModelDto Get() { if (!File.Exists(_hydraulic_model_file)) { Yw.Dto.YOops.Oh(Yw.Dto.eResultCode.Error, Yw.Dto.InternalErrorCodes.A001, $"水力模型文件缺失!文件路径:{_hydraulic_model_file}"); return null; } IStation.Epanet.NetworkHelper.Open(_hydraulic_model_file, out Epanet.Network.Network network); if (network == null) { Yw.Dto.YOops.Oh(Yw.Dto.eResultCode.Error, Yw.Dto.InternalErrorCodes.A001, $"文件解析失败!文件路径:{_hydraulic_model_file}"); return null; } if (network == null) return default; var reservoirs = network.Reservoirs; var tanks = network.Tanks; var junctions = network.Junctions; var pipes = network.Pipes; var pumps = network.Pumps; var valves = network.Valves; var hydraulic_model_dto = new Dto.Epanet.HydraulicModelDto(); if (reservoirs != null && reservoirs.Any()) { foreach (var item in reservoirs) { var dto = new Dto.Epanet.Reservoir { Id = item.Name, Coordinate = new Dto.Epanet.EnPoint(item.Coordinate.X, item.Coordinate.Y) }; hydraulic_model_dto.Reservoirs.Add(dto); } } if (tanks != null && tanks.Any()) { foreach (var item in tanks) { var dto = new Dto.Epanet.Tank { Id = item.Name, Coordinate = new Dto.Epanet.EnPoint(item.Coordinate.X, item.Coordinate.Y), }; hydraulic_model_dto.Tanks.Add(dto); } } if (junctions != null && junctions.Any()) { foreach (var item in junctions) { var dto = new Dto.Epanet.Junction { Id = item.Name, Coordinate = new Dto.Epanet.EnPoint(item.Coordinate.X, item.Coordinate.Y), }; hydraulic_model_dto.Junctions.Add(dto); } } if (pipes != null && pipes.Any()) { foreach (var item in pipes) { var dto = new Dto.Epanet.Pipe { Id = item.Name, }; if (item.FirstNode != null) { var node = item.FirstNode; dto.FirstNode = new Dto.Epanet.Node() { Id = node.Name, Coordinate = new Dto.Epanet.EnPoint(node.Coordinate.X, node.Coordinate.Y), }; } if (item.SecondNode != null) { var node = item.SecondNode; dto.SecondNode = new Dto.Epanet.Node() { Id = node.Name, Coordinate = new Dto.Epanet.EnPoint(node.Coordinate.X, node.Coordinate.Y), }; } hydraulic_model_dto.Pipes.Add(dto); } } if (pumps != null && pumps.Any()) { foreach (var item in pumps) { var dto = new Dto.Epanet.Pump { Id = item.Name, }; if (item.FirstNode != null) { var node = item.FirstNode; dto.FirstNode = new Dto.Epanet.Node() { Id = node.Name, Coordinate = new Dto.Epanet.EnPoint(node.Coordinate.X, node.Coordinate.Y), }; } if (item.SecondNode != null) { var node = item.SecondNode; dto.SecondNode = new Dto.Epanet.Node() { Id = node.Name, Coordinate = new Dto.Epanet.EnPoint(node.Coordinate.X, node.Coordinate.Y), }; } hydraulic_model_dto.Pumps.Add(dto); } } if (valves != null && valves.Any()) { foreach (var item in valves) { var dto = new Dto.Epanet.Valve { Id = item.Name, }; if (item.FirstNode != null) { var node = item.FirstNode; dto.FirstNode = new Dto.Epanet.Node() { Id = node.Name, Coordinate = new Dto.Epanet.EnPoint(node.Coordinate.X, node.Coordinate.Y), }; } if (item.SecondNode != null) { var node = item.SecondNode; dto.SecondNode = new Dto.Epanet.Node() { Id = node.Name, Coordinate = new Dto.Epanet.EnPoint(node.Coordinate.X, node.Coordinate.Y), }; } hydraulic_model_dto.Valves.Add(dto); } } return hydraulic_model_dto; } /// /// 获取Scada数据 /// [Route("GetScadaList@V1.0")] [HttpGet] public List GetScadaList() { return GetZyScadaList(); } private List GetZyScadaList() { var log_msg = string.Empty; var scada_list = new List(); if (Settings.ParasHelper.ZyDocking.Enable) { var url = Settings.ParasHelper.ZyDocking.ScadaHttpUrl; try { var response_text = Yw.Untity.HttpRequestHelper.Get(url); var scada_output = JsonHelper.Json2Object(response_text); if (scada_output.data != null && scada_output.data.Any()) { foreach (var scada_dict in scada_output.data) { var vals = scada_dict.Value.ElementAt(0).Value; var time = scada_dict.Value.ElementAt(1).Value; var key = scada_dict.Value.ElementAt(2).Value; var scada = new IStation.Dto.Epanet.ZyScada(); scada.Id = key; if (DateTime.TryParse(time, out DateTime t)) scada.Time = t; if (double.TryParse(vals, out double v)) scada.Value = v; scada_list.Add(scada); } } else { log_msg = "scada数据为空"; Yw.Dto.YOops.Oh(Yw.Dto.eResultCode.Error, Yw.Dto.InternalErrorCodes.A001, log_msg); } } catch (System.Exception ex) { log_msg = "http请求异常"; Yw.Dto.YOops.Oh(Yw.Dto.eResultCode.Error, Yw.Dto.InternalErrorCodes.A001, log_msg); } } else { var scada_debug_file = Settings.ParasHelper.LocalFile.DataFolderDirectory + "\\" + "scada_debug.txt"; var scada_debug_json = File.ReadAllText(scada_debug_file); var scada_output = JsonHelper.Json2Object(scada_debug_json); foreach (var scada_dict in scada_output.data) { var vals = scada_dict.Value.ElementAt(0).Value; var time = scada_dict.Value.ElementAt(1).Value; var key = scada_dict.Value.ElementAt(2).Value; var scada = new IStation.Dto.Epanet.ZyScada(); scada.Id = key; if (DateTime.TryParse(time, out DateTime t)) scada.Time = t; if (double.TryParse(vals, out double v)) scada.Value = v; scada_list.Add(scada); } } return scada_list; } /// /// 调度验证 /// [AllowAnonymous] [Route("ScheduleValidation@V1.0")] [HttpPost] //[NonUnify] public Dto.Epanet.HydraulicScheduleDto ScheduleValidation([Required] StationScheduleInput input) { if (!File.Exists(_hydraulic_model_file)) { Yw.Dto.YOops.Oh(Yw.Dto.eResultCode.Error, Yw.Dto.InternalErrorCodes.A001, $"水力模型文件缺失!文件路径:{_hydraulic_model_file}"); return null; } var receipt_time = DateTime.Now; var request_id = Yw.YitIdHelper.NextId(); var log_title = string.Empty; var log_msg = string.Empty; log_title = "初始化基础信息文件"; var station_info = _service_station.Get(); var scada_info = _service_scada.Get(); var schedule_config1 = _service_schedule_config.GetStation1(); var schedule_config2 = _service_schedule_config.GetStation2(); if (station_info == null || scada_info == null) { log_msg = "文件缺失!"; Log.Info(request_id, log_title, log_msg); Yw.Dto.YOops.Oh(Yw.Dto.eResultCode.Error, Yw.Dto.InternalErrorCodes.A001, log_msg); } var hydraulic_model_validation_config = _service_hydraulic_model_validation_config.Get(); if (hydraulic_model_validation_config == null) { log_msg = "水力模型验证文件不存在!"; Log.Info(request_id, log_title, log_msg); Yw.Dto.YOops.Oh(Yw.Dto.eResultCode.Error, Yw.Dto.InternalErrorCodes.A001, log_msg); } var target_flow1 = input.objects["TotalFlow1"]; var target_pressure1 = input.objects["TotalPressure1"]; var target_flow2 = input.objects["TotalFlow2"]; var target_pressure2 = input.objects["TotalPressure2"]; var water_level1 = 0.0; var water_level2 = 0.0; var current_open_pump_flags1 = new List(); var current_open_pump_flags2 = new List(); var scada_list = GetScadaList(); if (!scada_list.Any()) { log_msg = "Scada数据缺失!"; Log.Info(request_id, log_title, log_msg); Yw.Dto.YOops.Oh(Yw.Dto.eResultCode.Error, Yw.Dto.InternalErrorCodes.A001, log_msg); } var water_level_tag_list_1 = scada_info.GetS1WaterLevelTagList(); var water_level_tag_list_2 = scada_info.GetS2WaterLevelTagList(); var water_level_valid_value_list1 = new List(); var water_level_valid_value_list2 = new List(); var run_status_tag_dict_1 = scada_info.GetS1RunStatusTagDict(); var run_status_tag_dict_2 = scada_info.GetS2RunStatusTagDict(); foreach (var scada in scada_list) { if (!scada.Value.HasValue) continue; var tag = scada.Id; var value = scada.Value.Value; if (water_level_tag_list_1.Contains(tag)) { water_level_valid_value_list1.Add(value); continue; } else if (water_level_tag_list_2.Contains(tag)) { water_level_valid_value_list2.Add(value); continue; } if (value != 1) continue; if (run_status_tag_dict_1.ContainsKey(tag)) { current_open_pump_flags1.Add(run_status_tag_dict_1[tag]); continue; } else if (run_status_tag_dict_2.ContainsKey(tag)) { current_open_pump_flags2.Add(run_status_tag_dict_2[tag]); continue; } } if (water_level_valid_value_list1.Any()) water_level1 = water_level_valid_value_list1.Average(x => x); if (water_level_valid_value_list2.Any()) water_level2 = water_level_valid_value_list2.Average(x => x); log_title = "当前水位"; var target_head1 = Curve.PumpCalculateHelper.Mpa2M(target_pressure1) - water_level1; var target_head2 = Curve.PumpCalculateHelper.Mpa2M(target_pressure2) - water_level2; Log.Info(request_id, log_title, $"water_level1:{water_level1},target_head1:{target_head1},water_level2:{water_level2},target_head2:{target_head2}"); var helper = new Algorithm.ScheduleHelper(); helper.Initial(current_open_pump_flags1, schedule_config1); var optimal_combine1 = helper.Calc(station_info.S1, station_info.S1FlagsPart1, station_info.S1FlagsPart2, target_flow1, target_head1); helper.Initial(current_open_pump_flags2, schedule_config2); var optimal_combine2 = helper.Calc(station_info.S2, station_info.S2FlagsPart1, station_info.S2FlagsPart2, target_flow2, target_head2); log_title = "调度返回"; if (optimal_combine1 == null && optimal_combine2 == null) { log_msg = "厂内调度方案无法计算!"; Log.Info(request_id, log_title, log_msg); Yw.Dto.YOops.Oh(Yw.Dto.eResultCode.Error, Yw.Dto.InternalErrorCodes.A001, log_msg); } var pump_schedule_value_list=new List(); foreach (var item in _pump_flag_dict) { var pump_schedule_value = new Dto.Epanet.ScheduleValue(); pump_schedule_value.ModelId = item.Value; pump_schedule_value.Unit = "hz"; pump_schedule_value.ModelValue = 0; pump_schedule_value_list.Add(pump_schedule_value); } if (optimal_combine1 != null) { foreach (var combine in optimal_combine1.Combines) { foreach (var fre_pump in combine.FrePumps) { var flag = fre_pump.Flag; var pump_schedule_value = pump_schedule_value_list.Find(x => x.ModelId == _pump_flag_dict[flag]); if (pump_schedule_value != null) { pump_schedule_value.ModelValue = fre_pump.Frequency / 50; } } } } else { log_msg = $"\r\n1输水调度计算失败,无法满足目标流量:{target_flow1},目标压力:{target_pressure1}!"; Log.Info(request_id, log_title, log_msg); } if (optimal_combine2 != null) { foreach (var combine in optimal_combine2.Combines) { foreach (var fre_pump in combine.FrePumps) { var flag = fre_pump.Flag; var pump_schedule_value = pump_schedule_value_list.Find(x => x.ModelId == _pump_flag_dict[flag]); if (pump_schedule_value != null) { pump_schedule_value.ModelValue = fre_pump.Frequency / 50; } } } } else { log_msg += $"\r\n2输水调度计算失败,无法满足目标流量:{target_flow2},目标压力:{target_pressure2}!"; Log.Info(request_id, log_title, log_msg); } var hydraulic_schedule_dto = new Dto.Epanet.HydraulicScheduleDto(); var flow_id_mapping_dict = hydraulic_model_validation_config.FlowIdMappingDict; var pressure_id_mapping_dict = hydraulic_model_validation_config.PressureIdMappingDict; var pattern_id_mapping_dict = hydraulic_model_validation_config.PatternIdMappingDict; var pressure_id_kPa_list = hydraulic_model_validation_config.PressureIdkPaList; var pattern_list = new List(); var time_value = new IStation.Hydraulic.TimeValue { Time = receipt_time, Value = new Dictionary() }; foreach (var scada in scada_list) { var tag = scada.Id; var value = scada.Value; foreach (var item in flow_id_mapping_dict) { if (item.Value != tag) continue; time_value.Value.Add(tag, value ?? 0); } foreach (var item in pressure_id_mapping_dict) { if (item.Value != tag) continue; var pressure_value = value ?? 0; if (pressure_id_kPa_list.Contains(tag)) { pressure_value /= 1000; } pressure_value = IStation.Curve.PumpCalculateHelper.Mpa2M(pressure_value); time_value.Value.Add(tag, pressure_value); } foreach (var item in pattern_id_mapping_dict) { if (item.Value != tag) continue; var pattern_id = item.Key; var factor = value ?? 0; var pattern = new IStation.Hydraulic.Pattern { Id = pattern_id, FactorList = new List() }; var pump_schedule_value = pump_schedule_value_list.Find(x => x.ModelId == pattern_id); if (pump_schedule_value != null) { double scada_value = -1; if (_pump_nr_dict.ContainsKey(pattern_id)) { scada_value = factor / _pump_nr_dict[pattern_id]; scada_value = scada_value < 0 ? 0 : scada_value; } pump_schedule_value.ScadaId = tag; pump_schedule_value.ScadaValue = scada_value; factor = pump_schedule_value.ModelValue.Value; } pattern.FactorList.Add((float)factor); pattern_list.Add(pattern); } } var hydraulic_model_record_list = IStation.Hydraulic.ModeVerifyHelper.Verify(request_id, _hydraulic_model_file, flow_id_mapping_dict, pressure_id_mapping_dict, pattern_list, time_value); if (hydraulic_model_record_list == null || !hydraulic_model_record_list.Any()) { log_msg = $"模型验证数据为空!"; Log.Info(request_id, log_title, log_msg); } hydraulic_schedule_dto.ScheduleValues.AddRange(pump_schedule_value_list); foreach (var record in hydraulic_model_record_list) { var digits = 4; var unit = "m"; if (record.ValueType == eValueType.Flow) { digits = 1; unit = "m³/h"; } var schedule_value = new Dto.Epanet.ScheduleValue(); schedule_value.ModelId = record.ModelId; schedule_value.ScadaId = record.ScadaId; schedule_value.Unit = unit; if (record.ScadaValue.HasValue) { schedule_value.ScadaValue = Math.Round(record.ScadaValue.Value, digits); } if (record.ModeValue.HasValue) { schedule_value.ModelValue = Math.Round(record.ModeValue.Value, digits); } hydraulic_schedule_dto.ScheduleValues.Add(schedule_value); } return hydraulic_schedule_dto; } } }