using System.Text;
namespace Yw.EPAnet
{
///
/// 管网计算拓展
///
public static class NetworkCalcuExtensions
{
///
/// 简单计算
///
public static CalcuResult CalcuSimple(this Network network)
{
var result = new CalcuResult();
//Null验证
if (network == null)
{
result.Succeed = false;
return result;
}
var linkdict = network.GetAllLinks().ToDictionary(p => p.Id);
var nodedict = network.GetAllNodes().ToDictionary(p => p.Id);
//获取系统临时文件目录,创建inp临时文件
var inpFilePath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N") + ".inp");
//inp文本写入
var inpString = network.ToInpString();
File.WriteAllText(inpFilePath, inpString);
//加载管网
var epanet = new HydraulicCore(true);
var errOpen = epanet.open(inpFilePath, "", "");
if (errOpen != 0)
{
string errorMsg = epanet.geterrormsg();
result.Succeed = false;
result.FailedList.Add(new CalcuFailed()
{
Code = errOpen,
Message = $"{errorMsg}"
});
return result;
}
//水力计算
var errCalcu = epanet.solveH();
if (errCalcu != 0)
{
string errorMsg = epanet.geterrormsg();
result.Succeed = false;
result.FailedList.Add(new CalcuFailed()
{
Code = errCalcu,
Message = $"{errorMsg}"
});
return result;
}
int nodeCount = 0;
int linkCount = 0;
epanet.getcount((int)eCountType.Node, ref nodeCount);
epanet.getcount((int)eCountType.Link, ref linkCount);
const int MAXID = 31;
var sb = new StringBuilder(MAXID);
for (int i = 1; i <= nodeCount; i++)
{
epanet.getnodeid(i, sb);
var arr = new string[] { "Head", "Press", "Demand" }; //System.Enum.GetValues(typeof(HydraulicModel.NodeValueType));
var arrnum = new int[] { 10, 11, 9 };
var calcuNode = new CalcuNode()
{
Id = sb.ToString(),
};
for (var j = 0; j < arr.Length; j++)
{
float v = 0;
//var t = (EPAcore.Core.NodeValueType)j;
epanet.getnodevalue(i, arrnum[j], ref v);
switch (arr[j])
{
case "Head":
calcuNode.Head = v;
break;
case "Press":
calcuNode.Press = v;
break;
case "Demand":
calcuNode.Demand = v;
break;
}
}
result.NodeList.Add(calcuNode);
}
var nodeResultDict = result.NodeList.ToDictionary(p => p.Id);
for (int i = 1; i <= linkCount; i++)
{
epanet.getlinkid(i, sb);
//var arr = System.Enum.GetValues(typeof(HydraulicModel.LinkValueType));
var arr = new string[] { "Flow", "Velocity", "Headloss" }; //System.Enum.GetValues(typeof(HydraulicModel.NodeValueType));
var arrnum = new int[] { 8, 9, 10 };
var calcuLink = new CalcuLink()
{
Id = sb.ToString(),
};
for (var j = 0; j < arr.Length; j++)
{
float v = 0;
//var t = (EPAcore.Core.NodeValueType)j;
epanet.getlinkvalue(i, arrnum[j], ref v);
switch (arr[j])
{
case "Flow":
calcuLink.Flow = v;
break;
case "Velocity":
calcuLink.Velocity = v;
break;
case "Headloss":
calcuLink.Headloss = v;
break;
}
if (linkdict[calcuLink.Id] is Pipe p)
{
double minorloss1 = p.StartMinorloss * Math.Pow(calcuLink.Velocity, 2) / 2 / 9.81;
double minorloss2 = p.EndMinorloss * Math.Pow(calcuLink.Velocity, 2) / 2 / 9.81;
double minorloss = p.MinorLoss * Math.Pow(calcuLink.Velocity, 2) / 2 / 9.81;
calcuLink.Headloss -= minorloss1 + minorloss2;
calcuLink.MinorLoss = minorloss;
calcuLink.FrictionLoss = calcuLink.Headloss - minorloss;
//if (nodedict[p.StartNode.Id] is Elbow)
{
nodeResultDict[p.StartNode.Id].MinorLoss += minorloss1;
}
//if (nodedict[p.EndNode.Id] is Elbow)
{
nodeResultDict[p.EndNode.Id].MinorLoss += minorloss2;
}
}
}
result.LinkList.Add(calcuLink);
}
return result;
}
///
/// 计算局阻系数
/// network中的局部损失会被修改
///
public static CalcuResult CalcuMinorLoss(this Network network)
{
var calcuResult = network.CalcuSimple();
if (!calcuResult.Succeed)
{
return calcuResult;
}
var allCalcuLinks = calcuResult.LinkList;
var allNodeList = network.GetAllNodes();
var allLinkList = network.GetAllLinks();
foreach (var link in allLinkList)
{
if (link is Pipe p)
{
p.StartMinorloss = 0;
p.EndMinorloss = 0;
}
}
foreach (var node in allNodeList)
{
var prevLinks = node.GetPrevLinks(allCalcuLinks);
if (prevLinks == null || prevLinks.Count < 1)
{
continue;
}
var nextLinks = node.GetNextLinks(allCalcuLinks);
if (nextLinks == null || nextLinks.Count < 1)
{
continue;
}
if (node is Elbow elbow)
{
//弯头
if (!elbow.MinorLoss.HasValue)
{
continue;
}
if (prevLinks.Count != 1)
{
continue;
}
var prevLink = prevLinks[0] as Pipe;
if (prevLink != null)
{
prevLink.EndMinorloss = elbow.MinorLoss.Value / 2f;
}
if (nextLinks.Count != 1)
{
continue;
}
var nextLink = nextLinks[0] as Pipe;
if (nextLink != null)
{
nextLink.StartMinorloss = elbow.MinorLoss.Value / 2f;
}
}
else if (node is Threelink threelink)
{
//三通
var linkCount = prevLinks.Count + nextLinks.Count;
if (linkCount != 3)
{
continue;
}
Link mainLink = null;//主管
List branchLinks = null;//支管列表
bool isNext = prevLinks.Count == 1;
if (isNext)//1进2出
{
mainLink = prevLinks[0];
branchLinks = nextLinks;
}
else//2进1出
{
mainLink = nextLinks[0];
branchLinks = prevLinks;
}
var mainPipe = mainLink as Pipe;
if (mainPipe == null)
{
continue;
}
foreach (var branchLink in branchLinks)
{
var branchPipe = branchLink as Pipe;
if (branchPipe == null)
{
continue;
}
if (branchPipe.Diameter == mainPipe.Diameter)
{
var minorLoss = threelink.RunningThroughLoss;
if (!minorLoss.HasValue)
{
minorLoss = threelink.MinorLoss;
if (minorLoss.HasValue)
{
if (isNext)
branchPipe.StartMinorloss = minorLoss.Value;
else
branchPipe.EndMinorloss = minorLoss.Value;
}
}
}
else
{
var minorLoss = threelink.BranchThroughLoss;
if (!minorLoss.HasValue)
{
minorLoss = threelink.MinorLoss;
if (minorLoss.HasValue)
{
if (isNext)
branchPipe.StartMinorloss = minorLoss.Value;
else
branchPipe.EndMinorloss = minorLoss.Value;
}
}
}
}
}
else if (node is Fourlink fourlink)
{
//四通
if (!fourlink.MinorLoss.HasValue)
{
continue;
}
var linkCount = prevLinks.Count + nextLinks.Count;
if (linkCount != 4)
{
continue;
}
bool isNext = prevLinks.Count < nextLinks.Count;
var branchLinks = isNext ? nextLinks : prevLinks;
foreach (var branchLink in branchLinks)
{
var pipe = branchLink as Pipe;
if (pipe != null)
{
if (isNext)
{
pipe.StartMinorloss = fourlink.MinorLoss.Value;
}
else
{
pipe.EndMinorloss = fourlink.MinorLoss.Value;
}
}
}
}
}
calcuResult = network.CalcuSimple();
return calcuResult;
}
///
/// 计算
///
public static CalcuResult Calcu(this Network network, string calcuMode)
{
CalcuResult result = null;
switch (calcuMode)
{
case CalcuMode.Simple:
{
result = network.CalcuSimple();
}
break;
case CalcuMode.MinorLoss:
{
result = network.CalcuMinorLoss();
}
break;
default:
{
result = network.CalcuSimple();
}
break;
}
return result;
}
}
}