// Simulation Methods /// <summary>Evaluate rule premises.</summary> private bool EvalPremises( EpanetNetwork net, long time1, long htime, double dsystem) { bool result = true; foreach (var p in _pchain) { if (p.logop == Rulewords.OR) { if (!result) { result = p.CheckPremise(net, time1, htime, dsystem); } } else { if (!result) { return(false); } result = p.CheckPremise(net, time1, htime, dsystem); } } return(result); }
/// <summary>Execute action, returns true if the link was alterated.</summary> public bool Execute(EpanetNetwork net, TraceSource log, double tol, long htime) { bool flag = false; StatType s = _link.SimStatus; double v = _link.SimSetting; double x = _setting; if (_status == Values.IS_OPEN && s <= StatType.CLOSED) { // Switch link from closed to open _link.SetLinkStatus(true); flag = true; } else if (_status == Values.IS_CLOSED && s > StatType.CLOSED) { // Switch link from not closed to closed _link.SetLinkStatus(false); flag = true; } else if (!double.IsNaN(x)) { // Change link's setting switch (_link.Type) { case LinkType.PRV: case LinkType.PSV: case LinkType.PBV: x /= net.FieldsMap.GetUnits(FieldType.PRESSURE); break; case LinkType.FCV: x /= net.FieldsMap.GetUnits(FieldType.FLOW); break; } if (Math.Abs(x - v) > tol) { _link.SetLinkSetting(x); flag = true; } } if (flag) { if (net.StatFlag > 0) // Report rule action { LogRuleExecution(log, htime); } return(true); } return(false); }
/// <summary>Computes P & Y coefficients for pipe k.</summary> private void ComputePipeCoeff(EpanetNetwork net, PipeHeadModelCalculators.Compute hlModel) { // For closed pipe use headloss formula: h = CBIG*q if (status <= StatType.CLOSED) { invHeadLoss = 1.0 / Constants.CBIG; flowCorrection = flow; return; } hlModel(net, this, out invHeadLoss, out flowCorrection); }
/// <summary>Determines new status for pumps, CVs, FCVs & pipes to tanks.</summary> public static bool LinkStatus(EpanetNetwork net, TraceSource log, IEnumerable <SimulationLink> links) { bool change = false; foreach (SimulationLink link in links) { if (link.LinkStatus(net, log)) { change = true; } } return(change); }
/// <summary>Computes solution matrix coefficients for links.</summary> public static void ComputeMatrixCoeffs( EpanetNetwork net, PipeHeadModelCalculators.Compute hlModel, IEnumerable <SimulationLink> links, IList <Curve> curves, SparseMatrix smat, LsVariables ls) { foreach (SimulationLink link in links) { link.ComputeMatrixCoeff(net, hlModel, curves, smat, ls); } }
/// <summary>Implements actions on action list, returns the number of actions executed.</summary> private static int TakeActions(EpanetNetwork net, TraceSource log, List <ActItem> actionList, long htime) { double tol = 1e-3; int n = 0; foreach (ActItem item in actionList) { if (item.action.Execute(net, log, tol, htime)) { n++; } } return(n); }
/// <summary>Revises time step based on shortest time to fill or drain a tank.</summary> public static long MinimumTimeStep( EpanetNetwork net, IEnumerable <SimulationControl> controls, long htime, long tstep) { long newTStep = tstep; foreach (SimulationControl control in controls) { newTStep = control.GetRequiredTimeStep(net, htime, newTStep); } return(newTStep); }
/// <summary>Updates status of a check valve.</summary> private static StatType CvStatus(EpanetNetwork net, StatType s, double dh, double q) { if (Math.Abs(dh) > net.HTol) { if (dh < -net.HTol) { return(StatType.CLOSED); } return(q < -net.QTol ? StatType.CLOSED : StatType.OPEN); } else { return(q < -net.QTol ? StatType.CLOSED : s); } }
/// <summary>Determines new status for pumps, CVs, FCVs & pipes to tanks.</summary> private bool LinkStatus(EpanetNetwork net, TraceSource log) { bool change = false; double dh = first.SimHead - second.SimHead; StatType tStatus = status; if (tStatus == StatType.XHEAD || tStatus == StatType.TEMPCLOSED) { status = StatType.OPEN; } if (Type == LinkType.CV) { status = CvStatus(net, status, dh, flow); } var pump = this as SimulationPump; if (pump != null && status >= StatType.OPEN && setting > 0.0) { status = pump.PumpStatus(net, -dh); } if (Type == LinkType.FCV && !double.IsNaN(setting)) { status = ((SimulationValve)this).FcvStatus(net, tStatus); } if (first is SimulationTank || second is SimulationTank) { TankStatus(net); } if (tStatus != status) { change = true; if (net.StatFlag == StatFlag.FULL) { LogStatChange(net.FieldsMap, log, this, tStatus, status); } } return(change); }
/// <summary>Checks if a particular premise is true.</summary> public bool CheckPremise( EpanetNetwork net, long time1, long htime, double dsystem) { if (_variable == Varwords.TIME || _variable == Varwords.CLOCKTIME) { return(CheckTime(net, time1, htime)); } else if (_status > Values.IS_NUMBER) { return(CheckStatus()); } else { return(CheckValue(net.FieldsMap, dsystem)); } }
/// <summary>Checks which rules should fire at current time.</summary> private static int Check( EpanetNetwork net, IEnumerable <SimulationRule> rules, TraceSource log, long htime, long dt, double dsystem) { // Start of rule evaluation time interval long time1 = htime - dt + 1; List <ActItem> actionList = new List <ActItem>(); foreach (SimulationRule rule in rules) { UpdateActionList(rule, actionList, rule.EvalPremises(net, time1, htime, dsystem)); } return(TakeActions(net, log, actionList, htime)); }
/// <summary>Generate multi-species quality report.</summary> /// <param name="msxBin">Name of the MSX simulation output file.</param> /// <param name="net">Hydraulic network.</param> /// <param name="netMsx">MSX network.</param> /// <param name="tk2">Hydraulic network - MSX bridge.</param> /// <param name="values">Species report flag.</param> public void CreateMsxReport(string msxBin, EpanetNetwork net, EpanetMSX netMsx, EnToolkit2 tk2, bool[] values) { Rtime = 0; var nodes = netMsx.Network.Node; var links = netMsx.Network.Link; string[] nSpecies = netMsx.GetSpeciesNames(); int reportCount = (int)((net.Duration - net.RStart) / net.RStep) + 1; var reader = new MsxReader( nodes.Length - 1, links.Length - 1, nSpecies.Length, netMsx.ResultsOffset); int totalSpecies = values == null ? nSpecies.Length : values.Count(b => b); reader.Open(msxBin); var nodesHead = new object[nSpecies.Length + 1]; nodesHead[0] = _sheet.TransposedMode ? "Node/Time" : "Time/Node"; var linksHead = new object[nSpecies.Length + 1]; linksHead[0] = _sheet.TransposedMode ? "Link/Time" : "Time/Link"; int count = 1; for (int i = 0; i < nSpecies.Length; i++) { if (values == null || values[i]) { nodesHead[count] = nSpecies[i]; linksHead[count++] = nSpecies[i]; } } var nodeRow = new object[totalSpecies + 1]; for (int i = 1; i < nodes.Length; i++) { if (!nodes[i].Rpt) { continue; } var spr = _sheet.NewSpreadsheet("Node<<" + tk2.ENgetnodeid(i) + ">>"); spr.AddHeader(nodesHead); for (long time = net.RStart, period = 0; time <= net.Duration; time += net.RStep, period++) { nodeRow[0] = time.GetClockTime(); for (int j = 0, ji = 0; j < nSpecies.Length; j++) { if (values == null || values[j]) { nodeRow[ji++ + 1] = reader.GetNodeQual((int)period, i, j + 1); } } spr.AddData(nodeRow); } } var linkRow = new object[totalSpecies + 1]; for (int i = 1; i < links.Length; i++) { if (!links[i].Rpt) { continue; } var spr = _sheet.NewSpreadsheet("Link<<" + tk2.ENgetlinkid(i) + ">>"); spr.AddHeader(linksHead); for (long time = net.RStart, period = 0; time <= net.Duration; time += net.RStep, period++) { linkRow[0] = time.GetClockTime(); for (int j = 0, ji = 0; j < nSpecies.Length; j++) { if (values == null || values[j]) { linkRow[ji++ + 1] = reader.GetLinkQual((int)period, i, j + 1); } } spr.AddData(linkRow); } } reader.Close(); }
/// <summary>Generate quality report.</summary> /// <param name="qualFile">Name of the quality simulation output file.</param> /// <param name="net">Hydraulic network.</param> /// <param name="nodes">Show nodes quality flag.</param> /// <param name="links">Show links quality flag.</param> public void CreateQualReport(string qualFile, EpanetNetwork net, bool nodes, bool links) { Rtime = 0; int reportCount = (int)((net.Duration - net.RStart) / net.RStep) + 1; using (QualityReader dseek = new QualityReader(qualFile, net.FieldsMap)) { var netNodes = net.Nodes; var netLinks = net.Links; var nodesHead = new object[dseek.Nodes + 1]; nodesHead[0] = _sheet.TransposedMode ? "Node/Time" : "Time/Node"; for (int i = 0; i < netNodes.Count; i++) { nodesHead[i + 1] = netNodes[i].Name; } var linksHead = new object[dseek.Links + 1]; linksHead[0] = _sheet.TransposedMode ? "Link/Time" : "Time/Link"; for (int i = 0; i < netLinks.Count; i++) { linksHead[i + 1] = netLinks[i].Name; } var resultSheets = new XlsxWriter.Spreadsheet[HydVariable.Values.Length]; for (int i = 0; i < QualVariable.Values.Length; i++) { var qvar = QualVariable.Values[i]; if ((!qvar.isNode || !nodes) && (qvar.isNode || !links)) { continue; } resultSheets[i] = _sheet.NewSpreadsheet(qvar.name); resultSheets[i].AddHeader(qvar.isNode ? nodesHead : linksHead); } var nodeRow = new object[dseek.Nodes + 1]; var linkRow = new object[dseek.Links + 1]; using (var qIt = dseek.GetEnumerator()) for (long time = net.RStart; time <= net.Duration; time += net.RStep) { if (!qIt.MoveNext()) { return; } var step = qIt.Current; if (step == null) { continue; } nodeRow[0] = time.GetClockTime(); linkRow[0] = time.GetClockTime(); if (resultSheets[(int)QualVariable.Type.Nodes] != null) { for (int i = 0; i < dseek.Nodes; i++) { nodeRow[i + 1] = (double)step.GetNodeQuality(i); } resultSheets[(int)QualVariable.Type.Nodes].AddData(nodeRow); } if (resultSheets[(int)QualVariable.Type.Links] != null) { for (int i = 0; i < dseek.Links; i++) { linkRow[i + 1] = (double)step.GetLinkQuality(i); } resultSheets[(int)QualVariable.Type.Links].AddData(linkRow); } Rtime = time; } } }
/// <summary>Generate hydraulic report.</summary> /// <param name="hydBinFile">Name of the hydraulic simulation output file.</param> /// <param name="net">Hydraulic network.</param> /// <param name="values">Variables report flag.</param> public void CreateHydReport(string hydBinFile, EpanetNetwork net, bool[] values) { Rtime = 0; HydraulicReader dseek = new HydraulicReader(new BinaryReader(File.OpenRead(hydBinFile))); int reportCount = (int)((net.Duration - net.RStart) / net.RStep) + 1; var nodes = net.Nodes; var links = net.Links; object[] nodesHead = new object[dseek.Nodes + 1]; nodesHead[0] = _sheet.TransposedMode ? "Node/Time" : "Time/Node"; for (int i = 0; i < nodes.Count; i++) { nodesHead[i + 1] = nodes[i].Name; } var linksHead = new object[dseek.Links + 1]; linksHead[0] = _sheet.TransposedMode ? "Link/Time" : "Time/Link"; for (int i = 0; i < links.Count; i++) { linksHead[i + 1] = links[i].Name; } XlsxWriter.Spreadsheet[] resultSheets = new XlsxWriter.Spreadsheet[HydVariable.Values.Length]; // Array.Clear(resultSheets, 0, resultSheets.Length); for (int i = 0; i < resultSheets.Length; i++) { if (values != null && !values[i]) { continue; } resultSheets[i] = _sheet.NewSpreadsheet(HydVariable.Values[i].name); resultSheets[i].AddHeader(HydVariable.Values[i].isNode ? nodesHead : linksHead); } var nodeRow = new object[dseek.Nodes + 1]; var linkRow = new object[dseek.Links + 1]; for (long time = net.RStart; time <= net.Duration; time += net.RStep) { var step = dseek.GetStep(time); if (step == null) { Rtime = time; continue; } nodeRow[0] = time.GetClockTime(); linkRow[0] = time.GetClockTime(); // NODES HEADS if (resultSheets[(int)HydVariable.Type.Head] != null) { for (int i = 0; i < nodes.Count; i++) { nodeRow[i + 1] = step.GetNodeHead(i, nodes[i], net.FieldsMap); } resultSheets[(int)HydVariable.Type.Head].AddData(nodeRow); } // NODES DEMANDS if (resultSheets[(int)HydVariable.Type.Demands] != null) { for (int i = 0; i < nodes.Count; i++) { nodeRow[i + 1] = step.GetNodeDemand(i, nodes[i], net.FieldsMap); } resultSheets[(int)HydVariable.Type.Demands].AddData(nodeRow); } // NODES PRESSURE if (resultSheets[(int)HydVariable.Type.Pressure] != null) { for (int i = 0; i < nodes.Count; i++) { nodeRow[i + 1] = step.GetNodePressure(i, nodes[i], net.FieldsMap); } resultSheets[(int)HydVariable.Type.Pressure].AddData(nodeRow); } // LINK FLOW if (resultSheets[(int)HydVariable.Type.Flows] != null) { for (int i = 0; i < links.Count; i++) { linkRow[i + 1] = step.GetLinkFlow(i, links[i], net.FieldsMap); } resultSheets[(int)HydVariable.Type.Flows].AddData(linkRow); } // LINK VELOCITY if (resultSheets[(int)HydVariable.Type.Velocity] != null) { for (int i = 0; i < links.Count; i++) { linkRow[i + 1] = step.GetLinkVelocity(i, links[i], net.FieldsMap); } resultSheets[(int)HydVariable.Type.Velocity].AddData(linkRow); } // LINK HEADLOSS if (resultSheets[(int)HydVariable.Type.Headloss] != null) { for (int i = 0; i < links.Count; i++) { linkRow[i + 1] = step.GetLinkHeadLoss(i, links[i], net.FieldsMap); } resultSheets[(int)HydVariable.Type.Headloss].AddData(linkRow); } // LINK FRICTION if (resultSheets[(int)HydVariable.Type.Friction] != null) { for (int i = 0; i < links.Count; i++) { linkRow[i + 1] = step.GetLinkFriction(i, links[i], net.FieldsMap); } resultSheets[(int)HydVariable.Type.Friction].AddData(linkRow); } Rtime = time; } dseek.Close(); }
///<summary>Get the shortest time step to activate the control.</summary> private long GetRequiredTimeStep(EpanetNetwork net, long htime, long tstep) { long t = 0; // Node control if (Node != null) { if (!(Node is SimulationTank)) // Check if node is a tank { return(tstep); } double h = _node.SimHead; // Current tank grade double q = _node.SimDemand; // Flow into tank if (Math.Abs(q) <= Constants.QZERO) { return(tstep); } if ((h < Grade && Type == ControlType.HILEVEL && q > 0.0) || // Tank below hi level & filling (h > Grade && Type == ControlType.LOWLEVEL && q < 0.0)) // Tank above low level & emptying { SimulationTank tank = (SimulationTank)Node; double v = tank.FindVolume(net.FieldsMap, Grade) - tank.SimVolume; t = (long)Math.Round(v / q); // Time to reach level } } // Time control if (Type == ControlType.TIMER) { if (Time > htime) { t = Time - htime; } } // Time-of-day control if (Type == ControlType.TIMEOFDAY) { long t1 = (htime + net.Tstart) % Constants.SECperDAY; long t2 = Time; if (t2 >= t1) { t = t2 - t1; } else { t = Constants.SECperDAY - t1 + t2; } } // Revise time step if (t > 0 && t < tstep) { SimulationLink link = Link; // Check if rule actually changes link status or setting if (link != null && (link.Type > LinkType.PIPE && link.SimSetting != Setting) || (link.SimStatus != Status)) { tstep = t; } } return(tstep); }
/// <summary>Adjusts settings of links controlled by junction pressures after a hydraulic solution is found.</summary> public static bool PSwitch( TraceSource log, EpanetNetwork net, IEnumerable <SimulationControl> controls) { bool anychange = false; foreach (SimulationControl control in controls) { bool reset = false; if (control.Link == null) { continue; } // Determine if control based on a junction, not a tank if (control.Node != null && !(control.Node is SimulationTank)) { // Determine if control conditions are satisfied if (control.Type == ControlType.LOWLEVEL && control.Node.SimHead <= control.Grade + net.HTol) { reset = true; } if (control.Type == ControlType.HILEVEL && control.Node.SimHead >= control.Grade - net.HTol) { reset = true; } } SimulationLink link = control.Link; // Determine if control forces a status or setting change if (reset) { bool change = false; StatType s = link.SimStatus; if (link.Type == LinkType.PIPE) { if (s != control.Status) { change = true; } } if (link.Type == LinkType.PUMP) { if (link.SimSetting != control.Setting) { change = true; } } if (link.Type >= LinkType.PRV) { if (link.SimSetting != control.Setting) { change = true; } else if (double.IsNaN(link.SimSetting) && s != control.Status) { change = true; } } // If a change occurs, update status & setting if (change) { link.SimStatus = control.Status; if (link.Type > LinkType.PIPE) { link.SimSetting = control.Setting; } if (net.StatFlag == StatFlag.FULL) { LogStatChange(log, net.FieldsMap, link, s); } anychange = true; } } } return(anychange); }
/// <summary>Implements simple controls based on time or tank levels.</summary> public static int StepActions( TraceSource log, EpanetNetwork net, IEnumerable <SimulationControl> controls, long htime) { int setsum = 0; // Examine each control statement foreach (SimulationControl control in controls) { bool reset = false; // Make sure that link is defined if (control.Link == null) { continue; } // Link is controlled by tank level var node = control.Node as SimulationTank; if (node != null) { double h = node.SimHead; double vplus = Math.Abs(node.SimDemand); SimulationTank tank = node; double v1 = tank.FindVolume(net.FieldsMap, h); double v2 = tank.FindVolume(net.FieldsMap, control.Grade); if (control.Type == ControlType.LOWLEVEL && v1 <= v2 + vplus) { reset = true; } if (control.Type == ControlType.HILEVEL && v1 >= v2 - vplus) { reset = true; } } // Link is time-controlled if (control.Type == ControlType.TIMER) { if (control.Time == htime) { reset = true; } } // Link is time-of-day controlled if (control.Type == ControlType.TIMEOFDAY) { if ((htime + net.Tstart) % Constants.SECperDAY == control.Time) { reset = true; } } // Update link status & pump speed or valve setting if (reset) { StatType s1, s2; SimulationLink link = control.Link; if (link.SimStatus <= StatType.CLOSED) { s1 = StatType.CLOSED; } else { s1 = StatType.OPEN; } s2 = control.Status; double k1 = link.SimSetting; double k2 = k1; if (control.Link.Type > LinkType.PIPE) { k2 = control.Setting; } if (s1 != s2 || k1 != k2) { link.SimStatus = s2; link.SimSetting = k2; if (net.StatFlag != StatFlag.NO) { LogControlAction(log, control, htime); } setsum++; } } } return(setsum); }
/// <summary>Checks if condition on system time holds.</summary> private bool CheckTime(EpanetNetwork net, long time1, long htime) { long t1, t2; switch (_variable) { case Varwords.TIME: t1 = time1; t2 = htime; break; case Varwords.CLOCKTIME: t1 = (time1 + net.Tstart) % Constants.SECperDAY; t2 = (htime + net.Tstart) % Constants.SECperDAY; break; default: return(false); } var x = (long)_value; switch (_relop) { case Operators.LT: if (t2 >= x) { return(false); } break; case Operators.LE: if (t2 > x) { return(false); } break; case Operators.GT: if (t2 <= x) { return(false); } break; case Operators.GE: if (t2 < x) { return(false); } break; case Operators.EQ: case Operators.NE: var flag = false; if (t2 < t1) { if (x >= t1 || x <= t2) { flag = true; } } else { if (x >= t1 && x <= t2) { flag = true; } } if (_relop == Operators.EQ && !flag) { return(true); } if (_relop == Operators.NE && flag) { return(true); } break; } return(true); }
/// <summary> /// Updates next time step by checking if any rules will fire before then; /// also updates tank levels. /// </summary> public static void MinimumTimeStep( EpanetNetwork net, TraceSource log, SimulationRule[] rules, List <SimulationTank> tanks, long htime, long tstep, double dsystem, out long tstepOut, out long htimeOut) { long dt; // Normal time increment for rule evaluation long dt1; // Actual time increment for rule evaluation // Find interval of time for rule evaluation long tnow = htime; // Start of time interval for rule evaluation long tmax = tnow + tstep; // End of time interval for rule evaluation //If no rules, then time increment equals current time step if (rules.Length == 0) { dt = tstep; dt1 = dt; } else { // Otherwise, time increment equals rule evaluation time step and // first actual increment equals time until next even multiple of // Rulestep occurs. dt = net.RuleStep; dt1 = net.RuleStep - tnow % net.RuleStep; } // Make sure time increment is no larger than current time step dt = Math.Min(dt, tstep); dt1 = Math.Min(dt1, tstep); if (dt1 == 0) { dt1 = dt; } // Step through time, updating tank levels, until either // a rule fires or we reach the end of evaluation period. // // Note: we are updating the global simulation time (Htime) // here because it is used by functions in RULES.C(this class) // to evaluate rules when checkrules() is called. // It is restored to its original value after the // rule evaluation process is completed (see below). // Also note that dt1 will equal dt after the first // time increment is taken. do { htime += dt1; // Update simulation clock SimulationTank.StepWaterLevels(tanks, net.FieldsMap, dt1); // Find new tank levels if (Check(net, rules, log, htime, dt1, dsystem) != 0) { break; // Stop if rules fire } dt = Math.Min(dt, tmax - htime); // Update time increment dt1 = dt; // Update actual increment }while (dt > 0); //Compute an updated simulation time step (*tstep) // and return simulation time to its original value tstepOut = htime - tnow; htimeOut = tnow; }
/// <summary>Write simulation summary to one worksheet.</summary> /// <param name="inpFile">Hydraulic network file name.</param> /// <param name="net">Hydraulic network.</param> /// <param name="msxFile">MSX file.</param> /// <param name="msx">MSX solver.</param> public void WriteSummary(string inpFile, EpanetNetwork net, string msxFile, EpanetMSX msx) { var sh = _sheet.NewSpreadsheet("Summary"); try { FieldsMap fMap = net.FieldsMap; if (net.Title != null) { for (int i = 0; i < net.Title.Count && i < 3; i++) { if (!string.IsNullOrEmpty(net.Title[i])) { sh.AddData( net.Title[i].Length > 70 ? net.Title[i].Substring(0, 70) : net.Title[i]); } } } sh.AddData("\n"); sh.AddData(Text.FMT19, inpFile); sh.AddData(Text.FMT20, net.Junctions.Count()); int nReservoirs = net.Reservoirs.Count(); int nTanks = net.Tanks.Count(); int nValves = net.Valves.Count(); int nPumps = net.Pumps.Count(); int nPipes = net.Links.Count - nPumps - nValves; sh.AddData(Text.FMT21a, nReservoirs); sh.AddData(Text.FMT21b, nTanks); sh.AddData(Text.FMT22, nPipes); sh.AddData(Text.FMT23, nPumps); sh.AddData(Text.FMT24, nValves); sh.AddData(Text.FMT25, net.FormFlag.ParseStr()); sh.AddData(Text.FMT26, net.HStep.GetClockTime()); sh.AddData(Text.FMT27, net.HAcc); sh.AddData(Text.FMT27a, net.CheckFreq); sh.AddData(Text.FMT27b, net.MaxCheck); sh.AddData(Text.FMT27c, net.DampLimit); sh.AddData(Text.FMT28, net.MaxIter); switch (net.Duration == 0 ? QualType.NONE : net.QualFlag) { case QualType.NONE: sh.AddData(Text.FMT29, "None"); break; case QualType.CHEM: sh.AddData(Text.FMT30, net.ChemName); break; case QualType.TRACE: sh.AddData(Text.FMT31, "Trace From Node", net.GetNode(net.TraceNode).Name); break; case QualType.AGE: sh.AddData(Text.FMT32, "Age"); break; } if (net.QualFlag != QualType.NONE && net.Duration > 0) { sh.AddData(Text.FMT33, "Time Step", net.QStep.GetClockTime()); sh.AddData( Text.FMT34, "Tolerance", fMap.RevertUnit(FieldType.QUALITY, net.Ctol), fMap.GetField(FieldType.QUALITY).Units); } sh.AddData(Text.FMT36, net.SpGrav); sh.AddData(Text.FMT37a, net.Viscos / Constants.VISCOS); sh.AddData(Text.FMT37b, net.Diffus / Constants.DIFFUS); sh.AddData(Text.FMT38, net.DMult); sh.AddData( Text.FMT39, fMap.RevertUnit(FieldType.TIME, net.Duration), fMap.GetField(FieldType.TIME).Units); if (msxFile != null && msx != null) { sh.AddData(""); sh.AddData("MSX data file", msxFile); sh.AddData("Species"); Species[] spe = msx.Network.Species; for (int i = 1; i < msx.Network.Species.Length; i++) { sh.AddData(spe[i].Id, spe[i].Units); } } } catch (IOException) {} catch (ENException e) { Debug.Print(e.ToString()); } }
/// <summary>Closes link flowing into full or out of empty tank.</summary> private void TankStatus(EpanetNetwork net) { double q = flow; SimulationNode n1 = First; SimulationNode n2 = Second; // Make node n1 be the tank if (!(n1 is SimulationTank)) { if (!(n2 is SimulationTank)) { return; // neither n1 or n2 is a tank } // N2 is a tank, swap ! SimulationNode n = n1; n1 = n2; n2 = n; q = -q; } double h = n1.SimHead - n2.SimHead; SimulationTank tank = (SimulationTank)n1; // Skip reservoirs & closed links if (tank.Area == 0.0 || status <= StatType.CLOSED) { return; } // If tank full, then prevent flow into it if (tank.SimHead >= tank.Hmax - net.HTol) { //Case 1: Link is a pump discharging into tank if (Type == LinkType.PUMP) { if (Second == n1) { status = StatType.TEMPCLOSED; } } else if (CvStatus(net, StatType.OPEN, h, q) == StatType.CLOSED) { // Case 2: Downstream head > tank head status = StatType.TEMPCLOSED; } } // If tank empty, then prevent flow out of it if (tank.SimHead <= tank.Hmin + net.HTol) { // Case 1: Link is a pump discharging from tank if (Type == LinkType.PUMP) { if (First == n1) { status = StatType.TEMPCLOSED; } } // Case 2: Tank head > downstream head else if (CvStatus(net, StatType.CLOSED, h, q) == StatType.OPEN) { status = StatType.TEMPCLOSED; } } }
/// <summary>Compute P, Y and matrix coeffs.</summary> private void ComputeMatrixCoeff( EpanetNetwork net, PipeHeadModelCalculators.Compute hlModel, IList <Curve> curves, SparseMatrix smat, LsVariables ls) { switch (Type) { // Pipes case LinkType.CV: case LinkType.PIPE: ComputePipeCoeff(net, hlModel); break; // Pumps case LinkType.PUMP: ((SimulationPump)this).ComputePumpCoeff(net); break; // Valves case LinkType.PBV: case LinkType.TCV: case LinkType.GPV: case LinkType.FCV: case LinkType.PRV: case LinkType.PSV: // If valve status fixed then treat as pipe // otherwise ignore the valve for now. if (!((SimulationValve)this).ComputeValveCoeff(net, curves)) { return; } break; default: return; } int n1 = first.Index; int n2 = second.Index; ls.AddNodalInFlow(n1, -flow); ls.AddNodalInFlow(n2, +flow); ls.AddAij(smat.GetNdx(Index), -invHeadLoss); if (!(first is SimulationTank)) { ls.AddAii(smat.GetRow(n1), +invHeadLoss); ls.AddRhsCoeff(smat.GetRow(n1), +flowCorrection); } else { ls.AddRhsCoeff(smat.GetRow(n2), +(invHeadLoss * first.SimHead)); } if (!(second is SimulationTank)) { ls.AddAii(smat.GetRow(n2), +invHeadLoss); ls.AddRhsCoeff(smat.GetRow(n2), -flowCorrection); } else { ls.AddRhsCoeff(smat.GetRow(n1), +(invHeadLoss * second.SimHead)); } }
public static void main(string[] args) { TraceSource log = new TraceSource(typeof(EPATool).FullName, SourceLevels.All); string hydFile = null; string qualFile = null; var net = new EpanetNetwork(); List <NodeVariableType> nodesVariables = new List <NodeVariableType>(); List <LinkVariableType> linksVariables = new List <LinkVariableType>(); string inFile = ""; List <long> targetTimes = new List <long>(); List <string> targetNodes = new List <string>(); List <string> targetLinks = new List <string>(); int parseMode = 0; foreach (string arg in args) { if (arg.EndsWith(".inp", StringComparison.OrdinalIgnoreCase)) { parseMode = 0; inFile = arg; if (!File.Exists(inFile)) { ConsoleLog("END_RUN_ERR"); Console.Error.WriteLine("File not found !"); return; } continue; } switch (arg) { case "-T": case "-t": parseMode = 1; continue; case "-N": case "-n": parseMode = 2; continue; case "-L": case "-l": parseMode = 3; continue; } switch (parseMode) { case 1: targetTimes.Add((long)(Utilities.GetHour(arg) * 3600)); break; case 2: targetNodes.Add(arg); break; case 3: targetLinks.Add(arg); break; } } try { InputParser parserInp = InputParser.Create(FileType.INP_FILE); net = parserInp.Parse(new EpanetNetwork(), inFile); if (targetTimes.Count > 0) { foreach (long time in targetTimes) { string epanetTime = time.GetClockTime(); if (time < net.RStart) { throw new Exception("Target time \"" + epanetTime + "\" smaller than simulation start time"); } if (time > net.Duration) { throw new Exception("Target time \"" + epanetTime + "\" bigger than simulation duration"); } if ((time - net.RStart) % net.RStep != 0) { throw new Exception("Target time \"" + epanetTime + "\" not found"); } } } foreach (string nodeName in targetNodes) { if (net.GetNode(nodeName) == null) { throw new Exception("Node \"" + nodeName + "\" not found"); } } foreach (string linkName in targetLinks) { if (net.GetLink(linkName) == null) { throw new Exception("Link \"" + linkName + "\" not found"); } } nodesVariables.Add(NodeVariableType.ELEVATION); nodesVariables.Add(NodeVariableType.BASEDEMAND); if (net.QualFlag != QualType.NONE) { nodesVariables.Add(NodeVariableType.INITQUALITY); } nodesVariables.Add(NodeVariableType.PRESSURE); nodesVariables.Add(NodeVariableType.HEAD); nodesVariables.Add(NodeVariableType.DEMAND); if (net.QualFlag != (QualType.NONE)) { nodesVariables.Add(NodeVariableType.QUALITY); } linksVariables.Add(LinkVariableType.LENGHT); linksVariables.Add(LinkVariableType.DIAMETER); linksVariables.Add(LinkVariableType.ROUGHNESS); linksVariables.Add(LinkVariableType.FLOW); linksVariables.Add(LinkVariableType.VELOCITY); linksVariables.Add(LinkVariableType.UNITHEADLOSS); linksVariables.Add(LinkVariableType.FRICTIONFACTOR); if (net.QualFlag != QualType.NONE) { linksVariables.Add(LinkVariableType.QUALITY); } hydFile = Path.GetTempFileName(); // "hydSim.bin" ConsoleLog("START_RUNNING"); HydraulicSim hydSim = new HydraulicSim(net, log); hydSim.Simulate(hydFile); if (net.QualFlag != QualType.NONE) { qualFile = Path.GetTempFileName(); // "qualSim.bin" QualitySim q = new QualitySim(net, log); q.Simulate(hydFile, qualFile); } HydraulicReader hydReader = new HydraulicReader(new BinaryReader(File.OpenRead(hydFile))); StreamWriter nodesTextWriter = null; StreamWriter linksTextWriter = null; string nodesOutputFile = null; if (targetNodes.Count == 0 && targetLinks.Count == 0 || targetNodes.Count > 0) { nodesOutputFile = Path.GetFullPath(inFile) + ".nodes.out"; nodesTextWriter = new StreamWriter(nodesOutputFile, false, Encoding.UTF8); nodesTextWriter.Write('\t'); foreach (NodeVariableType nodeVar in nodesVariables) { nodesTextWriter.Write('\t'); nodesTextWriter.Write(nodeVar.ToString()); } nodesTextWriter.Write("\n\t"); foreach (NodeVariableType nodeVar in nodesVariables) { nodesTextWriter.Write('\t'); nodesTextWriter.Write(net.FieldsMap.GetField(ToFieldType(nodeVar)).Units); } nodesTextWriter.Write('\n'); } if (targetNodes.Count == 0 && targetLinks.Count == 0 || targetLinks.Count > 0) { string linksOutputFile = Path.GetFullPath(inFile) + ".links.out"; linksTextWriter = new StreamWriter(linksOutputFile, false, Encoding.UTF8); linksTextWriter.Write('\t'); foreach (LinkVariableType linkVar in linksVariables) { linksTextWriter.Write('\t'); linksTextWriter.Write(linkVar.ToString()); } linksTextWriter.Write("\n\t"); foreach (LinkVariableType linkVar in linksVariables) { linksTextWriter.Write('\t'); if (linkVar < 0) { continue; } linksTextWriter.Write(net.FieldsMap.GetField((FieldType)linkVar).Units); } linksTextWriter.Write('\n'); } for (long time = net.RStart; time <= net.Duration; time += net.RStep) { AwareStep step = hydReader.GetStep((int)time); int i = 0; if (targetTimes.Count > 0 && !targetTimes.Contains(time)) { continue; } if (nodesTextWriter != null) { foreach (Node node in net.Nodes) { if (targetNodes.Count > 0 && !targetNodes.Contains(node.Name)) { continue; } nodesTextWriter.Write(node.Name); nodesTextWriter.Write('\t'); nodesTextWriter.Write(time.GetClockTime()); foreach (NodeVariableType nodeVar in nodesVariables) { nodesTextWriter.Write('\t'); double val = GetNodeValue(nodeVar, net.FieldsMap, step, node, i); nodesTextWriter.Write(ConvertToScientifcNotation(val, 1000, 0.01, 2)); } nodesTextWriter.Write('\n'); i++; } } i = 0; if (linksTextWriter != null) { foreach (Link link in net.Links) { if (targetLinks.Count > 0 && !targetLinks.Contains(link.Name)) { continue; } linksTextWriter.Write(link.Name); linksTextWriter.Write('\t'); linksTextWriter.Write(time.GetClockTime()); foreach (LinkVariableType linkVar in linksVariables) { linksTextWriter.Write('\t'); double val = GetLinkValue( linkVar, net.FormFlag, net.FieldsMap, step, link, i); linksTextWriter.Write(ConvertToScientifcNotation(val, 1000, 0.01, 2)); } linksTextWriter.Write('\n'); i++; } } } if (nodesTextWriter != null) { nodesTextWriter.Close(); ConsoleLog("NODES FILE \"" + nodesOutputFile + "\""); } if (linksTextWriter != null) { linksTextWriter.Close(); ConsoleLog("LINKS FILES \"" + nodesOutputFile + "\""); } ConsoleLog("END_RUN_OK"); } catch (ENException e) { ConsoleLog("END_RUN_ERR"); Debug.Print(e.ToString()); } catch (IOException e) { ConsoleLog("END_RUN_ERR"); Debug.Print(e.ToString()); } catch (Exception e) { ConsoleLog("END_RUN_ERR"); Debug.Print(e.ToString()); } if (!string.IsNullOrEmpty(hydFile)) { File.Delete(hydFile); } if (!string.IsNullOrEmpty(qualFile)) { File.Delete(qualFile); } }
public EnToolkit2(EpanetNetwork net) { _net = net; _links = net.Links; _nodes = net.Nodes; }