From 2596928b751bb5edc6ff0537c3950d0cabaf2018 Mon Sep 17 00:00:00 2001
From: ningshuxia <ningshuxia0927@outlook.com>
Date: 星期三, 12 三月 2025 11:14:22 +0800
Subject: [PATCH] Test

---
 WinFrmUI/PBS.WinFrmUI.Hydro/Properties/Resources.Designer.cs                           |   63 +
 WinFrmUI/PBS.WinFrmUI.Hydro/01-water-supply-system-curve/SystemCurvePage.cs            |  273 +++++++
 Console/PBS.Console.Test/Program - 复制(2).cs                                            |  140 +++
 Console/PBS.Console.Test/SystemCurveCalcHelper.cs                                      |  268 +++++++
 WinFrmUI/PBS.WinFrmUI.Hydro/Properties/Resources.resx                                  |  120 +++
 Console/PBS.Console.Test/Program.cs                                                    |  113 +++
 WinFrmUI/PBS.WinFrmUI.Hydro/01-water-supply-system-curve/SystemCurvePage.resx          |  144 ++++
 Console/PBS.Console.Test/Helper.cs                                                     |  134 +++
 Desktop/PBS.Desktop/MainForm.cs                                                        |   20 
 Desktop/PBS.Desktop/PBS.Desktop.csproj                                                 |    2 
 HStation.PBS.sln                                                                       |  211 -----
 WinFrmUI/PBS.WinFrmUI.Hydro/PBS.WinFrmUI.Hydro.csproj.user                             |    9 
 Console/PBS.Console.Test/Program - 复制.cs                                               |  102 ++
 WinFrmUI/PBS.WinFrmUI.Hydro/01-water-supply-system-curve/SystemCurveCalcHelper.cs      |  172 ++++
 Desktop/PBS.Desktop/DbFirstHelper.cs                                                   |    2 
 WinFrmUI/PBS.WinFrmUI.Hydro/01-water-supply-system-curve/SystemCurveCalcHelper - 复制.cs |  209 +++++
 WinFrmUI/PBS.WinFrmUI.Hydro/PBS.WinFrmUI.Hydro.csproj                                  |   19 
 WinFrmUI/PBS.WinFrmUI.Hydro/01-water-supply-system-curve/SystemCurvePage.Designer.cs   |  139 +++
 Console/PBS.Console.Test/PBS.Console.Test.csproj                                       |   19 
 19 files changed, 1,960 insertions(+), 199 deletions(-)

diff --git a/Console/PBS.Console.Test/Helper.cs b/Console/PBS.Console.Test/Helper.cs
new file mode 100644
index 0000000..127419f
--- /dev/null
+++ b/Console/PBS.Console.Test/Helper.cs
@@ -0,0 +1,134 @@
+锘縰sing System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using Yw.Epanet;
+
+namespace PBS.Console.Test
+{
+    public class Helper
+    {
+        private readonly int _numNodes;
+        private readonly double[] _baseDemandValues;
+        private readonly double[][] _precomputedDemands;
+
+        #region 鏍稿績绠楁硶瀹炵幇
+        private double[][] PrecomputeDemands(int totalRuns)
+        {
+            var rand = new Random();
+            var demandPool = new double[totalRuns][];
+
+            for (int i = 0; i < totalRuns; i++)
+            {
+                demandPool[i] = new double[_numNodes];
+                for (int n = 0; n < _numNodes; n++)
+                {
+                    // 閬椾紶绠楁硶寮忛�夋嫨
+                    int idx = rand.Next(_baseDemandValues.Length);
+
+                    // 20%姒傜巼鍙樺紓
+                    if (rand.NextDouble() < 0.2)
+                        idx = (idx + 1) % _baseDemandValues.Length;
+
+                    demandPool[i][n] = _baseDemandValues[idx];
+                }
+            }
+            return demandPool;
+        }
+
+        private double[][] PrecomputeDemands1(int totalRuns)
+        {
+            var rand = new Random();
+            var demandPool = new double[totalRuns][];
+
+            for (int i = 0; i < totalRuns; i++)
+            {
+                demandPool[i] = new double[_numNodes];
+                for (int n = 0; n < _numNodes; n++)
+                {
+                    // 閬椾紶绠楁硶寮忛�夋嫨
+                    int idx = rand.Next(_baseDemandValues.Length);
+
+                    // 20%姒傜巼鍙樺紓
+                    if (rand.NextDouble() < 0.2)
+                        idx = (idx + 1) % _baseDemandValues.Length;
+
+                    demandPool[i][n] = _baseDemandValues[idx];
+                }
+            }
+            return demandPool;
+        }
+
+
+
+
+        private double[,] GenerateAllDemands(int nodeCount, int totalIterations, double[] weValues)
+        {
+        
+            double[,] demands = new double[totalIterations, nodeCount];
+            Parallel.For(0, totalIterations, iter =>
+            {
+                var rand = new Random();
+                for (int node = 0; node < nodeCount; node++)
+                { 
+                    // 閬椾紶绠楁硶寮忛�夋嫨
+                    int idx = rand.Next(weValues.Length);
+
+                    // 20%姒傜巼鍙樺紓
+                    if (rand.NextDouble() < 0.2)
+                        idx = (idx + 1) % weValues.Length;
+                    demands[iter, node] = weValues[idx];
+                }
+            });
+            return demands;
+        }
+
+        #endregion
+
+
+
+
+
+        #region 杈呭姪绫诲畾涔�
+        public class SimulationResult
+        {
+            public int RunId { get; set; }
+            public DateTime TimeStamp { get; set; }
+            public double[] Pressures { get; }
+            public double[] Flows { get; }
+
+            public SimulationResult(int nodeCount)
+            {
+                Pressures = new double[nodeCount];
+                Flows = new double[nodeCount];
+            }
+        }
+
+        public class SensitivityResult
+        {
+            public double[] FirstOrderIndices { get; }
+            public double[] TotalOrderIndices { get; }
+
+            public SensitivityResult(int parameterCount)
+            {
+                FirstOrderIndices = new double[parameterCount];
+                TotalOrderIndices = new double[parameterCount];
+            }
+        }
+
+        private class SobolSequence
+        {
+            // Sobol搴忓垪鐢熸垚瀹炵幇锛堥渶鏍规嵁鍏蜂綋鏁板搴撳疄鐜帮級
+            public double[][] Generate(int samples) => throw new NotImplementedException();
+        }
+
+        private SensitivityResult CalculateSobolIndices(double[][] inputs, List<double[]> outputs)
+        {
+            // Sobol鎸囨暟璁$畻瀹炵幇
+            throw new NotImplementedException();
+        }
+        #endregion
+    }
+}
diff --git a/Console/PBS.Console.Test/PBS.Console.Test.csproj b/Console/PBS.Console.Test/PBS.Console.Test.csproj
new file mode 100644
index 0000000..e220909
--- /dev/null
+++ b/Console/PBS.Console.Test/PBS.Console.Test.csproj
@@ -0,0 +1,19 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net6.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <Compile Remove="Program - 澶嶅埗%282%29.cs" />
+    <Compile Remove="Program - 澶嶅埗.cs" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Yw.Epanet.Calcu.Core" Version="1.0.0" />
+  </ItemGroup>
+
+</Project>
diff --git "a/Console/PBS.Console.Test/Program - \345\244\215\345\210\266\0502\051.cs" "b/Console/PBS.Console.Test/Program - \345\244\215\345\210\266\0502\051.cs"
new file mode 100644
index 0000000..26b692e
--- /dev/null
+++ "b/Console/PBS.Console.Test/Program - \345\244\215\345\210\266\0502\051.cs"
@@ -0,0 +1,140 @@
+锘�// 鍒涘缓涓�涓� Stopwatch 瀹炰緥 
+using System.Collections.Concurrent;
+using System.Diagnostics;
+using System.Text;
+
+
+Console.WriteLine("寮�濮嬫ā鎷�...");
+Stopwatch stopwatch = new Stopwatch();
+stopwatch.Start();
+
+var file_path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "1897563622226399232.inp");
+
+var pressure = 0d;
+var minDemand = 50.0;   // 鏈�灏忔�婚渶姘撮噺(m鲁/h)
+var maxDemand = 500.0;  // 鏈�澶ф�婚渶姘撮噺(m鲁/h)
+var calcCount = 20000;           // 璁$畻娆℃暟
+
+
+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 allDemands = GenerateDemandMatrix(minDemand, maxDemand, nodeCount, calcCount);
+    for (int i = 0; i < calcCount; i++)
+    {
+        helper.InitH(false);
+        var demands = allDemands[i];
+        for (int nodeIdx = 1; nodeIdx <= nodeCount; nodeIdx++)
+        {
+            double demand = demands[nodeIdx - 1];
+            err = helper.SetNodeValue(nodeIdx, Yw.Epanet.eNodeProperty.BaseDemand, demand);
+        }
+
+        helper.RunH(out long t);
+
+        var result = new SimulationResult();
+        for (int nodeIdx = 1; nodeIdx <= nodeCount; nodeIdx++)
+        {
+            pressure = 0;
+            helper.GetNodeValue(nodeIdx, Yw.Epanet.eNodeProperty.Pressure, out pressure);
+            result.UpdateMaxPressure(nodeIdx, pressure);
+        }
+        helper.NextH(out long tstep);
+        list.Add(result);
+    }
+
+
+    helper.Close();
+
+}
+
+
+
+stopwatch.Stop();
+
+Console.WriteLine("鎵�鏈夋ā鎷熷凡瀹屾垚銆�");
+Console.WriteLine($"鎬绘椂闂�:{stopwatch.Elapsed.TotalSeconds}");
+
+var strBuild = new StringBuilder();
+foreach (var item in list)
+{
+    var pressureList = item.MaxPressures.Values.ToList();
+    strBuild.AppendLine($"{pressureList.Min()},{pressureList.Max()}");
+}
+
+Console.WriteLine(strBuild.ToString());
+Console.ReadLine();
+Console.ReadKey();
+
+
+
+/// <summary>
+/// 鐢熸垚闇�姘撮噺鐭╅樀锛堝熀浜庨仐浼犵畻娉曠殑闅忔満鍒嗛厤绛栫暐[2](@ref)锛�
+/// </summary>
+double[][] GenerateDemandMatrix(double minDemand, double maxDemand, int nodeCount, int totalSteps)
+{
+    var demandMatrix = new double[totalSteps][];
+    double stepSize = (maxDemand - minDemand) / (totalSteps - 1);
+    var rand = new Random();
+    for (int step = 0; step < totalSteps; step++)
+    {
+        double totalDemand = minDemand + step * stepSize;
+        demandMatrix[step] = GenerateRandomDemands(rand, nodeCount, totalDemand);
+    }
+    return demandMatrix;
+}
+
+/// <summary>
+/// 闅忔満鍒嗛厤鎬婚渶姘撮噺鍒板悇鑺傜偣锛堢鍚堟渚嬩腑鐨勭敤姘撮噺鍒嗛厤閫昏緫[1](@ref)锛�
+/// </summary>
+double[] GenerateRandomDemands(Random rand, int nodeCount, double totalDemand)
+{
+    double[] demands = new double[nodeCount];
+    double remaining = totalDemand;
+
+    // 鍔犳潈闅忔満鍒嗛厤绠楁硶
+    for (int i = 0; i < nodeCount - 1; i++)
+    {
+        double maxPossible = remaining / (nodeCount - i);
+        demands[i] = rand.NextDouble() * maxPossible;
+        remaining -= demands[i];
+    }
+    demands[nodeCount - 1] = remaining;  // 纭繚鎬诲拰鍑嗙‘ 
+    return demands;
+}
+
+double[,] GenerateAllDemands(int nodeCount, int totalIterations, double[] weValues)
+{
+
+    double[,] demands = new double[totalIterations, nodeCount];
+    Parallel.For(0, totalIterations, iter =>
+    {
+        var rand = new Random();
+        for (int node = 0; node < nodeCount; node++)
+        {
+            // 閬椾紶绠楁硶寮忛�夋嫨
+            int idx = rand.Next(weValues.Length);
+
+            // 20%姒傜巼鍙樺紓
+            if (rand.NextDouble() < 0.2)
+                idx = (idx + 1) % weValues.Length;
+            demands[iter, node] = weValues[idx];
+        }
+    });
+    return demands;
+}
+
+public class SimulationResult
+{
+    public ConcurrentDictionary<int, double> MaxPressures { get; } = new();
+
+    public void UpdateMaxPressure(int nodeId, double pressure)
+    {
+        MaxPressures.AddOrUpdate(nodeId, pressure,
+            (id, old) => Math.Max(old, pressure));
+    }
+}
\ No newline at end of file
diff --git "a/Console/PBS.Console.Test/Program - \345\244\215\345\210\266.cs" "b/Console/PBS.Console.Test/Program - \345\244\215\345\210\266.cs"
new file mode 100644
index 0000000..d1af543
--- /dev/null
+++ "b/Console/PBS.Console.Test/Program - \345\244\215\345\210\266.cs"
@@ -0,0 +1,102 @@
+锘�// 鍒涘缓涓�涓� Stopwatch 瀹炰緥 
+using System.Collections.Concurrent;
+using System.Diagnostics;
+using System.Text;
+
+
+Console.WriteLine("寮�濮嬫ā鎷�...");
+Stopwatch stopwatch = new Stopwatch();
+stopwatch.Start(); 
+
+var file_path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "1897563622226399232.inp");
+ 
+var  pressure = 0d;
+var weVlaues = new double[] { 0, 2.5, 5, 7.5, 10 };
+var calcCount = 20000;
+var list=new List<SimulationResult>(20000); 
+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 allDemands = GenerateAllDemands(nodeCount, calcCount, weVlaues);
+    for (int i = 0; i < calcCount; i++)
+    {
+        helper.InitH(false);
+        for (int nodeIdx = 1; nodeIdx <= nodeCount; nodeIdx++)
+        {
+            double demand = allDemands[i, nodeIdx - 1];
+            err = helper.SetNodeValue(nodeIdx, Yw.Epanet.eNodeProperty.BaseDemand, demand);
+        }
+
+        helper.RunH(out long t);
+
+        var result = new SimulationResult();
+        for (int nodeIdx = 1; nodeIdx <= nodeCount; nodeIdx++)
+        {
+            pressure = 0;
+            helper.GetNodeValue(nodeIdx, Yw.Epanet.eNodeProperty.Pressure, out pressure);
+            result.UpdateMaxPressure(nodeIdx, pressure);
+        }
+        helper.NextH(out long tstep);
+        list.Add(result);
+    }
+     
+
+    helper.Close();
+
+}
+ 
+
+
+stopwatch.Stop();
+
+Console.WriteLine("鎵�鏈夋ā鎷熷凡瀹屾垚銆�");
+Console.WriteLine($"鎬绘椂闂�:{stopwatch.Elapsed.TotalSeconds}");
+
+var strBuild = new StringBuilder();
+foreach (var item in list)
+{
+    var pressureList= item.MaxPressures.Values.ToList();
+    strBuild.AppendLine($"{pressureList.Min():N5},{pressureList.Max():N5}");
+}
+
+Console.WriteLine(strBuild.ToString());
+Console.ReadLine();
+Console.ReadKey();
+
+
+
+
+  double[,] GenerateAllDemands(int nodeCount, int totalIterations, double[] weValues)
+{
+
+    double[,] demands = new double[totalIterations, nodeCount];
+    Parallel.For(0, totalIterations, iter =>
+    {
+        var rand = new Random();
+        for (int node = 0; node < nodeCount; node++)
+        {
+            // 閬椾紶绠楁硶寮忛�夋嫨
+            int idx = rand.Next(weValues.Length);
+
+            // 20%姒傜巼鍙樺紓
+            if (rand.NextDouble() < 0.2)
+                idx = (idx + 1) % weValues.Length;
+            demands[iter, node] = weValues[idx];
+        }
+    });
+    return demands;
+}
+
+public class SimulationResult
+{
+    public ConcurrentDictionary<int, double> MaxPressures { get; } = new();
+
+    public void UpdateMaxPressure(int nodeId, double pressure)
+    {
+        MaxPressures.AddOrUpdate(nodeId, pressure,
+            (id, old) => Math.Max(old, pressure));
+    }
+}
\ No newline at end of file
diff --git a/Console/PBS.Console.Test/Program.cs b/Console/PBS.Console.Test/Program.cs
new file mode 100644
index 0000000..480c7b8
--- /dev/null
+++ b/Console/PBS.Console.Test/Program.cs
@@ -0,0 +1,113 @@
+锘�// 鍒涘缓涓�涓� Stopwatch 瀹炰緥 
+using System.Collections.Concurrent;
+using System.Diagnostics;
+using System.Text;
+using static PBS.Console.Test.WaterDistributionSystemHelper;
+
+
+
+Console.WriteLine("寮�濮嬫ā鎷�...");
+Stopwatch stopwatch = new Stopwatch();
+stopwatch.Start();
+
+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();
+
+
+
+    //var allDemands = GenerateDemandMatrix(minDemand, maxDemand, nodeCount, calcCount);
+    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.UpdateMaxPressure(nodeIdx, pressure);
+        }
+        helper.NextH(out long tstep);
+        list.Add(result);
+    }
+
+
+    helper.Close();
+
+}
+ 
+
+stopwatch.Stop();
+
+Console.WriteLine("鎵�鏈夋ā鎷熷凡瀹屾垚銆�");
+Console.WriteLine($"鎬绘椂闂�:{stopwatch.Elapsed.TotalSeconds}");
+
+list = list.OrderBy(x => x.TotalDemand).ToList();
+var strBuild = new StringBuilder();
+foreach (var item in list)
+{
+    //var pressureList = item.PressuresDict.Values.ToList();
+    //var a = item.PressuresDict.OrderBy(x => x.Value).ToList();
+    //strBuild.AppendLine($"{item.TotalDemand},{a[0].Value},{a[0].Key}");
+    strBuild.AppendLine($"1:{item.TotalDemand},{item.PressuresDict[1]}");
+}
+
+
+Console.WriteLine(strBuild.ToString());
+Console.ReadLine();
+Console.ReadKey();
+
+
+ 
+public class SimulationResult
+{
+    public double TotalDemand { get; set; }
+    public Dictionary<int, double> PressuresDict { get; set; } = new();
+    //public ConcurrentDictionary<int, double> MaxPressures { get; } = new();
+
+    public void UpdateMaxPressure(int nodeId, double pressure)
+    {
+        PressuresDict.Add(nodeId, pressure);
+        //MaxPressures.AddOrUpdate(nodeId, pressure,
+        //    (id, old) => Math.Max(old, pressure));
+    }
+}
\ No newline at end of file
diff --git a/Console/PBS.Console.Test/SystemCurveCalcHelper.cs b/Console/PBS.Console.Test/SystemCurveCalcHelper.cs
new file mode 100644
index 0000000..ebbea7a
--- /dev/null
+++ b/Console/PBS.Console.Test/SystemCurveCalcHelper.cs
@@ -0,0 +1,268 @@
+锘縰sing System.Collections.Concurrent;
+using System.Runtime.InteropServices;
+
+
+namespace PBS.Console.Test
+{
+    using System;
+    using System.Collections.Generic;
+
+    public class WaterDistributionSystem1
+    {
+        #region 鏍稿績绠楁硶绫�
+        public class ModelConfig
+        {
+            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 SimulationResult
+        {
+            public double TotalDemand { get; set; }
+            public double[] NodeDemands { get; }
+            public DateTime Timestamp { get; }
+
+            public SimulationResult(int nodeCount)
+            {
+                NodeDemands = new double[nodeCount];
+                Timestamp = DateTime.Now;
+            }
+        }
+
+        public class DemandGenerator
+        {
+            private readonly ModelConfig _config;
+            private readonly Random _rand = new();
+
+            public DemandGenerator(ModelConfig config) => _config = config;
+
+            // 鐢熸垚闇�姹傜煩闃碉紙绗﹀悎瑙勮寖[6](@ref)鐨勭嚎鎬ч�掑绛栫暐锛�
+            public List<SimulationResult> GenerateDemandMatrix()
+            {
+                var results = new List<SimulationResult>(_config.TotalRuns);
+                double step = (_config.MaxDemand - _config.MinDemand) / (_config.TotalRuns - 1);
+
+                for (int i = 0; i < _config.TotalRuns; i++)
+                {
+                    double currentDemand = _config.MinDemand + step * i;
+                    results.Add(GenerateDemandSet(currentDemand));
+                }
+                return results;
+            }
+
+            // 鍗曚釜闇�姹傞泦鐢熸垚绠楁硶锛堝寘鍚妭鐐圭害鏉焄4](@ref)锛�
+            private SimulationResult GenerateDemandSet(double totalDemand)
+            {
+                var result = new SimulationResult(_config.NodeCount);
+                double remaining = totalDemand;
+
+                // 绗竴闃舵锛氬垎閰嶆渶灏忛渶姹�
+                for (int i = 0; i < _config.NodeCount; i++)
+                {
+                    result.NodeDemands[i] = _config.NodeLimits[i].min;
+                    remaining -= result.NodeDemands[i];
+                }
+
+                // 绗簩闃舵锛氬姞鏉冮殢鏈哄垎閰嶅墿浣欐按閲忥紙閬椾紶绠楁硶浼樺寲鎬濊矾[1](@ref)锛�
+                double[] weights = GenerateWeights();
+                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;
+                }
+
+                // 绗笁闃舵锛氳宸慨姝o紙纭繚鎬诲拰绮剧‘锛�
+                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;
+            }
+
+            // 鐢熸垚閬椾紶绠楁硶鏉冮噸锛堝弬鑰僛1,3](@ref)锛�
+            private double[] GenerateWeights()
+            {
+                double[] weights = new double[_config.NodeCount];
+                for (int i = 0; i < weights.Length; i++)
+                {
+                    weights[i] = _rand.NextDouble() * 0.8 + 0.2; // 20%鍩虹鏉冮噸+闅忔満鍙樺紓
+                }
+                return weights;
+            }
+
+            private static double Sum(double[] arr)
+            {
+                double sum = 0;
+                foreach (var v in arr) sum += v;
+                return sum;
+            }
+        }
+        #endregion
+
+        //#region 浣跨敤绀轰緥
+        //public static void Main()
+        //{
+        //    var config = new ModelConfig
+        //    {
+        //        NodeCount = 5,
+        //        TotalRuns = 10,
+        //        MinDemand = 50,
+        //        MaxDemand = 500,
+        //        NodeLimits = new List<(double, double)> {
+        //        (0, 100), (10, 150), (5, 80), (20, 200), (0, 120)
+        //    }
+        //    };
+
+        //    var generator = new DemandGenerator(config);
+        //    var results = generator.GenerateDemandMatrix();
+
+        //    // 杈撳嚭楠岃瘉
+        //    foreach (var r in results)
+        //    {
+        //        Console.WriteLine($"Total: {r.TotalDemand:F2} | Nodes: {string.Join(", ", r.NodeDemands)}");
+        //    }
+        //}
+        //#endregion
+    }
+
+
+    public class WaterDistributionSystemHelper
+    {
+        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;
+                }
+
+                // 绗笁闃舵锛氳宸慨姝o紙纭繚鎬诲拰绮剧‘锛�
+                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("鎬绘渶灏忛渶姹傝秴杩囨渶澶ц瀹氬��");
+            }
+        }
+
+    }
+}
diff --git a/Desktop/PBS.Desktop/DbFirstHelper.cs b/Desktop/PBS.Desktop/DbFirstHelper.cs
index 4b50f54..0621086 100644
--- a/Desktop/PBS.Desktop/DbFirstHelper.cs
+++ b/Desktop/PBS.Desktop/DbFirstHelper.cs
@@ -11,7 +11,7 @@
         public static async void Initial()
         {
             //await new Yw.BLL.DivisionDbFirstHelper().Initial();
-            await new Yw.BLL.HydroDbFirstHelper().Initial();
+            //await new Yw.BLL.HydroDbFirstHelper().Initial();
             await new Yw.BLL.DictDbFirstHelper().Initial();
             await new Yw.BLL.PhartDbFirstHelper().Initial();
             await new Yw.BLL.UnitDbFirstHelper().Initial();
diff --git a/Desktop/PBS.Desktop/MainForm.cs b/Desktop/PBS.Desktop/MainForm.cs
index b924f85..701e677 100644
--- a/Desktop/PBS.Desktop/MainForm.cs
+++ b/Desktop/PBS.Desktop/MainForm.cs
@@ -13,6 +13,7 @@
 using HStation.WinFrmUI.Dict;
 using NPOI.SS.Formula.Functions;
 using PBS.WinFrmUI;
+using PBS.WinFrmUI.Hydro;
 using PBS.WinFrmUI.WE;
 using System.IO;
 using Yw.WinFrmUI;
@@ -1382,12 +1383,12 @@
                 {
                     if (!IsExistPage(guid, true))
                     {
-                        var page = new HydroSceneMgrPage();
-                        page.PageGuid = guid;
-                        page.PageTitle.Caption = caption;
-                        page.PageTitle.HeaderSvgImage = svg;
-                        page.PageTitle.SvgImageSize = size;
-                        CreatePage(page, guid);
+                        //var page = new HydroSceneMgrPage();
+                        //page.PageGuid = guid;
+                        //page.PageTitle.Caption = caption;
+                        //page.PageTitle.HeaderSvgImage = svg;
+                        //page.PageTitle.SvgImageSize = size;
+                        //CreatePage(page, guid);
                         
                     }
                 });
@@ -1442,7 +1443,12 @@
                 {
                     if (!IsExistPage(guid, true))
                     {
-                        
+                        var page = new SystemCurvePage();
+                        page.PageGuid = guid;
+                        page.PageTitle.Caption = caption;
+                        page.PageTitle.HeaderSvgImage = svg;
+                        page.PageTitle.SvgImageSize = size;
+                        CreatePage(page, guid);
                     }
                 });
                 var forecastWater = Get("水量预测", new PageGuid()
diff --git a/Desktop/PBS.Desktop/PBS.Desktop.csproj b/Desktop/PBS.Desktop/PBS.Desktop.csproj
index 745ee9f..9232792 100644
--- a/Desktop/PBS.Desktop/PBS.Desktop.csproj
+++ b/Desktop/PBS.Desktop/PBS.Desktop.csproj
@@ -31,10 +31,10 @@
 
   <ItemGroup>
     <ProjectReference Include="..\..\WinFrmUI\HStation.WinFrmUI.Assets.Core\HStation.WinFrmUI.Assets.Core.csproj" />
+    <ProjectReference Include="..\..\WinFrmUI\PBS.WinFrmUI.Hydro\PBS.WinFrmUI.Hydro.csproj" />
     <ProjectReference Include="..\..\WinFrmUI\PBS.WinFrmUI.WE\PBS.WinFrmUI.WE.csproj" />
     <ProjectReference Include="..\..\WinFrmUI\PBS.WinFrmUI\PBS.WinFrmUI.csproj" />
     <ProjectReference Include="..\..\WinFrmUI\YW.WinFrmUI.Division.Core\Yw.WinFrmUI.Division.Core.csproj" />
-    <ProjectReference Include="..\..\WinFrmUI\Yw.WinFrmUI.Hydro.Core\Yw.WinFrmUI.Hydro.Core.csproj" />
   </ItemGroup>
 
   <ItemGroup>
diff --git a/HStation.PBS.sln b/HStation.PBS.sln
index 1896f5d..c370a22 100644
--- a/HStation.PBS.sln
+++ b/HStation.PBS.sln
@@ -45,8 +45,6 @@
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yw.BIMFace.SDK.Core", "Component\Yw.BIMFace.SDK.Core\Yw.BIMFace.SDK.Core.csproj", "{D6D805ED-C848-4403-97AB-E86715B9E2DB}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yw.WinFrmUI.Hydro.Q3d.Core", "WinFrmUI\Yw.WinFrmUI.Hydro.Q3d.Core\Yw.WinFrmUI.Hydro.Q3d.Core.csproj", "{454B8C89-EFF0-42E2-B569-C211F0168F5D}"
-EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HStation.WinFrmUI.Assets.Core", "WinFrmUI\HStation.WinFrmUI.Assets.Core\HStation.WinFrmUI.Assets.Core.csproj", "{2AC76D6E-7035-4FD0-84EA-E00BA7D9876B}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HStation.BLL.Assets.Core", "BLL\HStation.BLL.Assets.Core\HStation.BLL.Assets.Core.csproj", "{EC0D8314-B4AB-4FA6-A490-C34E5773C8AA}"
@@ -56,14 +54,6 @@
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HStation.Service.Assets.Core", "Service\HStation.Service.Assets.Core\HStation.Service.Assets.Core.csproj", "{0AFD5926-BBB4-4DC9-92B3-5FCD15C84A42}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HStation.WinFrmUI.Hydro.Core", "WinFrmUI\HStation.WinFrmUI.Hydro.Core\HStation.WinFrmUI.Hydro.Core.csproj", "{42261EEA-8BA7-4096-92B1-E809BDD72A82}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yw.WinFrmUI.Hydro.Core", "WinFrmUI\Yw.WinFrmUI.Hydro.Core\Yw.WinFrmUI.Hydro.Core.csproj", "{BBC8C860-98B1-45B1-B41D-518DCB402C17}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yw.Hydro.Core", "Hydro\Yw.Hydro.Core\Yw.Hydro.Core.csproj", "{F6068234-6BFC-48B1-9FAB-2892C097C430}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yw.EPAnet.Core", "Hydro\Yw.EPAnet.Core\Yw.EPAnet.Core.csproj", "{D6F58BEC-660B-4EFF-9A8F-D70571F6EFB8}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yw.EPAnet.Calcu.Core", "Hydro\Yw.EPAnet.Calcu.Core\Yw.EPAnet.Calcu.Core.csproj", "{6D1548F3-2C29-4B96-A3F5-A9D3BDD65454}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yw.WinFrmUI.Phart.Core", "WinFrmUI\Yw.WinFrmUI.Phart.Core\Yw.WinFrmUI.Phart.Core.csproj", "{1A862895-9461-4E89-A695-F2150E1D34C8}"
 EndProject
@@ -81,19 +71,13 @@
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HStation.Vmo.Assets.Core", "Vmo\HStation.Vmo.Assets.Core\HStation.Vmo.Assets.Core.csproj", "{3F682666-7578-47E7-8E1D-020AB5B75678}"
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Yw.Hydraulic.Core", "Hydro\Yw.Hydraulic.Core\Yw.Hydraulic.Core.vcxproj", "{0A0F9D7E-87C9-4276-823D-495355A01E8C}"
-EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HStation.WinFrmUI.PhartRelation.Core", "WinFrmUI\HStation.WinFrmUI.PhartRelation.Core\HStation.WinFrmUI.PhartRelation.Core.csproj", "{DBC6DC37-8BA8-4CFC-A98C-E6D34EE2E5D7}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yw.WinFrmUI.Hydro.L2d.Core", "WinFrmUI\Yw.WinFrmUI.Hydro.L2d.Core\Yw.WinFrmUI.Hydro.L2d.Core.csproj", "{AE2775AE-3C2D-49CB-BD3C-2FF5D4AE5B53}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HStation.WinFrmUI.Auth.Core", "WinFrmUI\HStation.WinFrmUI.Auth.Core\HStation.WinFrmUI.Auth.Core.csproj", "{62B68CCE-1FDA-42EB-8BBC-2053EB0E04CA}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HStation.Application.Assets.Core", "Application\HStation.Application.Assets.Core\HStation.Application.Assets.Core.csproj", "{6BC4873C-FB0D-46F1-ADCD-C1FD96B29A5D}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HStation.WinFrmUI.Dict.Core", "WinFrmUI\HStation.WinFrmUI.Dict.Core\HStation.WinFrmUI.Dict.Core.csproj", "{0D096C38-89A7-4C18-A62D-74A70693DC9F}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yw.WinFrmUI.Hydro.L3d.Core", "WinFrmUI\Yw.WinFrmUI.Hydro.L3d.Core\Yw.WinFrmUI.Hydro.L3d.Core.csproj", "{1201C5C6-8762-4168-B6D6-C658B6D654E7}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yw.WinFrmUI.Unit.Core", "WinFrmUI\Yw.WinFrmUI.Unit.Core\Yw.WinFrmUI.Unit.Core.csproj", "{2274B96A-C41A-42B5-A4E7-1C0706DF5D48}"
 EndProject
@@ -126,8 +110,6 @@
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HStation.WinFrmUI.Basic.Core", "WinFrmUI\HStation.WinFrmUI.Basic.Core\HStation.WinFrmUI.Basic.Core.csproj", "{2A30EB54-38CA-44D4-BB11-3C2658568346}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yw.WinFrmUI.Division.Core", "WinFrmUI\YW.WinFrmUI.Division.Core\Yw.WinFrmUI.Division.Core.csproj", "{85126D9A-8201-4231-B796-2BBFF8FE17FC}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yw.WinFrmUI.Hydro.W3d.Core", "WinFrmUI\Yw.WinFrmUI.Hydro.W3d.Core\Yw.WinFrmUI.Hydro.W3d.Core.csproj", "{F0829321-2C4D-40F8-A729-47FA9428DC66}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HStation.ReportFile.SDK.Core", "Component\HStation.ReportFile.SDK.Core\HStation.ReportFile.SDK.Core.csproj", "{4C71B0A5-2F2A-4AE3-86BF-556E7F8EF97B}"
 EndProject
@@ -184,6 +166,10 @@
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PBS.Desktop", "Desktop\PBS.Desktop\PBS.Desktop.csproj", "{C013AD3B-53A4-8187-1CFB-DA23F8811577}"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PBS.WinFrmUI.Hydro", "WinFrmUI\PBS.WinFrmUI.Hydro\PBS.WinFrmUI.Hydro.csproj", "{D8405A07-6BA9-4E0A-B2CA-BFB4C844DC56}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PBS.Console.Test", "Console\PBS.Console.Test\PBS.Console.Test.csproj", "{06CEF56B-7C66-4F1C-9647-73A8394FCBF6}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{F4B37540-7C50-4162-A086-31DC59823015}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -414,24 +400,6 @@
 		{D6D805ED-C848-4403-97AB-E86715B9E2DB}.Release|x64.Build.0 = Release|Any CPU
 		{D6D805ED-C848-4403-97AB-E86715B9E2DB}.Release|x86.ActiveCfg = Release|Any CPU
 		{D6D805ED-C848-4403-97AB-E86715B9E2DB}.Release|x86.Build.0 = Release|Any CPU
-		{454B8C89-EFF0-42E2-B569-C211F0168F5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{454B8C89-EFF0-42E2-B569-C211F0168F5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{454B8C89-EFF0-42E2-B569-C211F0168F5D}.Debug|x64.ActiveCfg = Debug|Any CPU
-		{454B8C89-EFF0-42E2-B569-C211F0168F5D}.Debug|x64.Build.0 = Debug|Any CPU
-		{454B8C89-EFF0-42E2-B569-C211F0168F5D}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{454B8C89-EFF0-42E2-B569-C211F0168F5D}.Debug|x86.Build.0 = Debug|Any CPU
-		{454B8C89-EFF0-42E2-B569-C211F0168F5D}.dll_test|Any CPU.ActiveCfg = Debug|Any CPU
-		{454B8C89-EFF0-42E2-B569-C211F0168F5D}.dll_test|Any CPU.Build.0 = Debug|Any CPU
-		{454B8C89-EFF0-42E2-B569-C211F0168F5D}.dll_test|x64.ActiveCfg = Debug|Any CPU
-		{454B8C89-EFF0-42E2-B569-C211F0168F5D}.dll_test|x64.Build.0 = Debug|Any CPU
-		{454B8C89-EFF0-42E2-B569-C211F0168F5D}.dll_test|x86.ActiveCfg = Debug|Any CPU
-		{454B8C89-EFF0-42E2-B569-C211F0168F5D}.dll_test|x86.Build.0 = Debug|Any CPU
-		{454B8C89-EFF0-42E2-B569-C211F0168F5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{454B8C89-EFF0-42E2-B569-C211F0168F5D}.Release|Any CPU.Build.0 = Release|Any CPU
-		{454B8C89-EFF0-42E2-B569-C211F0168F5D}.Release|x64.ActiveCfg = Release|Any CPU
-		{454B8C89-EFF0-42E2-B569-C211F0168F5D}.Release|x64.Build.0 = Release|Any CPU
-		{454B8C89-EFF0-42E2-B569-C211F0168F5D}.Release|x86.ActiveCfg = Release|Any CPU
-		{454B8C89-EFF0-42E2-B569-C211F0168F5D}.Release|x86.Build.0 = Release|Any CPU
 		{2AC76D6E-7035-4FD0-84EA-E00BA7D9876B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{2AC76D6E-7035-4FD0-84EA-E00BA7D9876B}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{2AC76D6E-7035-4FD0-84EA-E00BA7D9876B}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -522,78 +490,6 @@
 		{42261EEA-8BA7-4096-92B1-E809BDD72A82}.Release|x64.Build.0 = Release|Any CPU
 		{42261EEA-8BA7-4096-92B1-E809BDD72A82}.Release|x86.ActiveCfg = Release|Any CPU
 		{42261EEA-8BA7-4096-92B1-E809BDD72A82}.Release|x86.Build.0 = Release|Any CPU
-		{BBC8C860-98B1-45B1-B41D-518DCB402C17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{BBC8C860-98B1-45B1-B41D-518DCB402C17}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{BBC8C860-98B1-45B1-B41D-518DCB402C17}.Debug|x64.ActiveCfg = Debug|Any CPU
-		{BBC8C860-98B1-45B1-B41D-518DCB402C17}.Debug|x64.Build.0 = Debug|Any CPU
-		{BBC8C860-98B1-45B1-B41D-518DCB402C17}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{BBC8C860-98B1-45B1-B41D-518DCB402C17}.Debug|x86.Build.0 = Debug|Any CPU
-		{BBC8C860-98B1-45B1-B41D-518DCB402C17}.dll_test|Any CPU.ActiveCfg = Debug|Any CPU
-		{BBC8C860-98B1-45B1-B41D-518DCB402C17}.dll_test|Any CPU.Build.0 = Debug|Any CPU
-		{BBC8C860-98B1-45B1-B41D-518DCB402C17}.dll_test|x64.ActiveCfg = Debug|Any CPU
-		{BBC8C860-98B1-45B1-B41D-518DCB402C17}.dll_test|x64.Build.0 = Debug|Any CPU
-		{BBC8C860-98B1-45B1-B41D-518DCB402C17}.dll_test|x86.ActiveCfg = Debug|Any CPU
-		{BBC8C860-98B1-45B1-B41D-518DCB402C17}.dll_test|x86.Build.0 = Debug|Any CPU
-		{BBC8C860-98B1-45B1-B41D-518DCB402C17}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{BBC8C860-98B1-45B1-B41D-518DCB402C17}.Release|Any CPU.Build.0 = Release|Any CPU
-		{BBC8C860-98B1-45B1-B41D-518DCB402C17}.Release|x64.ActiveCfg = Release|Any CPU
-		{BBC8C860-98B1-45B1-B41D-518DCB402C17}.Release|x64.Build.0 = Release|Any CPU
-		{BBC8C860-98B1-45B1-B41D-518DCB402C17}.Release|x86.ActiveCfg = Release|Any CPU
-		{BBC8C860-98B1-45B1-B41D-518DCB402C17}.Release|x86.Build.0 = Release|Any CPU
-		{F6068234-6BFC-48B1-9FAB-2892C097C430}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{F6068234-6BFC-48B1-9FAB-2892C097C430}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{F6068234-6BFC-48B1-9FAB-2892C097C430}.Debug|x64.ActiveCfg = Debug|Any CPU
-		{F6068234-6BFC-48B1-9FAB-2892C097C430}.Debug|x64.Build.0 = Debug|Any CPU
-		{F6068234-6BFC-48B1-9FAB-2892C097C430}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{F6068234-6BFC-48B1-9FAB-2892C097C430}.Debug|x86.Build.0 = Debug|Any CPU
-		{F6068234-6BFC-48B1-9FAB-2892C097C430}.dll_test|Any CPU.ActiveCfg = Debug|Any CPU
-		{F6068234-6BFC-48B1-9FAB-2892C097C430}.dll_test|Any CPU.Build.0 = Debug|Any CPU
-		{F6068234-6BFC-48B1-9FAB-2892C097C430}.dll_test|x64.ActiveCfg = Debug|Any CPU
-		{F6068234-6BFC-48B1-9FAB-2892C097C430}.dll_test|x64.Build.0 = Debug|Any CPU
-		{F6068234-6BFC-48B1-9FAB-2892C097C430}.dll_test|x86.ActiveCfg = Debug|Any CPU
-		{F6068234-6BFC-48B1-9FAB-2892C097C430}.dll_test|x86.Build.0 = Debug|Any CPU
-		{F6068234-6BFC-48B1-9FAB-2892C097C430}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{F6068234-6BFC-48B1-9FAB-2892C097C430}.Release|Any CPU.Build.0 = Release|Any CPU
-		{F6068234-6BFC-48B1-9FAB-2892C097C430}.Release|x64.ActiveCfg = Release|Any CPU
-		{F6068234-6BFC-48B1-9FAB-2892C097C430}.Release|x64.Build.0 = Release|Any CPU
-		{F6068234-6BFC-48B1-9FAB-2892C097C430}.Release|x86.ActiveCfg = Release|Any CPU
-		{F6068234-6BFC-48B1-9FAB-2892C097C430}.Release|x86.Build.0 = Release|Any CPU
-		{D6F58BEC-660B-4EFF-9A8F-D70571F6EFB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{D6F58BEC-660B-4EFF-9A8F-D70571F6EFB8}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{D6F58BEC-660B-4EFF-9A8F-D70571F6EFB8}.Debug|x64.ActiveCfg = Debug|Any CPU
-		{D6F58BEC-660B-4EFF-9A8F-D70571F6EFB8}.Debug|x64.Build.0 = Debug|Any CPU
-		{D6F58BEC-660B-4EFF-9A8F-D70571F6EFB8}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{D6F58BEC-660B-4EFF-9A8F-D70571F6EFB8}.Debug|x86.Build.0 = Debug|Any CPU
-		{D6F58BEC-660B-4EFF-9A8F-D70571F6EFB8}.dll_test|Any CPU.ActiveCfg = Debug|Any CPU
-		{D6F58BEC-660B-4EFF-9A8F-D70571F6EFB8}.dll_test|Any CPU.Build.0 = Debug|Any CPU
-		{D6F58BEC-660B-4EFF-9A8F-D70571F6EFB8}.dll_test|x64.ActiveCfg = Debug|Any CPU
-		{D6F58BEC-660B-4EFF-9A8F-D70571F6EFB8}.dll_test|x64.Build.0 = Debug|Any CPU
-		{D6F58BEC-660B-4EFF-9A8F-D70571F6EFB8}.dll_test|x86.ActiveCfg = Debug|Any CPU
-		{D6F58BEC-660B-4EFF-9A8F-D70571F6EFB8}.dll_test|x86.Build.0 = Debug|Any CPU
-		{D6F58BEC-660B-4EFF-9A8F-D70571F6EFB8}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{D6F58BEC-660B-4EFF-9A8F-D70571F6EFB8}.Release|Any CPU.Build.0 = Release|Any CPU
-		{D6F58BEC-660B-4EFF-9A8F-D70571F6EFB8}.Release|x64.ActiveCfg = Release|Any CPU
-		{D6F58BEC-660B-4EFF-9A8F-D70571F6EFB8}.Release|x64.Build.0 = Release|Any CPU
-		{D6F58BEC-660B-4EFF-9A8F-D70571F6EFB8}.Release|x86.ActiveCfg = Release|Any CPU
-		{D6F58BEC-660B-4EFF-9A8F-D70571F6EFB8}.Release|x86.Build.0 = Release|Any CPU
-		{6D1548F3-2C29-4B96-A3F5-A9D3BDD65454}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{6D1548F3-2C29-4B96-A3F5-A9D3BDD65454}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{6D1548F3-2C29-4B96-A3F5-A9D3BDD65454}.Debug|x64.ActiveCfg = Debug|Any CPU
-		{6D1548F3-2C29-4B96-A3F5-A9D3BDD65454}.Debug|x64.Build.0 = Debug|Any CPU
-		{6D1548F3-2C29-4B96-A3F5-A9D3BDD65454}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{6D1548F3-2C29-4B96-A3F5-A9D3BDD65454}.Debug|x86.Build.0 = Debug|Any CPU
-		{6D1548F3-2C29-4B96-A3F5-A9D3BDD65454}.dll_test|Any CPU.ActiveCfg = Debug|Any CPU
-		{6D1548F3-2C29-4B96-A3F5-A9D3BDD65454}.dll_test|Any CPU.Build.0 = Debug|Any CPU
-		{6D1548F3-2C29-4B96-A3F5-A9D3BDD65454}.dll_test|x64.ActiveCfg = Debug|Any CPU
-		{6D1548F3-2C29-4B96-A3F5-A9D3BDD65454}.dll_test|x64.Build.0 = Debug|Any CPU
-		{6D1548F3-2C29-4B96-A3F5-A9D3BDD65454}.dll_test|x86.ActiveCfg = Debug|Any CPU
-		{6D1548F3-2C29-4B96-A3F5-A9D3BDD65454}.dll_test|x86.Build.0 = Debug|Any CPU
-		{6D1548F3-2C29-4B96-A3F5-A9D3BDD65454}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{6D1548F3-2C29-4B96-A3F5-A9D3BDD65454}.Release|Any CPU.Build.0 = Release|Any CPU
-		{6D1548F3-2C29-4B96-A3F5-A9D3BDD65454}.Release|x64.ActiveCfg = Release|Any CPU
-		{6D1548F3-2C29-4B96-A3F5-A9D3BDD65454}.Release|x64.Build.0 = Release|Any CPU
-		{6D1548F3-2C29-4B96-A3F5-A9D3BDD65454}.Release|x86.ActiveCfg = Release|Any CPU
-		{6D1548F3-2C29-4B96-A3F5-A9D3BDD65454}.Release|x86.Build.0 = Release|Any CPU
 		{1A862895-9461-4E89-A695-F2150E1D34C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{1A862895-9461-4E89-A695-F2150E1D34C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{1A862895-9461-4E89-A695-F2150E1D34C8}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -720,24 +616,6 @@
 		{3F682666-7578-47E7-8E1D-020AB5B75678}.Release|x64.Build.0 = Release|Any CPU
 		{3F682666-7578-47E7-8E1D-020AB5B75678}.Release|x86.ActiveCfg = Release|Any CPU
 		{3F682666-7578-47E7-8E1D-020AB5B75678}.Release|x86.Build.0 = Release|Any CPU
-		{0A0F9D7E-87C9-4276-823D-495355A01E8C}.Debug|Any CPU.ActiveCfg = Debug|x64
-		{0A0F9D7E-87C9-4276-823D-495355A01E8C}.Debug|Any CPU.Build.0 = Debug|x64
-		{0A0F9D7E-87C9-4276-823D-495355A01E8C}.Debug|x64.ActiveCfg = Debug|x64
-		{0A0F9D7E-87C9-4276-823D-495355A01E8C}.Debug|x64.Build.0 = Debug|x64
-		{0A0F9D7E-87C9-4276-823D-495355A01E8C}.Debug|x86.ActiveCfg = Debug|Win32
-		{0A0F9D7E-87C9-4276-823D-495355A01E8C}.Debug|x86.Build.0 = Debug|Win32
-		{0A0F9D7E-87C9-4276-823D-495355A01E8C}.dll_test|Any CPU.ActiveCfg = dll_test|x64
-		{0A0F9D7E-87C9-4276-823D-495355A01E8C}.dll_test|Any CPU.Build.0 = dll_test|x64
-		{0A0F9D7E-87C9-4276-823D-495355A01E8C}.dll_test|x64.ActiveCfg = dll_test|x64
-		{0A0F9D7E-87C9-4276-823D-495355A01E8C}.dll_test|x64.Build.0 = dll_test|x64
-		{0A0F9D7E-87C9-4276-823D-495355A01E8C}.dll_test|x86.ActiveCfg = dll_test|Win32
-		{0A0F9D7E-87C9-4276-823D-495355A01E8C}.dll_test|x86.Build.0 = dll_test|Win32
-		{0A0F9D7E-87C9-4276-823D-495355A01E8C}.Release|Any CPU.ActiveCfg = Release|x64
-		{0A0F9D7E-87C9-4276-823D-495355A01E8C}.Release|Any CPU.Build.0 = Release|x64
-		{0A0F9D7E-87C9-4276-823D-495355A01E8C}.Release|x64.ActiveCfg = Release|x64
-		{0A0F9D7E-87C9-4276-823D-495355A01E8C}.Release|x64.Build.0 = Release|x64
-		{0A0F9D7E-87C9-4276-823D-495355A01E8C}.Release|x86.ActiveCfg = Release|Win32
-		{0A0F9D7E-87C9-4276-823D-495355A01E8C}.Release|x86.Build.0 = Release|Win32
 		{DBC6DC37-8BA8-4CFC-A98C-E6D34EE2E5D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{DBC6DC37-8BA8-4CFC-A98C-E6D34EE2E5D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{DBC6DC37-8BA8-4CFC-A98C-E6D34EE2E5D7}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -756,24 +634,6 @@
 		{DBC6DC37-8BA8-4CFC-A98C-E6D34EE2E5D7}.Release|x64.Build.0 = Release|Any CPU
 		{DBC6DC37-8BA8-4CFC-A98C-E6D34EE2E5D7}.Release|x86.ActiveCfg = Release|Any CPU
 		{DBC6DC37-8BA8-4CFC-A98C-E6D34EE2E5D7}.Release|x86.Build.0 = Release|Any CPU
-		{AE2775AE-3C2D-49CB-BD3C-2FF5D4AE5B53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{AE2775AE-3C2D-49CB-BD3C-2FF5D4AE5B53}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{AE2775AE-3C2D-49CB-BD3C-2FF5D4AE5B53}.Debug|x64.ActiveCfg = Debug|Any CPU
-		{AE2775AE-3C2D-49CB-BD3C-2FF5D4AE5B53}.Debug|x64.Build.0 = Debug|Any CPU
-		{AE2775AE-3C2D-49CB-BD3C-2FF5D4AE5B53}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{AE2775AE-3C2D-49CB-BD3C-2FF5D4AE5B53}.Debug|x86.Build.0 = Debug|Any CPU
-		{AE2775AE-3C2D-49CB-BD3C-2FF5D4AE5B53}.dll_test|Any CPU.ActiveCfg = Debug|Any CPU
-		{AE2775AE-3C2D-49CB-BD3C-2FF5D4AE5B53}.dll_test|Any CPU.Build.0 = Debug|Any CPU
-		{AE2775AE-3C2D-49CB-BD3C-2FF5D4AE5B53}.dll_test|x64.ActiveCfg = Debug|Any CPU
-		{AE2775AE-3C2D-49CB-BD3C-2FF5D4AE5B53}.dll_test|x64.Build.0 = Debug|Any CPU
-		{AE2775AE-3C2D-49CB-BD3C-2FF5D4AE5B53}.dll_test|x86.ActiveCfg = Debug|Any CPU
-		{AE2775AE-3C2D-49CB-BD3C-2FF5D4AE5B53}.dll_test|x86.Build.0 = Debug|Any CPU
-		{AE2775AE-3C2D-49CB-BD3C-2FF5D4AE5B53}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{AE2775AE-3C2D-49CB-BD3C-2FF5D4AE5B53}.Release|Any CPU.Build.0 = Release|Any CPU
-		{AE2775AE-3C2D-49CB-BD3C-2FF5D4AE5B53}.Release|x64.ActiveCfg = Release|Any CPU
-		{AE2775AE-3C2D-49CB-BD3C-2FF5D4AE5B53}.Release|x64.Build.0 = Release|Any CPU
-		{AE2775AE-3C2D-49CB-BD3C-2FF5D4AE5B53}.Release|x86.ActiveCfg = Release|Any CPU
-		{AE2775AE-3C2D-49CB-BD3C-2FF5D4AE5B53}.Release|x86.Build.0 = Release|Any CPU
 		{62B68CCE-1FDA-42EB-8BBC-2053EB0E04CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{62B68CCE-1FDA-42EB-8BBC-2053EB0E04CA}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{62B68CCE-1FDA-42EB-8BBC-2053EB0E04CA}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -828,24 +688,6 @@
 		{0D096C38-89A7-4C18-A62D-74A70693DC9F}.Release|x64.Build.0 = Release|Any CPU
 		{0D096C38-89A7-4C18-A62D-74A70693DC9F}.Release|x86.ActiveCfg = Release|Any CPU
 		{0D096C38-89A7-4C18-A62D-74A70693DC9F}.Release|x86.Build.0 = Release|Any CPU
-		{1201C5C6-8762-4168-B6D6-C658B6D654E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{1201C5C6-8762-4168-B6D6-C658B6D654E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{1201C5C6-8762-4168-B6D6-C658B6D654E7}.Debug|x64.ActiveCfg = Debug|Any CPU
-		{1201C5C6-8762-4168-B6D6-C658B6D654E7}.Debug|x64.Build.0 = Debug|Any CPU
-		{1201C5C6-8762-4168-B6D6-C658B6D654E7}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{1201C5C6-8762-4168-B6D6-C658B6D654E7}.Debug|x86.Build.0 = Debug|Any CPU
-		{1201C5C6-8762-4168-B6D6-C658B6D654E7}.dll_test|Any CPU.ActiveCfg = Debug|Any CPU
-		{1201C5C6-8762-4168-B6D6-C658B6D654E7}.dll_test|Any CPU.Build.0 = Debug|Any CPU
-		{1201C5C6-8762-4168-B6D6-C658B6D654E7}.dll_test|x64.ActiveCfg = Debug|Any CPU
-		{1201C5C6-8762-4168-B6D6-C658B6D654E7}.dll_test|x64.Build.0 = Debug|Any CPU
-		{1201C5C6-8762-4168-B6D6-C658B6D654E7}.dll_test|x86.ActiveCfg = Debug|Any CPU
-		{1201C5C6-8762-4168-B6D6-C658B6D654E7}.dll_test|x86.Build.0 = Debug|Any CPU
-		{1201C5C6-8762-4168-B6D6-C658B6D654E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{1201C5C6-8762-4168-B6D6-C658B6D654E7}.Release|Any CPU.Build.0 = Release|Any CPU
-		{1201C5C6-8762-4168-B6D6-C658B6D654E7}.Release|x64.ActiveCfg = Release|Any CPU
-		{1201C5C6-8762-4168-B6D6-C658B6D654E7}.Release|x64.Build.0 = Release|Any CPU
-		{1201C5C6-8762-4168-B6D6-C658B6D654E7}.Release|x86.ActiveCfg = Release|Any CPU
-		{1201C5C6-8762-4168-B6D6-C658B6D654E7}.Release|x86.Build.0 = Release|Any CPU
 		{2274B96A-C41A-42B5-A4E7-1C0706DF5D48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{2274B96A-C41A-42B5-A4E7-1C0706DF5D48}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{2274B96A-C41A-42B5-A4E7-1C0706DF5D48}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -1134,24 +976,6 @@
 		{85126D9A-8201-4231-B796-2BBFF8FE17FC}.Release|x64.Build.0 = Release|Any CPU
 		{85126D9A-8201-4231-B796-2BBFF8FE17FC}.Release|x86.ActiveCfg = Release|Any CPU
 		{85126D9A-8201-4231-B796-2BBFF8FE17FC}.Release|x86.Build.0 = Release|Any CPU
-		{F0829321-2C4D-40F8-A729-47FA9428DC66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{F0829321-2C4D-40F8-A729-47FA9428DC66}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{F0829321-2C4D-40F8-A729-47FA9428DC66}.Debug|x64.ActiveCfg = Debug|Any CPU
-		{F0829321-2C4D-40F8-A729-47FA9428DC66}.Debug|x64.Build.0 = Debug|Any CPU
-		{F0829321-2C4D-40F8-A729-47FA9428DC66}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{F0829321-2C4D-40F8-A729-47FA9428DC66}.Debug|x86.Build.0 = Debug|Any CPU
-		{F0829321-2C4D-40F8-A729-47FA9428DC66}.dll_test|Any CPU.ActiveCfg = Debug|Any CPU
-		{F0829321-2C4D-40F8-A729-47FA9428DC66}.dll_test|Any CPU.Build.0 = Debug|Any CPU
-		{F0829321-2C4D-40F8-A729-47FA9428DC66}.dll_test|x64.ActiveCfg = Debug|Any CPU
-		{F0829321-2C4D-40F8-A729-47FA9428DC66}.dll_test|x64.Build.0 = Debug|Any CPU
-		{F0829321-2C4D-40F8-A729-47FA9428DC66}.dll_test|x86.ActiveCfg = Debug|Any CPU
-		{F0829321-2C4D-40F8-A729-47FA9428DC66}.dll_test|x86.Build.0 = Debug|Any CPU
-		{F0829321-2C4D-40F8-A729-47FA9428DC66}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{F0829321-2C4D-40F8-A729-47FA9428DC66}.Release|Any CPU.Build.0 = Release|Any CPU
-		{F0829321-2C4D-40F8-A729-47FA9428DC66}.Release|x64.ActiveCfg = Release|Any CPU
-		{F0829321-2C4D-40F8-A729-47FA9428DC66}.Release|x64.Build.0 = Release|Any CPU
-		{F0829321-2C4D-40F8-A729-47FA9428DC66}.Release|x86.ActiveCfg = Release|Any CPU
-		{F0829321-2C4D-40F8-A729-47FA9428DC66}.Release|x86.Build.0 = Release|Any CPU
 		{4C71B0A5-2F2A-4AE3-86BF-556E7F8EF97B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{4C71B0A5-2F2A-4AE3-86BF-556E7F8EF97B}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{4C71B0A5-2F2A-4AE3-86BF-556E7F8EF97B}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -1458,6 +1282,24 @@
 		{D8405A07-6BA9-4E0A-B2CA-BFB4C844DC56}.Release|x64.Build.0 = Release|Any CPU
 		{D8405A07-6BA9-4E0A-B2CA-BFB4C844DC56}.Release|x86.ActiveCfg = Release|Any CPU
 		{D8405A07-6BA9-4E0A-B2CA-BFB4C844DC56}.Release|x86.Build.0 = Release|Any CPU
+		{06CEF56B-7C66-4F1C-9647-73A8394FCBF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{06CEF56B-7C66-4F1C-9647-73A8394FCBF6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{06CEF56B-7C66-4F1C-9647-73A8394FCBF6}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{06CEF56B-7C66-4F1C-9647-73A8394FCBF6}.Debug|x64.Build.0 = Debug|Any CPU
+		{06CEF56B-7C66-4F1C-9647-73A8394FCBF6}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{06CEF56B-7C66-4F1C-9647-73A8394FCBF6}.Debug|x86.Build.0 = Debug|Any CPU
+		{06CEF56B-7C66-4F1C-9647-73A8394FCBF6}.dll_test|Any CPU.ActiveCfg = Debug|Any CPU
+		{06CEF56B-7C66-4F1C-9647-73A8394FCBF6}.dll_test|Any CPU.Build.0 = Debug|Any CPU
+		{06CEF56B-7C66-4F1C-9647-73A8394FCBF6}.dll_test|x64.ActiveCfg = Debug|Any CPU
+		{06CEF56B-7C66-4F1C-9647-73A8394FCBF6}.dll_test|x64.Build.0 = Debug|Any CPU
+		{06CEF56B-7C66-4F1C-9647-73A8394FCBF6}.dll_test|x86.ActiveCfg = Debug|Any CPU
+		{06CEF56B-7C66-4F1C-9647-73A8394FCBF6}.dll_test|x86.Build.0 = Debug|Any CPU
+		{06CEF56B-7C66-4F1C-9647-73A8394FCBF6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{06CEF56B-7C66-4F1C-9647-73A8394FCBF6}.Release|Any CPU.Build.0 = Release|Any CPU
+		{06CEF56B-7C66-4F1C-9647-73A8394FCBF6}.Release|x64.ActiveCfg = Release|Any CPU
+		{06CEF56B-7C66-4F1C-9647-73A8394FCBF6}.Release|x64.Build.0 = Release|Any CPU
+		{06CEF56B-7C66-4F1C-9647-73A8394FCBF6}.Release|x86.ActiveCfg = Release|Any CPU
+		{06CEF56B-7C66-4F1C-9647-73A8394FCBF6}.Release|x86.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -1475,16 +1317,11 @@
 		{5D082C0C-FD9B-4BEE-B57F-6C3D1B9F0BB3} = {5F0D2CDB-F911-4FFC-965B-F303D739712C}
 		{4724474E-66CD-4237-B3A0-085125AD2D8F} = {8592F739-4B08-4B0F-B0D5-FAB10D60B2A2}
 		{D6D805ED-C848-4403-97AB-E86715B9E2DB} = {0469F9DE-F12C-4B83-A871-A77A82DCB4C8}
-		{454B8C89-EFF0-42E2-B569-C211F0168F5D} = {E27E21BB-A9BD-4F2E-9713-22A1DD2C2F0E}
 		{2AC76D6E-7035-4FD0-84EA-E00BA7D9876B} = {1C729ADD-9928-43EA-876B-3D783D45CA0A}
 		{EC0D8314-B4AB-4FA6-A490-C34E5773C8AA} = {5F0D2CDB-F911-4FFC-965B-F303D739712C}
 		{A9253100-6A3B-47E8-AACC-289C9756336B} = {52EB5541-5EEA-4141-8C2F-1D3B499A1D6F}
 		{0AFD5926-BBB4-4DC9-92B3-5FCD15C84A42} = {7D5BC358-1783-460B-A8E1-DEF292149702}
 		{42261EEA-8BA7-4096-92B1-E809BDD72A82} = {1C729ADD-9928-43EA-876B-3D783D45CA0A}
-		{BBC8C860-98B1-45B1-B41D-518DCB402C17} = {E27E21BB-A9BD-4F2E-9713-22A1DD2C2F0E}
-		{F6068234-6BFC-48B1-9FAB-2892C097C430} = {9F4F9ECE-9C4C-4796-91A1-69805F823EA5}
-		{D6F58BEC-660B-4EFF-9A8F-D70571F6EFB8} = {9F4F9ECE-9C4C-4796-91A1-69805F823EA5}
-		{6D1548F3-2C29-4B96-A3F5-A9D3BDD65454} = {9F4F9ECE-9C4C-4796-91A1-69805F823EA5}
 		{1A862895-9461-4E89-A695-F2150E1D34C8} = {E27E21BB-A9BD-4F2E-9713-22A1DD2C2F0E}
 		{C4A4B99E-B96F-4AA6-9CB2-F4A472CA57F0} = {7D5BC358-1783-460B-A8E1-DEF292149702}
 		{2F857FCF-7EAE-4B09-ACA9-50CC14526CA1} = {52EB5541-5EEA-4141-8C2F-1D3B499A1D6F}
@@ -1492,13 +1329,10 @@
 		{AD2925B6-8E46-4B16-99F9-C0FD1F145B6B} = {BED981CF-7556-498E-9FDF-19029045CDDB}
 		{E6D1F549-1604-4F6B-856C-C8268F6D30BA} = {BED981CF-7556-498E-9FDF-19029045CDDB}
 		{3F682666-7578-47E7-8E1D-020AB5B75678} = {BED981CF-7556-498E-9FDF-19029045CDDB}
-		{0A0F9D7E-87C9-4276-823D-495355A01E8C} = {9F4F9ECE-9C4C-4796-91A1-69805F823EA5}
 		{DBC6DC37-8BA8-4CFC-A98C-E6D34EE2E5D7} = {1C729ADD-9928-43EA-876B-3D783D45CA0A}
-		{AE2775AE-3C2D-49CB-BD3C-2FF5D4AE5B53} = {E27E21BB-A9BD-4F2E-9713-22A1DD2C2F0E}
 		{62B68CCE-1FDA-42EB-8BBC-2053EB0E04CA} = {1C729ADD-9928-43EA-876B-3D783D45CA0A}
 		{6BC4873C-FB0D-46F1-ADCD-C1FD96B29A5D} = {8592F739-4B08-4B0F-B0D5-FAB10D60B2A2}
 		{0D096C38-89A7-4C18-A62D-74A70693DC9F} = {1C729ADD-9928-43EA-876B-3D783D45CA0A}
-		{1201C5C6-8762-4168-B6D6-C658B6D654E7} = {E27E21BB-A9BD-4F2E-9713-22A1DD2C2F0E}
 		{2274B96A-C41A-42B5-A4E7-1C0706DF5D48} = {E27E21BB-A9BD-4F2E-9713-22A1DD2C2F0E}
 		{D6AC90F8-0DF0-4AC2-B17A-6A02DB467347} = {7656976D-96EA-4E46-AD33-CF3C1DF47632}
 		{78A70278-A1D0-43AD-A156-CBE13BC15F45} = {95526A80-4E17-4FD8-AA26-D25251DA9EA5}
@@ -1515,7 +1349,6 @@
 		{C0C9D757-5AA3-4590-9161-C4CE2700F822} = {52EB5541-5EEA-4141-8C2F-1D3B499A1D6F}
 		{2A30EB54-38CA-44D4-BB11-3C2658568346} = {1C729ADD-9928-43EA-876B-3D783D45CA0A}
 		{85126D9A-8201-4231-B796-2BBFF8FE17FC} = {E27E21BB-A9BD-4F2E-9713-22A1DD2C2F0E}
-		{F0829321-2C4D-40F8-A729-47FA9428DC66} = {E27E21BB-A9BD-4F2E-9713-22A1DD2C2F0E}
 		{4C71B0A5-2F2A-4AE3-86BF-556E7F8EF97B} = {0469F9DE-F12C-4B83-A871-A77A82DCB4C8}
 		{21D4EA4C-3A6A-4B65-9FD8-11A34768872C} = {0469F9DE-F12C-4B83-A871-A77A82DCB4C8}
 		{36AD458B-32A8-4FF9-8548-8FD2CD7ADABF} = {8592F739-4B08-4B0F-B0D5-FAB10D60B2A2}
diff --git "a/WinFrmUI/PBS.WinFrmUI.Hydro/01-water-supply-system-curve/SystemCurveCalcHelper - \345\244\215\345\210\266.cs" "b/WinFrmUI/PBS.WinFrmUI.Hydro/01-water-supply-system-curve/SystemCurveCalcHelper - \345\244\215\345\210\266.cs"
new file mode 100644
index 0000000..1badfe9
--- /dev/null
+++ "b/WinFrmUI/PBS.WinFrmUI.Hydro/01-water-supply-system-curve/SystemCurveCalcHelper - \345\244\215\345\210\266.cs"
@@ -0,0 +1,209 @@
+锘縰sing System.Collections.Concurrent;
+using System.Runtime.InteropServices;
+
+
+namespace PBS.WinFrmUI.Hydro
+{
+    public class SystemCurveCalcHelper
+    {
+
+
+
+    }
+
+    public class ParallelEpanetSimulator : IDisposable
+    {
+        #region EPANET API 澹版槑
+        // 娉細闇�鏍规嵁瀹為檯EPANET 2.2鐨凜瀵煎嚭鍑芥暟绛惧悕璋冩暣
+        [DllImport("epanet2.dll", EntryPoint = "EN_open", CallingConvention = CallingConvention.Cdecl)]
+        private static extern int EN_open(string inpFile, string rptFile, string outFile);
+
+        [DllImport("epanet2.dll", EntryPoint = "EN_close", CallingConvention = CallingConvention.Cdecl)]
+        private static extern int EN_close();
+
+        [DllImport("epanet2.dll", EntryPoint = "EN_getcount", CallingConvention = CallingConvention.Cdecl)]
+        private static extern int EN_getcount(int countType);
+
+        [DllImport("epanet2.dll", EntryPoint = "EN_setnodevalue", CallingConvention = CallingConvention.Cdecl)]
+        private static extern int EN_setnodevalue(int index, int paramCode, double value);
+
+        [DllImport("epanet2.dll", EntryPoint = "EN_initH", CallingConvention = CallingConvention.Cdecl)]
+        private static extern int EN_initH(int saveFlag);
+
+        [DllImport("epanet2.dll", EntryPoint = "EN_runH", CallingConvention = CallingConvention.Cdecl)]
+        private static extern int EN_runH(ref long currentTime);
+
+        [DllImport("epanet2.dll", EntryPoint = "EN_nextH", CallingConvention = CallingConvention.Cdecl)]
+        private static extern int EN_nextH(ref long timeStep);
+
+        private const int EN_NODECOUNT = 0;
+        private const int EN_BASEDEMAND = 1;
+        #endregion
+
+        #region 鏍稿績鍙傛暟
+        private readonly string _inpFilePath;
+        private readonly double _minDemand;
+        private readonly double _maxDemand;
+        private readonly int _nodeCount;
+        private readonly int _totalIterations;
+        private readonly ConcurrentBag<SimulationResult> _results = new();
+        #endregion
+
+        public ParallelEpanetSimulator(string inpPath, double minDemand, double maxDemand, int iterations)
+        {
+            _inpFilePath = inpPath;
+            _minDemand = minDemand;
+            _maxDemand = maxDemand;
+            _totalIterations = iterations;
+
+            using (var helper = new Yw.Epanet.InteropXHelper())
+            {    
+                // 鍒濆鍖栬幏鍙栬妭鐐规暟閲�
+                var err=  helper.Open(_inpFilePath, "", "");
+                CheckError((int)err);
+
+
+                err = helper.GetCount( Yw.Epanet.eCountType.Node,out int count); 
+                helper.Close();
+                _nodeCount = count;
+            } 
+        }
+
+        public void RunParallelSimulations(int maxDegreeOfParallelism = -1)
+        {
+            // 棰勭敓鎴愭墍鏈夐殢鏈洪渶姹傦紙绾跨▼瀹夊叏锛�
+            var allDemands = GenerateAllDemands(_nodeCount, _totalIterations);
+
+            var parallelOptions = new ParallelOptions
+            {
+                MaxDegreeOfParallelism = maxDegreeOfParallelism,
+                TaskScheduler = TaskScheduler.Default
+            };
+
+            Parallel.For(0, _totalIterations, parallelOptions, iter =>
+            {
+                using (var helper = new Yw.Epanet.InteropXHelper())
+                {
+                    // 鍒濆鍖栬幏鍙栬妭鐐规暟閲�
+                    var err = helper.Open(_inpFilePath, "", "");
+                    CheckError((int)err);
+
+                    try
+                    {
+                        // 璁剧疆褰撳墠杩唬鐨勯渶姘撮噺
+                        for (int nodeIdx = 1; nodeIdx <= _nodeCount; nodeIdx++)
+                        {
+                            double demand = allDemands[iter, nodeIdx - 1];
+                            err = helper.SetNodeValue(nodeIdx, Yw.Epanet.eNodeProperty.BaseDemand, demand);
+                            CheckError((int)err);
+                        }
+
+                        // 杩愯姘村姏妯℃嫙
+                        var result = RunSingleSimulation();
+                        _results.Add(result);
+                         
+                    }
+                    catch (Exception)
+                    {
+                        throw;
+                    }
+                    finally
+                    {
+                        helper.Close();
+                    }
+
+                }
+
+
+                //// 姣忎釜绾跨▼鐙珛鍔犺浇妯″瀷閬垮厤璧勬簮鍐茬獊
+                //EN_open(_inpFilePath, null, null);
+                //try
+                //{
+                //    // 璁剧疆褰撳墠杩唬鐨勯渶姘撮噺
+                //    for (int nodeIdx = 1; nodeIdx <= _nodeCount; nodeIdx++)
+                //    {
+                //        double demand = allDemands[iter, nodeIdx - 1];
+                //        int err = EN_setnodevalue(nodeIdx, EN_BASEDEMAND, demand);
+                //        CheckError(err);
+                //    }
+
+                //    // 杩愯姘村姏妯℃嫙
+                //    var result = RunSingleSimulation();
+                //    _results.Add(result);
+                //}
+                //finally
+                //{
+                //    EN_close();
+                //}
+            });
+        }
+
+        private double[,] GenerateAllDemands(int nodeCount, int totalIterations)
+        {
+            double[,] demands = new double[totalIterations, nodeCount];
+            Parallel.For(0, totalIterations, iter =>
+            {
+                var rnd = new Random(Guid.NewGuid().GetHashCode());
+                for (int node = 0; node < nodeCount; node++)
+                {
+                    demands[iter, node] = _minDemand + (_maxDemand - _minDemand) * rnd.NextDouble();
+                }
+            });
+            return demands;
+        }
+
+        private SimulationResult RunSingleSimulation()
+        {
+            var result = new SimulationResult();
+            long currentTime = 0, timeStep = 0;
+            int err;
+
+            err = EN_initH(0);
+            CheckError(err);
+
+            while (true)
+            {
+                err = EN_runH(ref currentTime);
+                if (err > 0) break; // 妯℃嫙缁撴潫
+
+                // 鍦ㄦ澶勬崟鑾风粨鏋滐紙绀轰緥锛氳褰曟渶澶у帇鍔涳級
+                for (int nodeIdx = 1; nodeIdx <= _nodeCount; nodeIdx++)
+                {
+                    double pressure = 0;
+                    // 鍋囪鏈塃N_getnodevalue鐨勫疄鐜�
+                    // EN_getnodevalue(nodeIdx, EN_PRESSURE, ref pressure);
+                    result.UpdateMaxPressure(nodeIdx, pressure);
+                }
+
+                err = EN_nextH(ref timeStep);
+                CheckError(err);
+            }
+
+            return result;
+        }
+
+        private void CheckError(int errorCode)
+        {
+            if (errorCode != 0)
+                throw new EpanetException($"EPANET error {errorCode}");
+        }
+
+        public void Dispose() => EN_close();
+
+        public class SimulationResult
+        {
+            public ConcurrentDictionary<int, double> MaxPressures { get; } = new();
+
+            public void UpdateMaxPressure(int nodeId, double pressure)
+            {
+                MaxPressures.AddOrUpdate(nodeId, pressure,
+                    (id, old) => Math.Max(old, pressure));
+            }
+        }
+    }
+
+    public class EpanetException : Exception
+    {
+        public EpanetException(string message) : base(message) { }
+    }
+}
diff --git a/WinFrmUI/PBS.WinFrmUI.Hydro/01-water-supply-system-curve/SystemCurveCalcHelper.cs b/WinFrmUI/PBS.WinFrmUI.Hydro/01-water-supply-system-curve/SystemCurveCalcHelper.cs
new file mode 100644
index 0000000..cad9411
--- /dev/null
+++ b/WinFrmUI/PBS.WinFrmUI.Hydro/01-water-supply-system-curve/SystemCurveCalcHelper.cs
@@ -0,0 +1,172 @@
+锘縰sing System.Collections.Concurrent;
+using System.Runtime.InteropServices;
+
+
+namespace PBS.WinFrmUI.Hydro
+{
+    public class SystemCurveCalcHelper
+    {
+
+
+
+    }
+
+    public class ParallelEpanetSimulator : IDisposable
+    {
+        #region EPANET API 澹版槑
+        // 娉細闇�鏍规嵁瀹為檯EPANET 2.2鐨凜瀵煎嚭鍑芥暟绛惧悕璋冩暣
+        [DllImport("epanet2.dll", EntryPoint = "EN_open", CallingConvention = CallingConvention.Cdecl)]
+        private static extern int EN_open(string inpFile, string rptFile, string outFile);
+
+        [DllImport("epanet2.dll", EntryPoint = "EN_close", CallingConvention = CallingConvention.Cdecl)]
+        private static extern int EN_close();
+
+        [DllImport("epanet2.dll", EntryPoint = "EN_getcount", CallingConvention = CallingConvention.Cdecl)]
+        private static extern int EN_getcount(int countType);
+
+        [DllImport("epanet2.dll", EntryPoint = "EN_setnodevalue", CallingConvention = CallingConvention.Cdecl)]
+        private static extern int EN_setnodevalue(int index, int paramCode, double value);
+
+        [DllImport("epanet2.dll", EntryPoint = "EN_initH", CallingConvention = CallingConvention.Cdecl)]
+        private static extern int EN_initH(int saveFlag);
+
+        [DllImport("epanet2.dll", EntryPoint = "EN_runH", CallingConvention = CallingConvention.Cdecl)]
+        private static extern int EN_runH(ref long currentTime);
+
+        [DllImport("epanet2.dll", EntryPoint = "EN_nextH", CallingConvention = CallingConvention.Cdecl)]
+        private static extern int EN_nextH(ref long timeStep);
+
+        private const int EN_NODECOUNT = 0;
+        private const int EN_BASEDEMAND = 1;
+        #endregion
+
+        #region 鏍稿績鍙傛暟
+        private readonly string _inpFilePath;
+        private readonly double _minDemand;
+        private readonly double _maxDemand;
+        private readonly int _nodeCount;
+        private readonly int _totalIterations;
+        public ConcurrentBag<SimulationResult> _results = new();
+        #endregion
+
+        public ParallelEpanetSimulator(string inpPath, double minDemand, double maxDemand, int iterations)
+        {
+            _inpFilePath = inpPath;
+            _minDemand = minDemand;
+            _maxDemand = maxDemand;
+            _totalIterations = iterations;
+
+            using (var helper = new Yw.Epanet.InteropXHelper())
+            {
+                // 鍒濆鍖栬幏鍙栬妭鐐规暟閲�
+                var err = helper.Open(_inpFilePath, "", "");
+                CheckError((int)err);
+
+
+                err = helper.GetCount(Yw.Epanet.eCountType.Node, out int count);
+                helper.Close();
+                _nodeCount = count;
+            }
+        }
+
+        public List<SimulationResult> RunParallelSimulations(int maxDegreeOfParallelism = -1)
+        {
+            // 棰勭敓鎴愭墍鏈夐殢鏈洪渶姹傦紙绾跨▼瀹夊叏锛�
+            var allDemands = GenerateAllDemands(_nodeCount, _totalIterations);
+
+            var parallelOptions = new ParallelOptions
+            {
+                MaxDegreeOfParallelism = maxDegreeOfParallelism,
+                TaskScheduler = TaskScheduler.Default
+            };
+
+
+
+            long currentTime = 0; double pressure = 0;
+            //Parallel.For(0, _totalIterations, parallelOptions, iter =>
+            //{
+            using (var helper = new Yw.Epanet.InteropXHelper())
+            {
+
+                // 鍒濆鍖栬幏鍙栬妭鐐规暟閲�
+                var err = helper.Open(_inpFilePath, "", "");
+                CheckError((int)err);
+                err = helper.OpenH();
+                CheckError((int)err);
+
+                for (int i = 0; i < 20000; i++)
+                {
+                    helper.InitH(false);
+
+                    for (int nodeIdx = 1; nodeIdx <= _nodeCount; nodeIdx++)
+                    {
+                        double demand = allDemands[i, nodeIdx - 1];
+                        err = helper.SetNodeValue(nodeIdx, Yw.Epanet.eNodeProperty.BaseDemand, demand);
+                        CheckError((int)err);
+                    }
+                   
+                    helper.RunH(out long t);
+
+                    var result = new SimulationResult();
+                    for (int nodeIdx = 1; nodeIdx <= _nodeCount; nodeIdx++)
+                    {
+                        pressure = 0;
+                        helper.GetNodeValue(nodeIdx, Yw.Epanet.eNodeProperty.Pressure, out pressure);
+                        result.UpdateMaxPressure(nodeIdx, pressure);
+                    }
+                    helper.NextH(out long tstep);
+                    _results.Add(result);
+                }
+
+
+
+                helper.Close();
+
+            }
+
+
+            //});
+
+            return _results.ToList();
+        }
+
+        private double[,] GenerateAllDemands(int nodeCount, int totalIterations)
+        {
+            double[,] demands = new double[totalIterations, nodeCount];
+            Parallel.For(0, totalIterations, iter =>
+            {
+                var rnd = new Random(Guid.NewGuid().GetHashCode());
+                for (int node = 0; node < nodeCount; node++)
+                {
+                    demands[iter, node] = _minDemand + (_maxDemand - _minDemand) * rnd.NextDouble();
+                }
+            });
+            return demands;
+        }
+
+
+        private void CheckError(int errorCode)
+        {
+            if (errorCode != 0)
+                throw new EpanetException($"EPANET error {errorCode}");
+        }
+
+        public void Dispose() => EN_close();
+
+        public class SimulationResult
+        {
+            public ConcurrentDictionary<int, double> MaxPressures { get; } = new();
+
+            public void UpdateMaxPressure(int nodeId, double pressure)
+            {
+                MaxPressures.AddOrUpdate(nodeId, pressure,
+                    (id, old) => Math.Max(old, pressure));
+            }
+        }
+    }
+
+    public class EpanetException : Exception
+    {
+        public EpanetException(string message) : base(message) { }
+    }
+}
diff --git a/WinFrmUI/PBS.WinFrmUI.Hydro/01-water-supply-system-curve/SystemCurvePage.Designer.cs b/WinFrmUI/PBS.WinFrmUI.Hydro/01-water-supply-system-curve/SystemCurvePage.Designer.cs
new file mode 100644
index 0000000..53869eb
--- /dev/null
+++ b/WinFrmUI/PBS.WinFrmUI.Hydro/01-water-supply-system-curve/SystemCurvePage.Designer.cs
@@ -0,0 +1,139 @@
+锘縰sing DevExpress.Utils;
+using DevExpress.XtraGrid.Views.Grid;
+using System;
+using System.ComponentModel;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace PBS.WinFrmUI.Hydro
+{
+    partial class SystemCurvePage
+    {
+        /// <summary> 
+        /// Required designer variable.
+        /// </summary>
+        private IContainer components = null;
+
+        /// <summary> 
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Component Designer generated code
+
+        /// <summary> 
+        /// Required method for Designer support - do not modify 
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            ComponentResourceManager resources = new ComponentResourceManager(typeof(SystemCurvePage));
+            DevExpress.XtraCharts.SwiftPlotDiagram swiftPlotDiagram1 = new DevExpress.XtraCharts.SwiftPlotDiagram();
+            DevExpress.XtraCharts.Series series1 = new DevExpress.XtraCharts.Series();
+            DevExpress.XtraCharts.SwiftPointSeriesView swiftPointSeriesView1 = new DevExpress.XtraCharts.SwiftPointSeriesView();
+            ribbonControl1 = new DevExpress.XtraBars.Ribbon.RibbonControl();
+            barBtnCalc = new DevExpress.XtraBars.BarButtonItem();
+            ribbonPage = new DevExpress.XtraBars.Ribbon.RibbonPage();
+            ribbonPageGroup1 = new DevExpress.XtraBars.Ribbon.RibbonPageGroup();
+            chartControl1 = new DevExpress.XtraCharts.ChartControl();
+            ((ISupportInitialize)ribbonControl1).BeginInit();
+            ((ISupportInitialize)chartControl1).BeginInit();
+            ((ISupportInitialize)swiftPlotDiagram1).BeginInit();
+            ((ISupportInitialize)series1).BeginInit();
+            ((ISupportInitialize)swiftPointSeriesView1).BeginInit();
+            SuspendLayout();
+            // 
+            // ribbonControl1
+            // 
+            ribbonControl1.DrawGroupsBorderMode = DefaultBoolean.False;
+            ribbonControl1.EmptyAreaImageOptions.ImagePadding = new Padding(34, 39, 34, 39);
+            ribbonControl1.ExpandCollapseItem.Id = 0;
+            ribbonControl1.ItemPanelStyle = DevExpress.XtraBars.Ribbon.RibbonItemPanelStyle.Classic;
+            ribbonControl1.Items.AddRange(new DevExpress.XtraBars.BarItem[] { ribbonControl1.ExpandCollapseItem, barBtnCalc });
+            ribbonControl1.Location = new Point(0, 0);
+            ribbonControl1.Margin = new Padding(3, 4, 3, 4);
+            ribbonControl1.MaxItemId = 40;
+            ribbonControl1.Name = "ribbonControl1";
+            ribbonControl1.OptionsMenuMinWidth = 377;
+            ribbonControl1.Pages.AddRange(new DevExpress.XtraBars.Ribbon.RibbonPage[] { ribbonPage });
+            ribbonControl1.ShowApplicationButton = DefaultBoolean.False;
+            ribbonControl1.ShowExpandCollapseButton = DefaultBoolean.False;
+            ribbonControl1.ShowPageHeadersMode = DevExpress.XtraBars.Ribbon.ShowPageHeadersMode.Hide;
+            ribbonControl1.Size = new Size(935, 128);
+            ribbonControl1.ToolbarLocation = DevExpress.XtraBars.Ribbon.RibbonQuickAccessToolbarLocation.Hidden;
+            // 
+            // barBtnCalc
+            // 
+            barBtnCalc.Caption = "璁$畻";
+            barBtnCalc.Id = 39;
+            barBtnCalc.ImageOptions.SvgImage = (DevExpress.Utils.Svg.SvgImage)resources.GetObject("barBtnCalc.ImageOptions.SvgImage");
+            barBtnCalc.Name = "barBtnCalc";
+            barBtnCalc.ItemClick += barBtnCalc_ItemClick;
+            // 
+            // ribbonPage
+            // 
+            ribbonPage.Groups.AddRange(new DevExpress.XtraBars.Ribbon.RibbonPageGroup[] { ribbonPageGroup1 });
+            ribbonPage.Name = "ribbonPage";
+            ribbonPage.Text = "鍩虹鎿嶄綔";
+            // 
+            // ribbonPageGroup1
+            // 
+            ribbonPageGroup1.ItemLinks.Add(barBtnCalc);
+            ribbonPageGroup1.Name = "ribbonPageGroup1";
+            ribbonPageGroup1.Text = "ribbonPageGroup1";
+            // 
+            // chartControl1
+            // 
+            swiftPlotDiagram1.AxisX.VisibleInPanesSerializable = "-1";
+            swiftPlotDiagram1.AxisY.VisibleInPanesSerializable = "-1";
+            chartControl1.Diagram = swiftPlotDiagram1;
+            chartControl1.Dock = DockStyle.Fill;
+            chartControl1.Legend.LegendID = -1;
+            chartControl1.Location = new Point(0, 128);
+            chartControl1.Name = "chartControl1";
+            series1.Name = "Series 1";
+            series1.SeriesID = 0;
+            series1.View = swiftPointSeriesView1;
+            chartControl1.SeriesSerializable = new DevExpress.XtraCharts.Series[]
+    {
+    series1
+    };
+            chartControl1.Size = new Size(935, 748);
+            chartControl1.TabIndex = 1;
+            // 
+            // SystemCurvePage
+            // 
+            Appearance.BackColor = SystemColors.Control;
+            Appearance.Options.UseBackColor = true;
+            AutoScaleDimensions = new SizeF(8F, 18F);
+            AutoScaleMode = AutoScaleMode.Font;
+            Controls.Add(chartControl1);
+            Controls.Add(ribbonControl1);
+            Margin = new Padding(3, 5, 3, 5);
+            Name = "SystemCurvePage";
+            Size = new Size(935, 876);
+            ((ISupportInitialize)ribbonControl1).EndInit();
+            ((ISupportInitialize)swiftPlotDiagram1).EndInit();
+            ((ISupportInitialize)swiftPointSeriesView1).EndInit();
+            ((ISupportInitialize)series1).EndInit();
+            ((ISupportInitialize)chartControl1).EndInit();
+            ResumeLayout(false);
+            PerformLayout();
+        }
+
+        #endregion
+        private DevExpress.XtraBars.Ribbon.RibbonControl ribbonControl1;
+        private DevExpress.XtraBars.Ribbon.RibbonPage ribbonPage;
+        private DevExpress.XtraBars.BarButtonItem barBtnCalc;
+        private DevExpress.XtraBars.Ribbon.RibbonPageGroup ribbonPageGroup1;
+        private DevExpress.XtraCharts.ChartControl chartControl1;
+    }
+}
diff --git a/WinFrmUI/PBS.WinFrmUI.Hydro/01-water-supply-system-curve/SystemCurvePage.cs b/WinFrmUI/PBS.WinFrmUI.Hydro/01-water-supply-system-curve/SystemCurvePage.cs
new file mode 100644
index 0000000..4adb924
--- /dev/null
+++ b/WinFrmUI/PBS.WinFrmUI.Hydro/01-water-supply-system-curve/SystemCurvePage.cs
@@ -0,0 +1,273 @@
+锘縰sing 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;
+                }
+
+                // 绗笁闃舵锛氳宸慨姝o紙纭繚鎬诲拰绮剧‘锛�
+                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("鎬绘渶灏忛渶姹傝秴杩囨渶澶ц瀹氬��");
+            }
+        }
+
+
+    }
+
+
+
+}
\ No newline at end of file
diff --git a/WinFrmUI/PBS.WinFrmUI.Hydro/01-water-supply-system-curve/SystemCurvePage.resx b/WinFrmUI/PBS.WinFrmUI.Hydro/01-water-supply-system-curve/SystemCurvePage.resx
new file mode 100644
index 0000000..7659e0e
--- /dev/null
+++ b/WinFrmUI/PBS.WinFrmUI.Hydro/01-water-supply-system-curve/SystemCurvePage.resx
@@ -0,0 +1,144 @@
+锘�<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!--
+    Microsoft ResX Schema
+
+    Version 2.0
+
+    The primary goals of this format is to allow a simple XML format
+    that is mostly human readable. The generation and parsing of the
+    various data types are done through the TypeConverter classes
+    associated with the data types.
+
+    Example:
+
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+
+    There are any number of "resheader" rows that contain simple
+    name/value pairs.
+
+    Each data row contains a name, and value. The row also contains a
+    type or mimetype. Type corresponds to a .NET class that support
+    text/value conversion through the TypeConverter architecture.
+    Classes that don't support this are serialized and stored with the
+    mimetype set.
+
+    The mimetype is used for serialized objects, and tells the
+    ResXResourceReader how to depersist the object. This is currently not
+    extensible. For a given mimetype the value must be set accordingly:
+
+    Note - application/x-microsoft.net.object.binary.base64 is the format
+    that the ResXResourceWriter will generate, however the reader can
+    read any of the formats listed below.
+
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <assembly alias="DevExpress.Data.v23.2" name="DevExpress.Data.v23.2, Culture=neutral, PublicKeyToken=b88d1754d700e49a" />
+  <data name="barBtnCalc.ImageOptions.SvgImage" type="DevExpress.Utils.Svg.SvgImage, DevExpress.Data.v23.2" mimetype="application/x-microsoft.net.object.bytearray.base64">
+    <value>
+        AAEAAAD/////AQAAAAAAAAAMAgAAAFlEZXZFeHByZXNzLkRhdGEudjIzLjIsIFZlcnNpb249MjMuMi40
+        LjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjg4ZDE3NTRkNzAwZTQ5YQUBAAAAHURl
+        dkV4cHJlc3MuVXRpbHMuU3ZnLlN2Z0ltYWdlAQAAAAREYXRhBwICAAAACQMAAAAPAwAAALMDAAAC77u/
+        PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz4NCjxzdmcgeD0iMHB4IiB5PSIwcHgi
+        IHZpZXdCb3g9IjAgMCAzMiAzMiIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv
+        MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWw6c3Bh
+        Y2U9InByZXNlcnZlIiBpZD0iTGF5ZXJfMSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAg
+        MzIgMzIiPg0KICA8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgoJLkJsdWV7ZmlsbDojMTE3N0Q3O30KCS5H
+        cmVlbntmaWxsOiMwMzlDMjM7fQoJLlllbGxvd3tmaWxsOiNGRkIxMTU7fQoJLkJsYWNre2ZpbGw6Izcy
+        NzI3Mjt9CgkuV2hpdGV7ZmlsbDojRkZGRkZGO30KCS5SZWR7ZmlsbDojRDExQzFDO30KCS5zdDB7b3Bh
+        Y2l0eTowLjc1O30KPC9zdHlsZT4NCiAgPGcgaWQ9IkNhbGN1bGF0b3IiPg0KICAgIDxwYXRoIGQ9Ik0y
+        OSwwSDE2djE0aDE0VjFDMzAsMC41LDI5LjUsMCwyOSwweiBNMjgsOEgxOFY2aDEwVjh6IiBjbGFzcz0i
+        QmxhY2siIC8+DQogICAgPHBhdGggZD0iTTAsMjljMCwwLjUsMC41LDEsMSwxaDEzVjE2SDBWMjl6IE0y
+        LjgsMjAuMmwxLjQtMS40TDcsMjEuNmwyLjgtMi44bDEuNCwxLjRMOC40LDIzbDIuOCwyLjhsLTEuNCwx
+        LjQgICBMNywyNC40bC0yLjgsMi44bC0xLjQtMS40TDUuNiwyM0wyLjgsMjAuMnoiIGNsYXNzPSJCbGFj
+        ayIgLz4NCiAgICA8cGF0aCBkPSJNMCwxdjEzaDE0VjBIMUMwLjUsMCwwLDAuNSwwLDF6IE0yLDZoNFYy
+        aDJ2NGg0djJIOHY0SDZWOEgyVjZ6IiBjbGFzcz0iQmxhY2siIC8+DQogICAgPHBhdGggZD0iTTE2LDE2
+        djE0aDEzYzAuNSwwLDEtMC41LDEtMVYxNkgxNnogTTI4LDI2SDE4di0yaDEwVjI2eiBNMjgsMjJIMTh2
+        LTJoMTBWMjJ6IiBjbGFzcz0iWWVsbG93IiAvPg0KICA8L2c+DQo8L3N2Zz4L
+</value>
+  </data>
+</root>
\ No newline at end of file
diff --git a/WinFrmUI/PBS.WinFrmUI.Hydro/PBS.WinFrmUI.Hydro.csproj b/WinFrmUI/PBS.WinFrmUI.Hydro/PBS.WinFrmUI.Hydro.csproj
index 1ec4945..fcd8755 100644
--- a/WinFrmUI/PBS.WinFrmUI.Hydro/PBS.WinFrmUI.Hydro.csproj
+++ b/WinFrmUI/PBS.WinFrmUI.Hydro/PBS.WinFrmUI.Hydro.csproj
@@ -19,7 +19,13 @@
   </ItemGroup>
 
   <ItemGroup>
+    <Compile Remove="01-water-supply-system-curve\SystemCurveCalcHelper - 澶嶅埗.cs" />
+    <Compile Remove="01-water-supply-system-curve\SystemCurveCalcHelper.cs" />
+  </ItemGroup>
+
+  <ItemGroup>
     <PackageReference Include="DevExpress.Win.Design" Version="23.2.4" />
+    <PackageReference Include="Yw.Epanet.Calcu.Core" Version="1.0.0" />
   </ItemGroup>
 
   <ItemGroup>
@@ -27,7 +33,18 @@
   </ItemGroup>
 
   <ItemGroup>
-    <Folder Include="Properties\" />
+    <Compile Update="Properties\Resources.Designer.cs">
+      <DesignTime>True</DesignTime>
+      <AutoGen>True</AutoGen>
+      <DependentUpon>Resources.resx</DependentUpon>
+    </Compile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <EmbeddedResource Update="Properties\Resources.resx">
+      <Generator>ResXFileCodeGenerator</Generator>
+      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+    </EmbeddedResource>
   </ItemGroup>
 
 </Project>
diff --git a/WinFrmUI/PBS.WinFrmUI.Hydro/PBS.WinFrmUI.Hydro.csproj.user b/WinFrmUI/PBS.WinFrmUI.Hydro/PBS.WinFrmUI.Hydro.csproj.user
new file mode 100644
index 0000000..b157eaf
--- /dev/null
+++ b/WinFrmUI/PBS.WinFrmUI.Hydro/PBS.WinFrmUI.Hydro.csproj.user
@@ -0,0 +1,9 @@
+锘�<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup />
+  <ItemGroup>
+    <Compile Update="01-water-supply-system-curve\SystemCurvePage.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/WinFrmUI/PBS.WinFrmUI.Hydro/Properties/Resources.Designer.cs b/WinFrmUI/PBS.WinFrmUI.Hydro/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..d8f2fcc
--- /dev/null
+++ b/WinFrmUI/PBS.WinFrmUI.Hydro/Properties/Resources.Designer.cs
@@ -0,0 +1,63 @@
+锘�//------------------------------------------------------------------------------
+// <auto-generated>
+//     姝や唬鐮佺敱宸ュ叿鐢熸垚銆�
+//     杩愯鏃剁増鏈�:4.0.30319.42000
+//
+//     瀵规鏂囦欢鐨勬洿鏀瑰彲鑳戒細瀵艰嚧涓嶆纭殑琛屼负锛屽苟涓斿鏋�
+//     閲嶆柊鐢熸垚浠g爜锛岃繖浜涙洿鏀瑰皢浼氫涪澶便��
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace PBS.WinFrmUI.Hydro.Properties {
+    using System;
+    
+    
+    /// <summary>
+    ///   涓�涓己绫诲瀷鐨勮祫婧愮被锛岀敤浜庢煡鎵炬湰鍦板寲鐨勫瓧绗︿覆绛夈��
+    /// </summary>
+    // 姝ょ被鏄敱 StronglyTypedResourceBuilder
+    // 绫婚�氳繃绫讳技浜� ResGen 鎴� Visual Studio 鐨勫伐鍏疯嚜鍔ㄧ敓鎴愮殑銆�
+    // 鑻ヨ娣诲姞鎴栫Щ闄ゆ垚鍛橈紝璇风紪杈� .ResX 鏂囦欢锛岀劧鍚庨噸鏂拌繍琛� ResGen
+    // (浠� /str 浣滀负鍛戒护閫夐」)锛屾垨閲嶆柊鐢熸垚 VS 椤圭洰銆�
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    internal class Resources {
+        
+        private static global::System.Resources.ResourceManager resourceMan;
+        
+        private static global::System.Globalization.CultureInfo resourceCulture;
+        
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Resources() {
+        }
+        
+        /// <summary>
+        ///   杩斿洖姝ょ被浣跨敤鐨勭紦瀛樼殑 ResourceManager 瀹炰緥銆�
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Resources.ResourceManager ResourceManager {
+            get {
+                if (object.ReferenceEquals(resourceMan, null)) {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PBS.WinFrmUI.Hydro.Properties.Resources", typeof(Resources).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+        
+        /// <summary>
+        ///   閲嶅啓褰撳墠绾跨▼鐨� CurrentUICulture 灞炴�э紝瀵�
+        ///   浣跨敤姝ゅ己绫诲瀷璧勬簮绫荤殑鎵�鏈夎祫婧愭煡鎵炬墽琛岄噸鍐欍��
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Globalization.CultureInfo Culture {
+            get {
+                return resourceCulture;
+            }
+            set {
+                resourceCulture = value;
+            }
+        }
+    }
+}
diff --git a/WinFrmUI/PBS.WinFrmUI.Hydro/Properties/Resources.resx b/WinFrmUI/PBS.WinFrmUI.Hydro/Properties/Resources.resx
new file mode 100644
index 0000000..1af7de1
--- /dev/null
+++ b/WinFrmUI/PBS.WinFrmUI.Hydro/Properties/Resources.resx
@@ -0,0 +1,120 @@
+锘�<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>
\ No newline at end of file

--
Gitblit v1.9.3