cloudflight
2024-11-23 e5bfcecde9a5c696b3119ae29a6b7f2eb993cb82
Hydro/Yw.EPAnet.Calcu.Core/03-calcu/NetworkPathAnalyseExtensions.cs
@@ -9,181 +9,9 @@
    /// </summary>
    public static class NetworkPathAnalyseExtensions
    {
        public static List<ChartNode> GetChartNodeByPathLinks(this Network network, List<ILink> links)
        {
            double length = 0;
            ChartNode nodeEnd = new ChartNode();
            List<ChartNode> chartNodes = new List<ChartNode>();
            for (int i = 0; i < links.Count; i++)
            {
                var link = links[i];
                var node = link.Flow > 0 ? link.StartNode : link.EndNode;
                var Cnode = new ChartNode()
                {
                    Id = node.Id,
                    StartHead = node.Head,
                    EndHead = node.Head,
                    Elev = node.Elev
                };
                chartNodes.Add(Cnode);
                var nodeEnd0 = link.Flow > 0 ? link.EndNode : link.StartNode;
                nodeEnd.Id = nodeEnd0.Id;
                nodeEnd.Head = nodeEnd.StartHead = nodeEnd.EndHead = nodeEnd0.Head;
                nodeEnd.Elev = nodeEnd0.Elev;
                if (link is Pipe p)
                    length += p.Length;
            }
            chartNodes.Add(nodeEnd);
            for (int i=0;i<links.Count;i++)
            {
                var link = links[i];
                Pipe p=link as Pipe;
                if (p != null)
                {
                    //根据p.diameter和p.flow计算流速
                    double velocity = p.Flow / (Math.PI * Math.Pow(p.Diameter / 2, 2));
                    //根据流速计算局部水头损失
                    double minorloss1 = p.StartNodeMinorlossCoff* Math.Pow(velocity, 2) / 2 / 9.81;
                    double minorloss2 = p.EndNodeMinorlossCoff * Math.Pow(velocity, 2) / 2 / 9.81;
                    if (i < links.Count - 1)
                    {
                        chartNodes[i].EndHead = chartNodes[i].Head - minorloss1;
                        chartNodes[i + 1].StartHead = chartNodes[i].EndHead - minorloss2;
                    }
                    else
                    {
                        chartNodes[i].EndHead = chartNodes[i].Head - minorloss1;
                    }
                }
            }
            return chartNodes;
        }
        /// <summary>
        /// 分析下游主要供水路径
        /// </summary>
        public static List<ILink> AnalyzeDownstreamPath(this Network network, Junction startJunc)
        {
            var visitedNodes = new HashSet<INode>();
            var maxlink = startJunc.NextLinks.OrderByDescending(o => Math.Abs(o.Flow)).ToList()[0];
            return  network.TraversePipeNetworkALL(maxlink, visitedNodes, 1, true);
        }
        /// <summary>
        /// 分析上游主要供水路径
        /// </summary>
        /// <param name="network"></param>
        /// <param name="startJunc"></param>
        /// <returns></returns>
        public static List<ILink> AnalyzeUpstreamPath(this Network network, Junction startJunc)
        {
            var visitedNodes = new HashSet<INode>();
            var maxlink = startJunc.NextLinks.OrderByDescending(o => Math.Abs(o.Flow)).ToList()[0];
            return network.TraversePipeNetworkALL(maxlink, visitedNodes, -1, true);
        }
        /// <summary>
        /// 宽度搜索遍历管网
        /// </summary>
        /// <param name="network"></param>
        /// <param name="startLink">起始管线</param>
        /// <param name="visitedNodes">遍历的哈希表(用于多点遍历)</param>
        /// <param name="direction">遍历方向,0表示双向,1表示正向,-1表示反向</param>
        /// <param name="isOnlyMax">是否只取最大流量的分支</param>
        /// <returns></returns>
        public static List<ILink> TraversePipeNetworkALL(this Network network,ILink startLink, HashSet<INode> visitedNodes = null, int direction = 0, bool isOnlyMax = false)
        {
            var _links主要路径=new List<ILink>();
            if (isOnlyMax) _links主要路径.Add(startLink);
            Queue<ILink> queue = new Queue<ILink>();
            queue.Enqueue(startLink);
            if (visitedNodes == null)
                visitedNodes = new HashSet<INode>();
            while (queue.Count > 0)
            {
                ILink currentLink = queue.Dequeue();
                if (isOnlyMax) _links主要路径.Add(currentLink);
                foreach (var node in new INode[] { currentLink.StartNode, currentLink.EndNode })
                {
                    if (direction == 1 && currentLink.Flow >= 0 && node == currentLink.StartNode) continue;
                    if (direction == -1 && currentLink.Flow <= 0 && node == currentLink.EndNode) continue;
                    if (node != null && !visitedNodes.Contains(node))
                    {
                        visitedNodes.Add(node);
                        List<ILink> list = new List<ILink>();
                        foreach (var link in node.Links)
                        {
                            if (!visitedNodes.Contains(link.StartNode) || !visitedNodes.Contains(link.EndNode))
                            {
                                list.Add(link);
                            }
                        }
                        if (!isOnlyMax)
                        {
                            foreach (var link in list)
                            {
                                queue.Enqueue(link);
                            }
                        }
                        else
                        {
                            if (list.Count >= 1)
                            {
                                var maxlist = list.OrderByDescending(p => Math.Abs(p.Flow)).ToList()[0];
                                queue.Enqueue(maxlist);
                            }
                        }
                    }
                }
            }
            return _links主要路径;
        }
    }
    public class ChartNode
        internal class InnerLossNode
    {
        public string Id { get; set; }
        /// <summary>
        /// 起始水头
        /// </summary>
@@ -214,5 +42,243 @@
                return StartHead - EndHead;
            }
        }
            public double Distance { get; set; }
        }
        public static List<LossNode> GetChartNodeByPathLinks(this Network network, List<Link> links,CalcuResult calcuResult)
        {
            var dictLinks = calcuResult.LinkList.ToDictionary(p => p.Id);
            var dictNodes = calcuResult.NodeList.ToDictionary(p => p.Id);
            double length = 0;
            InnerLossNode nodeEnd = new InnerLossNode();
            List<InnerLossNode> chartNodes = new List<InnerLossNode>();
            for (int i = 0; i < links.Count; i++)
            {
                var link = links[i];
                var node = dictLinks[link.Id].Flow > 0 ? link.StartNode : link.EndNode;
                double elev = getElev(node);
                var Cnode = new InnerLossNode()
                {
                    Id = node.Id,
                    StartHead = dictNodes[node.Id].Head,
                    EndHead = dictNodes[node.Id].Head,
                    Elev = elev,
                    Distance = length
                };
                chartNodes.Add(Cnode);
                var nodeEnd0 = dictLinks[link.Id].Flow > 0 ? link.EndNode : link.StartNode;
                nodeEnd.Id = nodeEnd0.Id;
                nodeEnd.Head = nodeEnd.StartHead = nodeEnd.EndHead = dictNodes[nodeEnd0.Id].Head;
                nodeEnd.Elev = getElev(nodeEnd0);
                if (link is Pipe p)
                    length += p.Length;
            }
            chartNodes.Add(nodeEnd);
            for (int i=0;i<links.Count;i++)
            {
                var link = links[i];
                Pipe p=link as Pipe;
                if (p != null)
                {
                    //根据p.diameter和p.flow计算流速
                    double velocity = dictLinks[ p.Id].Flow/ (Math.PI * Math.Pow(p.Diameter / 2, 2));
                    //根据流速计算局部水头损失
                    double minorloss1 = p.StartMinorloss* Math.Pow(velocity, 2) / 2 / 9.81;
                    double minorloss2 = p.EndMinorloss * Math.Pow(velocity, 2) / 2 / 9.81;
                    if (i < links.Count - 1)
                    {
                        chartNodes[i].EndHead = chartNodes[i].Head - minorloss1;
                        chartNodes[i + 1].StartHead = chartNodes[i].EndHead - minorloss2;
                    }
                    else
                    {
                        chartNodes[i].EndHead = chartNodes[i].Head - minorloss1;
                    }
                }
            }
            List<LossNode> lossNodes = new List<LossNode>();
            for (int i = 0; i < chartNodes.Count; i++)
            {
                var node = chartNodes[i];
                LossNode lossNode = new LossNode()
                {
                    Id = node.Id,
                    Elev = node.Elev,
                    Head = node.StartHead,
                    MinorLoss = node.MinorHeadLoss,
                    Distance =node.Distance,
                };
                lossNodes.Add(lossNode);
            }
            return lossNodes;
        }
        private static double getElev(Node node)
        {
            double elev = 0;
            if (node is Tank tank)
            {
                elev = tank.PoolElev + tank.InitLevel;
            }
            else if (node is Reservoir reser)
            {
                elev = reser.Head;
            }
            else if (node is Junction junc)
            {
                elev = junc.Elev;
            }
            return elev;
        }
        /// <summary>
        /// 分析下游主要供水路径
        /// </summary>
        public static List<Link> AnalyzeDownstreamPath(this Network network, Node startJunc,CalcuResult calcuResult)
        {
            var dictLinks = calcuResult.LinkList.ToDictionary(p => p.Id);
            var dictNodes = calcuResult.NodeList.ToDictionary(p => p.Id);
            var visitedNodes = new HashSet<Node>();
            var maxlink = startJunc.GetNextLinks(calcuResult.LinkList).OrderByDescending(o => Math.Abs(dictLinks[o.Id].Flow)).ToList()[0];
            return  network.TraversePipeNetworkALL(maxlink, visitedNodes, 1, true);
        }
        /// <summary>
        /// 分析上游主要供水路径
        /// </summary>
        /// <param name="network"></param>
        /// <param name="startJunc"></param>
        /// <returns></returns>
        public static List<Link> AnalyzeUpstreamPath(this Network network, Junction startJunc, CalcuResult calcuResult)
        {
            var dictLinks = calcuResult.LinkList.ToDictionary(p => p.Id);
            var dictNodes = calcuResult.NodeList.ToDictionary(p => p.Id);
            var visitedNodes = new HashSet<Node>();
            var maxlink = startJunc.GetPrevLinks(calcuResult.LinkList).OrderByDescending(o => Math.Abs(dictLinks[o.Id].Flow)).ToList()[0];
            return network.TraversePipeNetworkALL(maxlink, visitedNodes, -1, true, calcuResult);
        }
        /// <summary>
        /// 宽度搜索遍历管网
        /// </summary>
        /// <param name="network"></param>
        /// <param name="startLink">起始管线</param>
        /// <param name="visitedNodes">遍历的哈希表(用于多点遍历)</param>
        /// <param name="direction">遍历方向,0表示双向,1表示正向,-1表示反向</param>
        /// <param name="isOnlyMax">是否只取最大流量的分支</param>
        /// <returns></returns>
        public static List<Link> TraversePipeNetworkALL(this Network network, Link startLink, HashSet<Node> visitedNodes = null, int direction = 0, bool isOnlyMax = false,CalcuResult calcuResult=null)
        {
            var dictLinks = calcuResult.LinkList.ToDictionary(p => p.Id);
            var dictNodes = calcuResult.NodeList.ToDictionary(p => p.Id);
            var _links主要路径=new List<Link>();
            if (isOnlyMax) _links主要路径.Add(startLink);
            Queue<Link> queue = new Queue<Link>();
            queue.Enqueue(startLink);
            if (visitedNodes == null)
                visitedNodes = new HashSet<Node>();
            while (queue.Count > 0)
            {
                Link currentLink = queue.Dequeue();
                if (isOnlyMax) _links主要路径.Add(currentLink);
                foreach (var node in new Node[] { currentLink.StartNode, currentLink.EndNode })
                {
                    if (direction == 1 && dictLinks[currentLink.Id].Flow >= 0 && node == currentLink.StartNode) continue;
                    if (direction == -1 && dictLinks[currentLink.Id].Flow <= 0 && node == currentLink.EndNode) continue;
                    if (node != null && !visitedNodes.Contains(node))
                    {
                        visitedNodes.Add(node);
                        List<Link> list = new List<Link>();
                        foreach (var link in node.Links)
                        {
                            if (!visitedNodes.Contains(link.StartNode) || !visitedNodes.Contains(link.EndNode))
                            {
                                list.Add(link);
                            }
                        }
                        if (!isOnlyMax)
                        {
                            foreach (var link in list)
                            {
                                queue.Enqueue(link);
                            }
                        }
                        else
                        {
                            if (list.Count >= 1)
                            {
                                var maxlist = list.OrderByDescending(p => Math.Abs(dictLinks[p.Id].Flow)).ToList()[0];
                                queue.Enqueue(maxlist);
                            }
                        }
                    }
                }
            }
            return _links主要路径;
        }
    }
    public class LossNode
    {
        public string Id { get; set; }
        /// <summary>
        /// 高程
        /// </summary>
        public double Elev { get; set; }
        /// <summary>
        /// 水头
        /// </summary>
        public double Head { get; set; }
        /// <summary>
        /// 局部水头损失
        /// </summary>
        public double MinorLoss { get; set; }
        /// <summary>
        /// 距离
        /// </summary>
        public double Distance { get; set; }
    }
}