///<summary>Computes coefficients of linearized network eqns.</summary> private void NewCoeffs() { _lsv.Clear(); foreach (SimulationLink link in _links) { link.SimInvHeadLoss = 0; link.SimFlowCorrection = 0; } SimulationLink.ComputeMatrixCoeffs( net, _pHlModel, _links, _curves, _smat, _lsv); // Compute link coeffs. SimulationNode.ComputeEmitterCoeffs(net, _junctions, _smat, _lsv); // Compute emitter coeffs. SimulationNode.ComputeNodeCoeffs(_junctions, _smat, _lsv); // Compute node coeffs. SimulationValve.ComputeMatrixCoeffs(net, _lsv, _smat, _valves); // Compute valve coeffs. }
///<summary>Init hydraulic simulation, preparing the linear solver and the hydraulic structures wrappers.</summary> /// <param name="net">Hydraulic network reference.</param> /// <param name="log">Logger reference.</param> public HydraulicSim(EpanetNetwork net, TraceSource log) { _running = false; _logger = log; // this.CreateSimulationNetwork(net); _nodes = new SimulationNode[net.Nodes.Count]; _links = new SimulationLink[net.Links.Count]; _pumps = new List <SimulationPump>(); _tanks = new List <SimulationTank>(); _junctions = new List <SimulationNode>(); _valves = new List <SimulationValve>(); var nodesById = new Dictionary <string, SimulationNode>(net.Nodes.Count); for (int i = 0; i < net.Nodes.Count; i++) { SimulationNode node; var networkNode = net.Nodes[i]; if (networkNode.Type == NodeType.JUNC) { node = new SimulationNode(networkNode, i); _junctions.Add(node); } else { node = new SimulationTank(networkNode, i); _tanks.Add((SimulationTank)node); } _nodes[i] = node; nodesById[node.Id] = node; } for (int i = 0; i < net.Links.Count; i++) { SimulationLink link; var networkLink = net.Links[i]; if (networkLink is Valve) { var valve = new SimulationValve(nodesById, networkLink, i); _valves.Add(valve); link = valve; } else if (networkLink is Pump) { var pump = new SimulationPump(nodesById, networkLink, i); _pumps.Add(pump); link = pump; } else { link = new SimulationLink(nodesById, networkLink, i); } _links[i] = link; } _rules = net.Rules.Select(r => new SimulationRule(r, _links, _nodes)).ToArray(); _curves = net.Curves.ToArray(); _controls = net.Controls.Select(x => new SimulationControl(_nodes, _links, x)).ToArray(); this.net = net; _epat = net.GetPattern(this.net.EPatId); _smat = new SparseMatrix(_nodes, _links, _junctions.Count); _lsv = new LsVariables(_nodes.Length, _smat.CoeffsCount); Htime = 0; switch (this.net.FormFlag) { case FormType.HW: _pHlModel = PipeHeadModelCalculators.HwModelCalculator; break; case FormType.DW: _pHlModel = PipeHeadModelCalculators.DwModelCalculator; break; case FormType.CM: _pHlModel = PipeHeadModelCalculators.CmModelCalculator; break; } foreach (SimulationLink link in _links) { link.InitLinkFlow(); } foreach (SimulationNode node in _junctions) { if (node.Ke > 0.0) { node.SimEmitter = 1.0; } } foreach (SimulationLink link in _links) { if ((link.Type == LinkType.PRV || link.Type == LinkType.PSV || link.Type == LinkType.FCV) && !double.IsNaN(link.Roughness)) { link.SimStatus = StatType.ACTIVE; } if (link.SimStatus <= StatType.CLOSED) { link.SimFlow = Constants.QZERO; } else if (Math.Abs(link.SimFlow) <= Constants.QZERO) { link.InitLinkFlow(link.SimStatus, link.SimSetting); } link.SimOldStatus = link.SimStatus; } Htime = 0; Rtime = this.net.RStep; }
///<summary>Solve the linear equation system to compute the links flows and nodes heads.</summary> /// <returns>Solver steps and relative error.</returns> protected void NetSolve(out int iter, out double relerr) { iter = 0; relerr = 0.0; int nextCheck = net.CheckFreq; if (net.StatFlag == StatFlag.FULL) { LogRelErr(iter, relerr); } int maxTrials = net.MaxIter; if (net.ExtraIter > 0) { maxTrials += net.ExtraIter; } double relaxFactor = 1.0; int errcode = 0; iter = 1; while (iter <= maxTrials) { //Compute coefficient matrices A & F and solve A*H = F // where H = heads, A = Jacobian coeffs. derived from // head loss gradients, & F = flow correction terms. NewCoeffs(); //dumpMatrixCoeffs(new File("dumpMatrix.txt"),true); // Solution for H is returned in F from call to linsolve(). errcode = _smat.LinSolve( _junctions.Count, _lsv.AiiVector, _lsv.AijVector, _lsv.RhsCoeffs); // Ill-conditioning problem if (errcode > 0) { // If control valve causing problem, fix its status & continue, // otherwise end the iterations with no solution. if (SimulationValve.CheckBadValve( net, _logger, _valves, Htime, _smat.GetOrder(errcode))) { continue; } break; } // Update current solution. // (Row[i] = row of solution matrix corresponding to node i). foreach (SimulationNode node in _junctions) { node.SimHead = _lsv.GetRhsCoeff(_smat.GetRow(node.Index)); // Update heads } // Update flows relerr = NewFlows(relaxFactor); // Write convergence error to status report if called for if (net.StatFlag == StatFlag.FULL) { LogRelErr(iter, relerr); } relaxFactor = 1.0; bool valveChange = false; // Apply solution damping & check for change in valve status if (net.DampLimit > 0.0) { if (relerr <= net.DampLimit) { relaxFactor = 0.6; valveChange = SimulationValve.ValveStatus(net, _logger, _valves); } } else { valveChange = SimulationValve.ValveStatus(net, _logger, _valves); } // Check for convergence if (relerr <= net.HAcc) { // We have convergence. Quit if we are into extra iterations. if (iter > net.MaxIter) { break; } // Quit if no status changes occur. bool statChange = valveChange; if (SimulationLink.LinkStatus(net, _logger, _links)) { statChange = true; } if (SimulationControl.PSwitch(_logger, net, _controls)) { statChange = true; } if (!statChange) { break; } // We have a status change so continue the iterations nextCheck = iter + net.CheckFreq; } else if (iter <= net.MaxCheck && iter == nextCheck) { // No convergence yet. See if its time for a periodic status // check on pumps, CV's, and pipes connected to tanks. SimulationLink.LinkStatus(net, _logger, _links); nextCheck += net.CheckFreq; } iter++; } foreach (SimulationNode node in _junctions) { node.SimDemand = node.SimDemand + node.SimEmitter; } if (errcode > 0) { LogHydErr(_smat.GetOrder(errcode)); errcode = 110; return; } if (errcode != 0) { throw new ENException((ErrorCode)errcode); } }