using DevExpress.XtraCharts;
|
using System.Diagnostics;
|
using System.IO;
|
using Yw.WinFrmUI;
|
|
namespace PBS.WinFrmUI.Hydro
|
{
|
public partial class SystemCurvePage : DocumentPage
|
{
|
public SystemCurvePage()
|
{
|
InitializeComponent();
|
}
|
|
|
public override void InitialDataSource()
|
{
|
var xyD= this.chartControl1.Diagram as SwiftPlotDiagram;
|
xyD.EnableAxisXZooming = true;
|
xyD.EnableAxisYZooming = true;
|
xyD.EnableAxisXScrolling = true;
|
xyD.EnableAxisYScrolling = true;
|
|
}
|
|
private void barBtnCalc_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
|
{
|
//// 创建一个 Stopwatch 实例
|
//Stopwatch stopwatch = new Stopwatch();
|
|
//// 开始计时
|
//stopwatch.Start();
|
//var file_path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "1897563622226399232.inp");
|
//var helper = new ParallelEpanetSimulator(file_path, 0, 5, 20000);
|
//var list = helper.RunParallelSimulations();
|
|
//Console.WriteLine("所有模拟已完成。");
|
|
//// 停止计时
|
//stopwatch.Stop();
|
|
//Console.WriteLine($"总时间:{stopwatch.Elapsed.TotalSeconds}");
|
//Console.ReadLine();
|
Calc();
|
}
|
|
private void Calc()
|
{
|
Stopwatch stopwatch = new Stopwatch();
|
|
var file_path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "1897563622226399232.inp");
|
|
var pressure = 0d;
|
var minDemand = 0; // 最小总需水量(m³/h)
|
var maxDemand = 45; // 最大总需水量(m³/h)
|
var calcCount = 20000; // 计算次数
|
var rand = new Random();
|
|
var list = new List<SimulationResult>(calcCount);
|
using (var helper = new Yw.Epanet.InteropXHelper())
|
{
|
var err = helper.Open(file_path, "", "");
|
err = helper.GetCount(Yw.Epanet.eCountType.Node, out int nodeCount);
|
err = helper.OpenH();
|
|
var config = new Config
|
{
|
NodeCount = nodeCount,
|
TotalRuns = calcCount,
|
MinDemand = minDemand,
|
MaxDemand = maxDemand,
|
NodeLimits = new()
|
};
|
|
for (int nodeIndex = 1; nodeIndex <= nodeCount; nodeIndex++)
|
{
|
config.NodeLimits.Add(new(0, rand.NextDouble() * 10));
|
}
|
|
|
var generator = new DemandAllocator(config);
|
var allDemands = generator.GenerateAllocationMatrix();
|
|
|
for (int i = 0; i < calcCount; i++)
|
{
|
helper.InitH(false);
|
var demands = allDemands[i];
|
for (int nodeIdx = 1; nodeIdx <= nodeCount; nodeIdx++)
|
{
|
double demand = demands.NodeDemands[nodeIdx - 1];
|
err = helper.SetNodeValue(nodeIdx, Yw.Epanet.eNodeProperty.BaseDemand, demand);
|
}
|
|
helper.RunH(out long t);
|
|
var result = new SimulationResult();
|
result.TotalDemand = demands.TotalDemand;
|
for (int nodeIdx = 1; nodeIdx <= nodeCount; nodeIdx++)
|
{
|
pressure = 0;
|
helper.GetNodeValue(nodeIdx, Yw.Epanet.eNodeProperty.Pressure, out pressure);
|
result.UpdatePressure(nodeIdx, pressure);
|
}
|
helper.NextH(out long tstep);
|
list.Add(result);
|
}
|
|
|
helper.Close();
|
|
}
|
|
|
stopwatch.Stop();
|
|
|
list = list.OrderBy(x => x.TotalDemand).ToList();
|
|
|
|
this.chartControl1.BeginInit();
|
this.chartControl1.Series[0].Points.Clear();
|
|
foreach (var item in list)
|
{
|
var pressureList = item.PressuresDict.Values.ToList();
|
var x = item.TotalDemand;
|
var y=pressureList.Min();
|
this.chartControl1.Series[0].Points.Add(new DevExpress.XtraCharts.SeriesPoint(x,y));
|
}
|
|
this.chartControl1.EndInit();
|
}
|
|
|
public class SimulationResult
|
{
|
public double TotalDemand { get; set; }
|
public Dictionary<int, double> PressuresDict { get; set; } = new();
|
|
public void UpdatePressure(int nodeId, double pressure)
|
{
|
PressuresDict.Add(nodeId, pressure);
|
}
|
}
|
|
public class Config
|
{
|
public int NodeCount { get; set; } // 节点总数
|
public int TotalRuns { get; set; } // 计算次数
|
public double MinDemand { get; set; } // 最小总需水量(m³/h)
|
public double MaxDemand { get; set; } // 最大总需水量(m³/h)
|
public List<(double min, double max)> NodeLimits { get; set; } = new(); // 节点水量限制
|
}
|
|
public class AllocationResult
|
{
|
public double TotalDemand { get; set; }
|
public double[] NodeDemands { get; }
|
public DateTime Timestamp { get; }
|
|
public AllocationResult(int nodeCount)
|
{
|
NodeDemands = new double[nodeCount];
|
Timestamp = DateTime.Now;
|
}
|
}
|
|
public class DemandAllocator
|
{
|
private readonly Config _config;
|
private readonly Random _rand = new();
|
|
public DemandAllocator(Config config)
|
{
|
ValidateConfig(config);
|
_config = config;
|
}
|
|
public List<AllocationResult> GenerateAllocationMatrix()
|
{
|
var results = new List<AllocationResult>(_config.TotalRuns);
|
double step = (_config.MaxDemand - _config.MinDemand) / (_config.TotalRuns - 1);
|
|
// 根据GB50015规范考虑未预见水量[6](@ref)
|
for (int i = 0; i < _config.TotalRuns; i++)
|
{
|
double currentDemand = _config.MinDemand + step * i;
|
results.Add(GenerateAllocation(currentDemand));
|
}
|
return results;
|
}
|
|
private AllocationResult GenerateAllocation(double totalDemand)
|
{
|
var result = new AllocationResult(_config.NodeCount);
|
double remaining = totalDemand;
|
|
// 第一阶段:分配最低需水量(符合设计秒流量规范[7](@ref))
|
for (int i = 0; i < _config.NodeCount; i++)
|
{
|
result.NodeDemands[i] = _config.NodeLimits[i].min;
|
remaining -= result.NodeDemands[i];
|
}
|
|
// 第二阶段:遗传算法式加权分配(参考专利[5](@ref))
|
double[] weights = GenerateGeneticWeights();
|
double weightSum = Sum(weights);
|
|
for (int i = 0; i < _config.NodeCount && remaining > 0; i++)
|
{
|
double allocatable = Math.Min(
|
remaining * (weights[i] / weightSum),
|
_config.NodeLimits[i].max - result.NodeDemands[i]
|
);
|
|
result.NodeDemands[i] += allocatable;
|
remaining -= allocatable;
|
}
|
|
// 第三阶段:误差修正(确保总和精确)
|
if (remaining > 0)
|
{
|
int index = _rand.Next(_config.NodeCount);
|
result.NodeDemands[index] = Math.Min(
|
result.NodeDemands[index] + remaining,
|
_config.NodeLimits[index].max
|
);
|
}
|
|
result.TotalDemand = Sum(result.NodeDemands);
|
return result;
|
}
|
|
// 遗传算法权重生成(20%基础权重+随机变异[3](@ref))
|
private double[] GenerateGeneticWeights()
|
{
|
double[] weights = new double[_config.NodeCount];
|
for (int i = 0; i < weights.Length; i++)
|
{
|
weights[i] = _rand.NextDouble() * 0.8 + 0.2;
|
}
|
return weights;
|
}
|
|
private static double Sum(double[] arr)
|
{
|
double sum = 0;
|
foreach (var v in arr) sum += v;
|
return sum;
|
}
|
|
private void ValidateConfig(Config config)
|
{
|
double totalMin = 0;
|
foreach (var limit in config.NodeLimits)
|
{
|
totalMin += limit.min;
|
if (limit.min < 0 || limit.max < limit.min)
|
throw new ArgumentException("节点限制值无效");
|
}
|
if (totalMin > config.MaxDemand)
|
throw new ArgumentException("总最小需求超过最大设定值");
|
}
|
}
|
|
|
}
|
|
|
|
}
|