using Hydro; using MathNet.Numerics; using MathNet.Numerics.LinearAlgebra.Double; using Newtonsoft.Json; using System.ComponentModel; using System.Data; using System.IO; using System.Text; namespace PBS.WinFrmUI.Hydro { public enum 二供分区Type { 加压供水, 屋顶水箱, 市政直供 } [Serializable] public class BuildDataset { public BuildDataset(string name) { Name = name; } public BuildDataset() { } public void Clear() { if (this.Data != null) { Data.Clear(); } this.IsFitted = false; } public string Name { get; set; } private List _Data = new List(); public List Data { get { return _Data; } set { _Data = value; IsFitted = false; } } //= new List(); public int degree { get; set; } = 2; public List ForumParams = null; [JsonIgnore] [NonSerialized] public DenseVector coefficients = null; // 存储多项式系数 public double ErrNum { get { return -1; } } private int stepNum { get { return 100; } } private double step { get { return (range_X.Max - range_X.Min) / stepNum; } } /// /// 不需要读取 /// public string Legend { get { return "Legend1"; } } public void CurveFit(Range rangeX = null) { if (!HasData) { IsFitted = false; return; } if (rangeX != null) range_X = rangeX; coefficients = Fit.Polynomial(Data.Select(p => (double)p.X).ToArray(), Data.Select(p => (double)p.Y).ToArray(), degree); if (range_X == null) { range_X = new Range(9999999, -9999999); Data.ForEach(p => { if (range_X.Min > p.X) range_X.Min = p.X; if (range_X.Max < p.X) range_X.Max = p.X; }); } IsFitted = true; } public double Evaluate(double x) { if (!IsFitted) return ErrNum; // 计算多项式在点 x 处的取值 double y = 0; for (int i = 0; i < coefficients.Count; i++) { y += coefficients[i] * Math.Pow(x, i); } return y; } public double Evaluate_Solve(double y) { if (!IsFitted) return ErrNum; if (degree == 2) // 多项式次数 { if (!is_Yvalue_validate(y)) return ErrNum; double a = coefficients[degree]; // 二次项系数 double b = coefficients[degree - 1]; // 一次项系数 double c = coefficients[0] - y; // 常数项系数减去给定的 y 值 // 求解二次方程 ax^2 + bx + c = 0 double delta = b * b - 4 * a * c; double x1 = (-b + Math.Sqrt(delta)) / (2 * a); double x2 = (-b - Math.Sqrt(delta)) / (2 * a); // 取两个解中符合实际情况的那个(可以根据具体应用场景来确定) double x = (x2 >= x1) ? x2 : x1; return x; } else { return ErrNum; } } public double YMax { get { if (!IsFitted) return ErrNum; double a = coefficients[degree]; double b = coefficients[degree - 1]; double c = coefficients[0]; double delta = b * b - 4 * a * c; double minExtremePoint = -b / (2 * a); // 计算导函数的零点 double maxValue = 0; if (a < 0) maxValue = -delta / (4 * a) + c; else maxValue = a * minExtremePoint * minExtremePoint + b * minExtremePoint + c; // 计算最小值 return maxValue; } } public double YdataMax { get { double max = -99999; foreach (var p in Data) { if (max < p.Y) max = p.Y; } return max; } } public bool is_Yvalue_validate(double y) { if (!IsFitted) return false; double a = coefficients[degree]; if (a < 0) return y <= YMax; else return y >= YMax; } /// /// X显示的范围 /// public Range range_X; /// /// Y显示的范围 /// public Range range_Y; public bool HasData { get { return Data.Count >= 3; } } [JsonIgnore] [NonSerialized] public bool IsFitted = false; [JsonIgnore] [NonSerialized] private List _FittedCurve = null; public List FittedCurve { get { if (_FittedCurve == null && range_X != null && coefficients != null) { /* var curvehelper = new CurveFitHelper(Data, degree); coefficients = curvehelper.coefficients; return curvehelper.GetFitCurve(stepNum);*/ List doubles = new List(); for (double x = range_X.Min; x <= range_X.Max; x += step) { double y = Evaluate(x); if (y == double.NaN) y = 0; //chart.Series[1].Points.AddXY(x, y); doubles.Add(new PointF((float)x, (float)y)); } _FittedCurve = doubles; return doubles; } return _FittedCurve; } set { _FittedCurve = value; } } public List FittedCurvebyRange(Range range) { List doubles = new List(); if (range == null) { range = new Range(); range.Min = range_X.Min; range.Max = range_X.Max; } var step = (range.Max - range.Min) / stepNum; for (double x = range.Min; x <= range.Max; x += step) { double y = Evaluate(x); //chart.Series[1].Points.AddXY(x, y); doubles.Add(new PointF((float)x, (float)y)); } return doubles; } } [Serializable] public class Range { public Range() { } public Range(double Min, double Max) { this.Min = Min; this.Max = Max; } public double Max; public double Min; public double Len { get { return Max - Min; } } public static Range Union(Range a, Range b) { if (a == null) return b; if (b == null) return a; return new Range(a.Min < b.Min ? a.Min : b.Min, a.Max > b.Max ? a.Max : b.Max); } public bool isValid { get { return Min < Max; } } } public class UDemand { public string Name { get; set; } public Range Range { get; set; } public string picUrl { get; set; } } [Serializable] public class Build { public Build() { Datasets = new Dictionary() { {"流量压降曲线",new BuildDataset("流量压降曲线") }, {"流量压降上限",new BuildDataset("流量压降上限") }, {"流量压降下限",new BuildDataset("流量压降下限") }, {"流量压降平均",new BuildDataset("流量压降平均") }, }; } public string ID { get; set; } [Category("1、基本信息")] [Description("名称")] [DisplayName("名称")] [Browsable(true)] public string Name { get; set; } [Category("1、基本信息")] [Description("二供供水的类型")] [DisplayName("二供类型")] [Browsable(true)] public 二供分区Type Type { get; set; } [Browsable(false)] public Dictionary Datasets { get; set; } [NonSerialized] [JsonIgnore] public Munity factory = null; public string factoryName = ""; [Category("2、计算参数")] [Description("楼层高度")] [DisplayName("峰值流量(L/s)")] [Browsable(false)] public double MaxDemand { get; set; } = 15; [Category("1、基本信息")] [Description("楼层高度")] [DisplayName("每层高度")] [Browsable(false)] public double 层高 { get; set; } = 3.5; [Category("2、计算参数")] [Description("最不利点")] [DisplayName("用户压力需求(m)")] [Browsable(true)] public int 用户压力需求 { get; set; } = 8; [Category("1、基本信息")] [Description("楼层数量")] [DisplayName("楼层数")] [Browsable(false)] public double 层数 { get; set; } = 5; [Category("1、基本信息")] [Description("每层户数")] [DisplayName("每层户数")] [Browsable(false)] public double 每层户数 { get; set; } = 4; [Category("1、基本信息")] [Description("用户总数")] [DisplayName("用户总数")] [Browsable(false)] public double 用户总数 { get { return 层数 * 每层户数 * 用户压力需求; } } [Category("2、计算参数")] [Description("用户总数")] [DisplayName("系统流量(m³/h)")] [Browsable(true)] public double 系统最大流量 { get; set; } = 5; [Browsable(false)] private string _templateID = null; public Build Copy() { Build p = new Build(); p.ID = ID; p.Name = Name; p.MaxDemand = MaxDemand; p.层高 = 层高; p.层数 = 层数; p.每层户数 = 每层户数; p.系统最大流量 = 系统最大流量; p.Type = Type; p.factory = factory; foreach (var pair in Datasets) { List list = new List(); pair.Value.Data.ForEach(m => list.Add(m)); p.Datasets[pair.Key].Data = list; Range rangeDefault = new Range(double.MaxValue, double.MinValue); p.Datasets[pair.Key].range_X = Range.Union(rangeDefault, pair.Value.range_X); p.Datasets[pair.Key].range_Y = Range.Union(rangeDefault, pair.Value.range_Y); } p.CurveFit(); return p; } [Browsable(false)] public string templateID { get { return _templateID; } set { _templateID = value; template = TemplateList.GetTemplate(_templateID); } } public Template template { get; private set; } = null; public void CurveFit(bool is拟合 = true) { foreach (var data in Datasets) { if (data.Value.HasData) data.Value.CurveFit(); } } } public class Munity : Build { //public string Name { get; set; } public int PlaceType { get; set; } public List Pumps { get; set; } public void CurveFit() { foreach (var p in Pumps) { p.CurveFit(); } } } public class MunityList { public List Factories { get; set; } public MunityList() { Factories = new List(); } public Munity AddFactory(string name, int PlaceType) { Munity item = new Munity { Name = name, PlaceType = PlaceType, Pumps = new List() }; Factories.Add(item); return item; } public Build AddPump(Munity factory, string name, 二供分区Type type) { Build pump = new Build { Name = name, Type = type, factoryName = factory.Name }; pump.factory = factory; factory.Pumps.Add(pump); return pump; } public void RemoveFactory(Munity factory) { Factories.Remove(factory); } //private string _filePath = "data.txt"; //private string _bakPath = "bak\\"; private string _filePath = null;// "data.txt"; private string _bakPath = Path.Combine(Directory.GetCurrentDirectory(), "bak\\"); private string _fileDirectory = Path.Combine(Directory.GetCurrentDirectory(), "sav\\"); //public FactoryListFileManager(string filePath) //{ // _filePath = filePath; //} public string Save(string filePath) { if (filePath == null) { using (SaveFileDialog ofd = new SaveFileDialog()) { ofd.InitialDirectory = _fileDirectory; ofd.Filter = "txt|*.txt|All|*.*"; var result = ofd.ShowDialog(); if (result == DialogResult.OK) _filePath = ofd.FileName; else return null; } } else { _filePath = filePath; } if (File.Exists(_filePath)) { FileInfo fi = new FileInfo(_filePath); if (!Directory.Exists(_bakPath)) Directory.CreateDirectory(_bakPath); string bakName = Path.Combine(_bakPath, $"{fi.Name}_bak_{fi.LastWriteTime.ToString("yyyy_MM_dd_HH_mm_ss")}.txt"); File.Copy(_filePath, bakName, true); } var sb = new StringBuilder(); //sb.Append( JsonConvert.SerializeObject(Factories)); //2023年7月1日 放弃文本化输出,采用json输出 foreach (var factory in Factories) { // 写入工厂信息 sb.AppendLine($"Factory,{factory.PlaceType},{factory.Name},{factory.templateID}"); foreach (var build in factory.Pumps) { // 写入水泵信息 sb.AppendLine($"Pump,{build.Type},{build.Name},{build.层高},{build.每层户数},{build.系统最大流量},{build.层数},{build.templateID}"); foreach (var dataset in build.Datasets) { // 写入数据集信息 sb.AppendLine($"Dataset,{dataset.Value.Name}"); if (dataset.Value.range_X != null) sb.AppendLine($"Dataset_Range_X,{dataset.Value.range_X.Min},{dataset.Value.range_X.Max}"); if (dataset.Value.range_Y != null) sb.AppendLine($"Dataset_Range_Y,{dataset.Value.range_Y.Min},{dataset.Value.range_Y.Max}"); if (dataset.Value.Data != null) foreach (var point in dataset.Value.Data) { // 写入数据点信息 sb.AppendLine($"{point.X},{point.Y}"); } } } } // 将数据写入文件 File.WriteAllText(_filePath, sb.ToString()); return _filePath; } public string Load(string fileName) { //var factoryList = new FactoryList(); Factories.Clear(); if (!Directory.Exists(_fileDirectory)) Directory.CreateDirectory(_fileDirectory); if (fileName == null) { using (OpenFileDialog ofd = new OpenFileDialog()) { ofd.InitialDirectory = _fileDirectory; ofd.Filter = "txt|*.txt|All|*.*"; var result = ofd.ShowDialog(); if (result == DialogResult.OK) _filePath = ofd.FileName; else return null; } } else { _filePath = fileName; } //var factoryList = new FactoryList(); if (!File.Exists(_filePath)) { return null; } Factories.Clear(); var currentFactory = default(Munity); var currentPump = default(Build); var currentDataset = default(BuildDataset); //var txt = File.ReadAllText(_filePath); //Factories = JsonConvert.DeserializeObject>(txt); //Factories.ToList().ForEach(factory => //{ // factory.Pumps.ForEach(pump => { pump.factory = factory; }); //}); foreach (var line in File.ReadAllLines(_filePath)) { var fields = line.Split(','); switch (fields[0]) { case "Factory": // 读取工厂信息 var factoryType = (ePlaceType)Enum.Parse(typeof(int), fields[1]); var factoryName = fields[2]; currentFactory = new Munity { Name = factoryName, PlaceType = (int)factoryType, Pumps = new List(), templateID = fields.Length > 3 ? fields[3] : null }; this.Factories.Add(currentFactory); currentPump = null; currentDataset = null; break; case "Pump": // 读取水泵信息 var pumpType = (二供分区Type)Enum.Parse(typeof(二供分区Type), fields[1]); var pumpName = fields[2]; currentPump = new Build { Name = pumpName, Type = pumpType, factoryName = currentFactory.Name, factory = currentFactory, 层高 = double.Parse(fields[3]), 每层户数 = double.Parse(fields[4]), 系统最大流量 = double.Parse(fields[5]), 层数 = fields.Length >= 7 ? double.Parse(fields[6]) : 75, templateID = fields.Length >= 8 ? fields[7] : null }; currentFactory.Pumps.Add(currentPump); currentDataset = null; break; case "Dataset": // 读取数据集信息 var datasetName = fields[1]; currentDataset = new BuildDataset { Name = datasetName, Data = new List() }; currentPump.Datasets[currentDataset.Name] = currentDataset; break; case "Dataset_Range_X": { double d1 = 0; double d2 = 0; if (double.TryParse(fields[1], out d1) && double.TryParse(fields[2], out d2)) { currentDataset.range_X = new Range(d1, d2); } break; } case "Dataset_Range_Y": { double d1 = 0; double d2 = 0; if (double.TryParse(fields[1], out d1) && double.TryParse(fields[2], out d2)) { currentDataset.range_Y = new Range(d1, d2); } break; } default: // 读取数据点信息 var x = float.Parse(fields[0]); var y = float.Parse(fields[1]); currentDataset.Data.Add(new PointF(x, y)); break; } } CurveFit(); //return factoryList; return _filePath; } public void CurveFit() { foreach (var f in Factories) { f.CurveFit(); } } } }