1
lixiaojun
2024-09-28 562f5485ca20eccca3c8a9c3ced8475d1019df26
Hydro/Yw.EPAnet.Calcu.Core/04-Inp/InpInteropHelper.cs
@@ -1,4 +1,8 @@
namespace Yw.EPAnet
using System.Text;
using System.Text.RegularExpressions;
//using Hydro.CommonBase;
namespace Yw.EPAnet
{
    /// <summary>
    /// Inp交互辅助类
@@ -9,11 +13,237 @@
        /// 转换至Inp字符串
        /// </summary>
        /// <returns></returns>
        public static string ToInpString(this Network rhs)
        public static string ToInpString(this Network net)
        {
            return default;
            string tempString = "";
            var tempPath = Path.Combine(Directory.GetCurrentDirectory(), @"template\template.inp");
            if (!File.Exists(tempPath))
            {
                throw new Exception("模板文件不存在," + tempPath);
            }
            tempString = File.ReadAllText(tempPath);
            StringBuilder statusStringBuilder = new StringBuilder();
            statusStringBuilder.AppendLine(";ID              \tStatus/Setting\r\n");
            StringBuilder emitterStringBuilder = new StringBuilder();
            emitterStringBuilder.AppendLine(";Junction        \tCoefficient");
            StringBuilder coorStringBuilder = new StringBuilder();
            coorStringBuilder.AppendLine(";Node               X-Coord              Y-Coord");
            Dictionary<string, string> dictExchange = new Dictionary<string, string>() {
                {"{junctions}","{0}" },
                {"{reservoirs}","{1}" },
                {"{tanks}","{2}" },
                {"{pipes}","{3}" },
                {"{valves}","{4}" },
                {"{pumps}","{5}" },
                {"{coor}","{6}" },
                {"{curve}","{7}" },
            };
            dictExchange.ToList().ForEach(m => tempString = tempString.Replace(m.Key, m.Value));
            StringBuilder junctionStringBuilder = new StringBuilder();
            junctionStringBuilder.AppendLine(";ID                 Elev           Demand         Pattern         Type");
            net.Junctions.ForEach(o =>
            {
                var pTemp = o.DemandPattern;
                if (string.IsNullOrEmpty(pTemp) || pTemp == ";" || pTemp == "_") pTemp = "";
                junctionStringBuilder.AppendLine($"{o.Id}\t{o.Elev}\t{o.Demand}\t{pTemp}\t;\t" + $"0\tJunction");
                coorStringBuilder.AppendLine(o.Id + "    " + o.Position.X + "    " + o.Position.Y);
            });
            net.Meters.ForEach(o =>
            {
                var pTemp = o.DemandPattern;
                if (string.IsNullOrEmpty(pTemp) || pTemp == ";" || pTemp == "_") pTemp = "";
                junctionStringBuilder.AppendLine($"{o.Id}\t{o.Elev}\t{o.Demand}\t{pTemp}\t;\t" + $"0\tMeters");
                coorStringBuilder.AppendLine(o.Id + "    " + o.Position.X + "    " + o.Position.Y);
            });
            net.Nozzles.ForEach(o =>
            {
                var pTemp = o.DemandPattern;
                if (string.IsNullOrEmpty(pTemp) || pTemp == ";" || pTemp == "_") pTemp = "";
                junctionStringBuilder.AppendLine($"{o.Id}\t{o.Elev}\t{o.Demand}\t{pTemp}\t;\t" + $"0\tNozzle\t{o.Coefficient}");
                emitterStringBuilder.AppendLine(o.Id + "    " + o.Coefficient);
                coorStringBuilder.AppendLine(o.Id + "    " + o.Position.X + "    " + o.Position.Y);
            });
            string junctionString = junctionStringBuilder.ToString();
            StringBuilder reservoirStringBuilder = new StringBuilder();
            reservoirStringBuilder.AppendLine(";ID                 Head           Pattern ");
            net.Reservoirs.ForEach(o =>
            {
                reservoirStringBuilder.AppendLine($"{o.Id}\t{o.Head}\t{o.HeadPattern}\t;\t" + $"0\t{o.PoolElev}");
                coorStringBuilder.AppendLine(o.Id + "    " + o.Position.X + "    " + o.Position.Y);
            });
            string reserverString = reservoirStringBuilder.ToString();
            StringBuilder tankStringBuilder = new StringBuilder();
            tankStringBuilder.AppendLine(";ID                 Elevation      InitLevel      MinLevel       MaxLevel       Diameter       MinVol         VolCurve           Overflow");
            net.Tanks.ForEach(o =>
            {
                // tankStringBuilder.AppendLine($"{o.Id}\t{o.PoolElev}\t{o.InitLevel}\t{o.MinLevel}\t{o.MaxLevel}\t{o.Diameter}\t{o.MinVol}\t{o.VolCurve}\t{o.Overflow}\t;\t");// + $"0");
                tankStringBuilder.AppendLine($"{o.Id}\t{o.PoolElev}\t{o.InitLevel}\t{o.MinLevel}\t{o.MaxLevel}\t{o.Diameter}\t{o.MinVol}\t{o.VolCurve}\t;\t");// + $"0");
                coorStringBuilder.AppendLine(o.Id + "    " + o.Position.X + "    " + o.Position.Y);
            });
            string tankString = tankStringBuilder.ToString();
            StringBuilder pipeStringBuilder = new StringBuilder();
            pipeStringBuilder.AppendLine(";ID                 Node1              Node2              Length         Diameter       Roughness      MinorLoss      Status");
            net.Pipes.ForEach(o =>
            {
                if (o.Roughness == 0) o.Roughness = 110;
                string statusString = o.LinkStatus == PipeStatus.Closed ? "CLOSED" : "";
                pipeStringBuilder.AppendLine($"{o.Id}\t{o.StartNode.Id}\t{o.EndNode.Id}\t{o.Length}\t{o.Diameter}\t{o.Roughness}\t{o.MinorLoss}\t{statusString}\t;\t");// + $"{p.Level}");
                if (o.LinkStatus != PipeStatus.Open)
                {
                    statusStringBuilder.AppendLine(o.Id + "\t" + statusString);
                }
            });
            string pipeString = pipeStringBuilder.ToString();
            StringBuilder valveStringBuilder = new StringBuilder();
            valveStringBuilder.AppendLine(";ID                 Node1              Node2              Diameter       Type   Setting        MinorLoss  ");
            net.Valves.ForEach(o =>
            {
                valveStringBuilder.AppendLine($"{o.Id}\t{o.StartNode.Id}\t{o.EndNode.Id}\t{o.Diameter:F4}\t{o.ValveType}\t{o.ValveSetting}\t{o.MinorLoss:F4}\t;\t");// + $"0");
                if (!string.IsNullOrEmpty(o.LinkStatus))
                    statusStringBuilder.AppendLine(o.Id + "\t" + o.LinkStatus);
            });
            string valveString = valveStringBuilder.ToString();
            StringBuilder pumpStringBuilder = new StringBuilder();
            pumpStringBuilder.AppendLine(";ID                 Node1              Node2              Parameters  ");
            net.Pumps.ForEach(o =>
            {
                pumpStringBuilder.AppendLine($"{o.Id}\t{o.StartNode.Id}\t{o.EndNode.Id}\tHead\t{o.CurveQH}\tSPEED\t{o.SpeedRatio}\t;\t");// + $"0");
                if (!string.IsNullOrEmpty(o.LinkStatus))
                    statusStringBuilder.AppendLine(o.Id + "\t" + o.LinkStatus);
            });
            string pumpString = pumpStringBuilder.ToString();
            StringBuilder curveStringBuilder = new StringBuilder();
            curveStringBuilder.AppendLine(@";ID                 X-Value        Y-Value
                                            ;HEADLOSS:
                                             GPVDefault         0              0
                                             GPVDefault         100            0
                                            ;PUMP:
                                             PumpDefault        0              45.38
                                             PumpDefault        83.33333333    45.25
                                             PumpDefault        111.1111111    45.12
                                             PumpDefault        138.8888889    44.96
                                             PumpDefault        166.6666667    44.76
                                             PumpDefault        194.4444444    44.52
                                             PumpDefault        222.2222222    44.24
                                             PumpDefault        250            43.92
                                             PumpDefault        277.7777778    43.56
                                             PumpDefault        305.5555556    43.17
                                             PumpDefault        333.3333333    42.73
                                             PumpDefault        361.1111111    42.25
                                             PumpDefault        388.8888889    41.74
                                             PumpDefault        416.6666667    41.18
                                             PumpDefault        444.4444444    40.58
                                             PumpDefault        472.2222222    39.95
                                             PumpDefault        500            39.28
                                             PumpDefault        527.7777778    38.56
                                             PumpDefault        555.5555556    37.81
                                             PumpDefault        583.3333333    37.02
                                             PumpDefault        611.1111111    36.19
                                             PumpDefault        638.8888889    35.32
                                             PumpDefault        666.6666667    34.41
                                             PumpDefault        694.4444444    33.46
                                             PumpDefault        722.2222222    32.47
                                             PumpDefault        750            31.44
                                             PumpDefault        777.7777778    30.37
                                             PumpDefault        805.5555556    29.27    ");
            net.Curves.ForEach(o =>
            {
                var curvePtList = o.CurveData?.OrderBy(x => x.X).ToList();
                foreach (var curvePt in curvePtList)
                {
                    curveStringBuilder.AppendLine($"{o.Id}  {curvePt.X} {curvePt.Y}");
                }
                //curveStringBuilder.AppendLine(o.ToString());
            });
            string curveString = curveStringBuilder.ToString();
            string coorString = coorStringBuilder.ToString();
            string output = "";
            string emitterString = emitterStringBuilder.ToString();
            string statusString = statusStringBuilder.ToString();
            output = tempString;
            output = ReplaceContent(output, "JUNCTIONS", junctionString);
            output = ReplaceContent(output, "RESERVOIRS", reserverString);
            output = ReplaceContent(output, "TANKS", tankString);
            output = ReplaceContent(output, "PIPES", pipeString);
            output = ReplaceContent(output, "VALVES", valveString);
            output = ReplaceContent(output, "PUMPS", pumpString);
            output = ReplaceContent(output, "CURVES", curveString);
            output = ReplaceContent(output, "COORDINATES", coorString);
            output = ReplaceContent(output, "EMITTERS", emitterString);
            output = ReplaceContent(output, "STATUS", statusString);
            return output;
        }
        private static string ReplaceContent(string text, string content, string replaceString)
        {
            string str = replaceString;
            string replacedText = ReplaceCoordinatesSection(text, content, str);
            return replacedText;
            //Console.WriteLine(replacedText);
        }
        public static string ReplaceCoordinatesSection(string text, string content, string str)
        {
            string pattern = $@"(\[{content}\]).*?(\[|$)";
            string replacedText = Regex.Replace(text, pattern, match =>
            {
                string section = match.Groups[2].Value.Trim();
                if (!string.IsNullOrEmpty(section))
                {
                    return $"{match.Groups[1].Value}\n{str}\n[";
                }
                else
                {
                    return $"{match.Groups[1].Value}\n{str}\n[";
                }
            }, RegexOptions.Singleline);
            return replacedText;
        }
        /// <summary>
        /// 从Inp字符串中解析
        /// </summary>
@@ -21,7 +251,277 @@
        /// <returns></returns>
        public static Network FromInpString(string inpString)
        {
            return default;
            string InpPath = inpString;
            var net = new Network();
            if (InpPath == null || !File.Exists(InpPath)) return null;
            List<InpCoor> points = new List<InpCoor>();
            StreamReader sr = new StreamReader(InpPath);
            //try
            {
                string line;
                string section = "";
                while ((line = sr.ReadLine()) != null)
                {
                    if (line.Trim().StartsWith("["))
                    {
                        section = line.TrimStart('[').TrimEnd(']');
                    }
                    else
                    {
                        string s = line.Trim('\t').Trim(' ');
                        if (s.Length == 0 || s[0] == ';') continue;
                        line = line.Replace("\t\t", "\t_\t").Replace("\t \t", "\t_\t");
                        InpParts parts = new InpParts(line.Split(new char[] { '\t', ' ', ';' }, StringSplitOptions.RemoveEmptyEntries));
                        switch (section)
                        {
                            case "JUNCTIONS":
                                {
                                    var ID = parts[0];
                                    float elev;
                                    float.TryParse(parts[1], out elev);
                                    var Elev = elev;
                                    float demand;
                                    float.TryParse(parts[2], out demand);
                                    var Demand = demand;
                                    var PatternID = parts[3];
                                    int level;
                                    int.TryParse(parts[6], out level);
                                    var Level = level;
                                    if (parts[5] == "Meter")
                                    {
                                        net.Meters.Add(new Meter()
                                        {
                                            Id = ID,
                                            Elev = Elev,
                                            Demand = Demand,
                                            DemandPattern = PatternID,
                                        });
                                    }
                                    else if (parts[5] == "Nozzle")
                                    {
                                        net.Nozzles.Add(new Nozzle()
                                        {
                                            Id = ID,
                                            Elev = Elev,
                                            Demand = Demand,
                                            DemandPattern = PatternID,
                                        });
                                    }
                                    else
                                    {
                                        net.Junctions.Add(new Junction()
                                        {
                                            Id = ID,
                                            Elev = Elev,
                                            Demand = Demand,
                                            DemandPattern = PatternID,
                                        });
                                    }
                                }
                                break;
                            case "RESERVOIRS":
                                {
                                    var r = new Reservoir();
                                    r.Id = parts[0];
                                    float head;
                                    if (float.TryParse(parts[1], out head))
                                        r.Head = head;
                                    r.HeadPattern = parts.Length > 2 ? parts[2] : "";
                                    int level;
                                    //if (int.TryParse(parts[3], out level))
                                    //    r.Level = level;
                                    net.Reservoirs.Add(r);
                                }
                                break;
                            case "TANKS":
                                {
                                    //TankModel tank = new TankModel(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5], parts[6], parts[7], parts[8]);
                                    float initLevel = 0;
                                    float.TryParse(parts[2], out initLevel);
                                    float minLevel = 0;
                                    float.TryParse(parts[3], out minLevel);
                                    float maxLevel = 0;
                                    float.TryParse(parts[4], out maxLevel);
                                    float diamter = 0;
                                    float.TryParse(parts[5], out diamter);
                                    float minVol = 0;
                                    float.TryParse(parts[6], out minVol);
                                    var tank = new Tank()
                                    {
                                        Id = parts[0],
                                        PoolElev = float.Parse(parts[1]),
                                        InitLevel = initLevel,
                                        MinLevel = minLevel,
                                        MaxLevel = maxLevel,
                                        Diameter = diamter,
                                        MinVol = minVol,
                                        VolCurve = "",
                                    };
                                    //int level;
                                    //if (int.TryParse(parts[9], out level))
                                    //    tank.Level = level;
                                    net.Tanks.Add(tank);
                                }
                                break;
                            case "PIPES":
                                {
                                    InpPipe p = new InpPipe();
                                    p.Id = parts[0];
                                    p.Node1 = parts[1];
                                    p.Node2 = parts[2];
                                    float length;
                                    if (float.TryParse(parts[3], out length))
                                        p.Length = length;
                                    float diameter;
                                    if (float.TryParse(parts[4], out diameter))
                                        p.Diameter = diameter;
                                    float roughness;
                                    if (float.TryParse(parts[5], out roughness))
                                        p.Roughness = roughness;
                                    float minorLoss;
                                    if (float.TryParse(parts[6], out minorLoss))
                                        p.MinorLoss = minorLoss;
                                    p.LinkStatus = parts.Length > 7 ? PipeStatus.Closed : PipeStatus.Open;
                                    //int level;
                                    //if (int.TryParse(parts[8], out level))
                                    //    p.Level = level;
                                    net.Pipes.Add(p);
                                }
                                break;
                            case "VALVES":
                                {
                                    InpValve valve = new InpValve();
                                    valve.Id = parts[0];
                                    // 取出Node1和Node2中的字母部分,例如“S201326593”被取出为“201326593”
                                    valve.Node1 = parts[1]; // Regex.Replace(parts[1], "[^0-9]", "");
                                    valve.Node2 = parts[2]; // Regex.Replace(parts[2], "[^0-9]", "");
                                    float diameter;
                                    if (float.TryParse(parts[3], out diameter))
                                        valve.Diameter = diameter;
                                    valve.ValveType = parts[4];
                                    valve.ValveSetting = parts[5];
                                    float minorLoss;
                                    if (float.TryParse(parts[6], out minorLoss))
                                        valve.MinorLoss = minorLoss;
                                    net.Valves.Add(valve);
                                }
                                break;
                            case "COORDINATES":
                                {
                                    string id = parts[0];
                                    double x;
                                    double y;
                                    if (double.TryParse(parts[1], out x) && double.TryParse(parts[2], out y))
                                    {
                                        points.Add(new InpCoor(id, new Position2d(x, y)));
                                    }
                                }
                                break;
                        }
                    }
                }
                sr.Close();
                #region 优化方案
                int k1 = 0;
                int k2 = 0;
                var Nodes = net.GetAllNodes();
                var Links = net.GetAllLinks();
                Nodes.Sort((a, b) => string.Compare(a.Id, b.Id));
                points.Sort((a, b) => string.Compare(a.Id, b.Id));
                k1 = 0;
                k2 = 0;
                while (k1 < Nodes.Count)
                {
                    var J = Nodes[k1];
                    var coor = points[k2];
                    while (J.Id != coor.Id && k2 < points.Count)
                    {
                        k2++;
                        if (k2 < points.Count) coor = points[k2];
                    }
                    if (k2 == points.Count)
                    {
                        break;
                        //throw new Exception($"未找到Node[{J.Id}]的坐标");
                    }
                    J.Position = new Position2d();
                    J.Position.X = coor.Position.X;
                    J.Position.Y = coor.Position.Y;
                    k1++;
                }
                #endregion
                //建立点线关系链表StartNode,先将管线以Node1(节点1的ID)排序,再将Nodes按ID排序,建立两个游标k1、k2,正向一次循环,建立链表关系
                //时间复杂度 O(n)
                Links.Sort((a, b) => string.Compare(((IInpParser)a).Node1, ((IInpParser)b).Node1));
                k1 = 0;
                k2 = 0;
                while (k2 < Links.Count)
                {
                    var p = Links[k2];
                    var J = Nodes[k1];
                    while (J.Id != ((IInpParser)p).Node1 && k1 < Nodes.Count)
                    {
                        k1++;
                        if (k1 < Nodes.Count) J = Nodes[k1];
                    }
                    if (k1 == Nodes.Count)
                    {
                        break;
                        //throw new Exception($"未找到Link[{p.Id}]的起始节点[{((IInpParser)p).Node1}]");
                    }
                    p.StartNode = J;
                    if (J.Links == null) J.Links = new List<ILink>();
                    J.Links.Add(p);
                    k2++;
                }
                //建立点线关系链表StartNode,先将管线以Node2(节点1的ID)排序,再将Nodes按ID排序,建立两个游标k1、k2,正向一次循环,建立链表关系
                //时间复杂度 O(n)
                Links.Sort((a, b) => string.Compare(((IInpParser)a).Node2, ((IInpParser)b).Node2));
                k1 = 0;
                k2 = 0;
                while (k2 < Links.Count)
                {
                    var p = Links[k2];
                    var J = Nodes[k1];
                    while (J.Id != ((IInpParser)p).Node2 && k1 < Nodes.Count)
                    {
                        k1++;
                        if (k1 < Nodes.Count) J = Nodes[k1];
                    }
                    if (k1 == Nodes.Count)
                    {
                        break;
                        //throw new Exception($"未找到Link[{p.Id}]的终止节点[{((IInpParser)p).Node2}]");
                    }
                    p.EndNode = J;
                    if (J.Links == null) J.Links = new List<ILink>();
                    J.Links.Add(p);
                    k2++;
                }
                return net;
            }
        }
    }