using IStation.Epanet.Enums;
using IStation.Epanet.Log;
using IStation.Epanet.Network.Structures;
using IStation.Epanet.Util;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace IStation.Epanet.Network.IO.Input
{
///INP parser class.
public class InpParser : InputParser
{
private SectType _sect = (SectType)(-1);
private readonly List _tok = new List(Constants.MAXTOKS);
private string _comment;
private string _line;
private Rule _currentRule; // Current rule
private static readonly string[] optionValueKeywords = {
Keywords.w_TOLERANCE, Keywords.w_DIFFUSIVITY, Keywords.w_DAMPLIMIT, Keywords.w_VISCOSITY,
Keywords.w_SPECGRAV, Keywords.w_TRIALS, Keywords.w_ACCURACY, Keywords.w_HTOL,
Keywords.w_QTOL, Keywords.w_RQTOL, Keywords.w_CHECKFREQ, Keywords.w_MAXCHECK,
Keywords.w_EMITTER, Keywords.w_DEMAND
};
public InpParser()
{
_currentRule = null;
}
public override Network Parse(Network nw, string fileName)
{
if (string.IsNullOrEmpty(fileName))
throw new ArgumentNullException(nameof(fileName));
net = nw ?? new Network();
try
{
using (FileStream fs = File.OpenRead(fileName))
{
//Parse demands and time patterns first
//Ê×ÏȽâÎöÐèÇóºÍʱ¼äģʽ
ParsePc(fs);
fs.Position = 0;
Parse(fs);
if (errors.Count > 0)
throw new EnException(ErrorCode.Err200);
}
}
catch (IOException ex)
{
throw new EnException(ErrorCode.Err302, ex);
}
AdjustData(net);
net.FieldsMap.Prepare(net.UnitsFlag, net.FlowFlag, net.PressFlag, net.QualFlag, net.ChemUnits, net.SpGrav, net.HStep);
Convert();
return net;
}
/// Parse demands and time patterns first.
///
private void ParsePc(Stream stream)
{
var buffReader = new StreamReader(stream, Encoding.Default);
while ((_line = buffReader.ReadLine()) != null)
{
_line = _line.Trim();
if (string.IsNullOrEmpty(_line))
continue;
if (_line[0] == '[')
{
if (_line.StartsWith("[PATTERNS]", StringComparison.OrdinalIgnoreCase))
{
_sect = SectType.PATTERNS;
}
else if (_line.StartsWith("[CURVES]", StringComparison.OrdinalIgnoreCase))
_sect = SectType.CURVES;
else
_sect = (SectType)(-1);
continue;
}
if (_sect != (SectType)(-1))
{
if (_line.IndexOf(';') >= 0)
_line = _line.Substring(0, _line.IndexOf(';'));
if (string.IsNullOrEmpty(_line))
continue;
if (GetTokens(_line, _tok) == 0)
continue;
try
{
switch (_sect)
{
case SectType.PATTERNS:
ParsePattern();
break;
case SectType.CURVES:
ParseCurve();
break;
}
}
catch (InputException ex)
{
LogException(ex);
}
}
}
}
// Parse INP file
private void Parse(Stream stream)
{
_sect = (SectType)(-1);
TextReader reader = new StreamReader(stream, Encoding.Default); // "ISO-8859-1";
while ((_line = reader.ReadLine()) != null)
{
if (_line.Length > Constants.MAXLINE)
LogException(new EnException(ErrorCode.Err214, _sect, _line));
_comment = null;
int index = _line.IndexOf(';');
if (index >= 0)
{
if (index > 0)
_comment = _line.Substring(index + 1).Trim();
_line = _line.Substring(0, index);
}
//lineCount++;
_line = _line.Trim();
if (string.IsNullOrEmpty(_line))
continue;
if (GetTokens(_line, _tok) == 0)
continue;
if (_tok[0][0] == '[')
{
_sect = FindSectionType(_tok[0]);
if (_sect < 0)
{
log.Warning("Unknown section type: " + _tok[0]);
}
if (_sect == SectType.END)
break;
continue;
}
if (_sect < 0) continue;
try
{
NewLine();
}
catch (InputException ex)
{
LogException(ex);
}
}
}
private void NewLine()
{
switch (_sect)
{
case SectType.TITLE:
ParseTitle();
break;
case SectType.JUNCTIONS:
ParseJunction();
break;
case SectType.RESERVOIRS:
ParseReservoir();
break;
case SectType.TANKS:
ParseTank();
break;
case SectType.PIPES:
ParsePipe();
break;
case SectType.PUMPS:
ParsePump();
break;
case SectType.VALVES:
ParseValve();
break;
case SectType.PATTERNS:
//ParsePattern();
break;
case SectType.CURVES:
//ParseCurve();
break;
case SectType.DEMANDS:
ParseDemand();
break;
case SectType.CONTROLS:
ParseControl();
break;
case SectType.RULES:
ParseRule(); /* See RULES.C */
break;
case SectType.SOURCES:
ParseSource();
break;
case SectType.EMITTERS:
ParseEmitter();
break;
case SectType.QUALITY:
ParseQuality();
break;
case SectType.STATUS:
ParseStatus();
break;
case SectType.ROUGHNESS:
break;
case SectType.ENERGY:
ParseEnergy();
break;
case SectType.REACTIONS:
ParseReaction();
break;
case SectType.MIXING:
ParseMixing();
break;
case SectType.REPORT:
ParseReport();
break;
case SectType.TIMES:
ParseTime();
break;
case SectType.OPTIONS:
ParseOption();
break;
/* Data in these sections are not used for any computations */
case SectType.COORDINATES:
ParseCoordinate();
break;
case SectType.LABELS:
ParseLabel();
break;
case SectType.TAGS:
ParseTag();
break;
case SectType.VERTICES:
ParseVertice();
break;
case SectType.BACKDROP:
break;
default:
throw new InputException(ErrorCode.Err201, _sect, _line);
}
}
/// Mimics C atol function behavior
private static bool Atol(string s, out int value)
{
if (string.IsNullOrEmpty(s))
{
value = 0;
return false;
}
int i = 0;
foreach (char c in s)
{
if (c != '-' && c != '+' && !char.IsWhiteSpace(c)) break;
i++;
}
while (i < s.Length)
{
if (!char.IsNumber(s[i]))
break;
i++;
}
return int.TryParse(s.Substring(0, i), out value);
}
private void ParseTitle()
{
if (net.Title.Count >= 3) return;
string s = _line.Length > Constants.MAXMSG
? _line.Substring(0, Constants.MAXMSG)
: _line;
net.Title.Add(s);
}
private void ParseJunction()
{
int n = _tok.Count;
double y = 0.0d;
Pattern p = null;
if (net.GetNode(_tok[0]) != null)
throw new InputException(ErrorCode.Err215, SectType.JUNCTIONS, _tok[0]);
Node node = new Junction(_tok[0]);
net.Nodes.Add(node);
if (n < 2)
throw new InputException(ErrorCode.Err201, SectType.JUNCTIONS, _line);
if (!_tok[1].ToDouble(out double el))
throw new InputException(ErrorCode.Err202, SectType.JUNCTIONS, _tok[0]);
if (n >= 3 && !_tok[2].ToDouble(out y))
throw new InputException(ErrorCode.Err202, SectType.JUNCTIONS, _tok[0]);
if (n >= 4)
{
p = net.GetPattern(_tok[3]);
if (p == null)
{
throw new InputException(ErrorCode.Err205, SectType.JUNCTIONS, _tok[0]);
}
}
node.Elevation = el;
node.C0 = 0.0;
node.QualSource = null;
node.Ke = 0.0;
node.RptFlag = false;
if (!string.IsNullOrEmpty(_comment))
node.Comment = _comment;
if (n >= 3)
{
node.PrimaryDemand.Base = y;
node.PrimaryDemand.Pattern = p;
}
}
private void ParseReservoir()
{
int n = _tok.Count;
Pattern p = null;
if (net.GetNode(_tok[0]) != null)
throw new InputException(ErrorCode.Err215, SectType.TANKS, _tok[0]);
Reservoir reservoir = new Reservoir(_tok[0]);
if (!string.IsNullOrEmpty(_comment))
reservoir.Comment = _comment;
net.Nodes.Add(reservoir);
if (n < 2)
throw new InputException(ErrorCode.Err201, SectType.REACTIONS, _line);
if (!_tok[1].ToDouble(out double head))
throw new InputException(ErrorCode.Err202, SectType.REACTIONS, _tok[0]);
if (n == 3)
{
p = net.GetPattern(_tok[2]);
if (p == null)
{
throw new InputException(ErrorCode.Err205, SectType.REACTIONS, _tok[0]);
}
}
reservoir.RptFlag = false;
reservoir.Elevation = 0.0;
reservoir.C0 = 0.0;
reservoir.QualSource = null;
reservoir.Ke = 0.0;
reservoir.Head = head;
reservoir.Pattern = p;
}
private void ParseTank()
{
int n = _tok.Count;
Pattern p = null;
Curve vcurve = null;
double initlevel = 0.0d,
minlevel = 0.0d,
maxlevel = 0.0d,
minvol = 0.0d,
diam = 0.0d;
if (net.GetNode(_tok[0]) != null)
throw new InputException(ErrorCode.Err215, SectType.TANKS, _tok[0]);
Tank tank = new Tank(_tok[0]);
if (!string.IsNullOrEmpty(_comment))
tank.Comment = _comment;
net.Nodes.Add(tank);
if (n < 2)
throw new InputException(ErrorCode.Err201, SectType.TANKS, _line);
if (!_tok[1].ToDouble(out double el))
throw new InputException(ErrorCode.Err202, SectType.TANKS, _tok[0]);
if (n <= 3)
{
/* Tank is reservoir.*/
if (n == 3)
{
p = net.GetPattern(_tok[2]);
if (p == null)
{
throw new InputException(ErrorCode.Err205, SectType.TANKS, _tok[0]);
}
}
}
else if (n < 6)
{
throw new InputException(ErrorCode.Err201, SectType.TANKS, _line);
}
else
{
/* Check for valid input data */
if (!_tok[2].ToDouble(out initlevel) ||
!_tok[3].ToDouble(out minlevel) ||
!_tok[4].ToDouble(out maxlevel) ||
!_tok[5].ToDouble(out diam) ||
diam < 0.0)
throw new InputException(ErrorCode.Err202, SectType.TANKS, _tok[0]);
if (n >= 7 && !_tok[6].ToDouble(out minvol))
throw new InputException(ErrorCode.Err202, SectType.TANKS, _tok[0]);
if (n == 8)
{
vcurve = net.GetCurve(_tok[7]);
if (vcurve == null)
throw new InputException(ErrorCode.Err206, SectType.TANKS, _tok[0]);
}
}
tank.RptFlag = false;
tank.Elevation = el;
tank.C0 = 0.0;
tank.QualSource = null;
tank.Ke = 0.0;
tank.H0 = initlevel;
tank.Hmin = minlevel;
tank.Hmax = maxlevel;
tank.Area = diam;
tank.Pattern = p;
tank.Kb = double.NaN;
/*
*******************************************************************
NOTE: The min, max, & initial volumes set here are based on a
nominal tank diameter. They will be modified in INPUT1.C if
a volume curve is supplied for this tank.
*******************************************************************
*/
double area = Math.PI * diam * diam / 4.0d;
tank.Vmin = area * minlevel;
if (minvol > 0.0) tank.Vmin = minvol;
tank.V0 = tank.Vmin + area * (initlevel - minlevel);
tank.Vmax = tank.Vmin + area * (maxlevel - minlevel);
tank.Vcurve = vcurve;
tank.MixModel = MixType.Mix1;
tank.V1Max = 1.0;
}
private void ParsePipe()
{
StatusType status = StatusType.OPEN;
double lcoeff = 0.0d;
if (net.GetLink(_tok[0]) != null)
throw new InputException(ErrorCode.Err215, SectType.PIPES, _tok[0]);
Pipe pipe = new Pipe(_tok[0]);
net.Links.Add(pipe);
if (_tok.Count < 6)
throw new InputException(ErrorCode.Err201, SectType.PIPES, _line);
Node j1 = net.GetNode(_tok[1]),
j2 = net.GetNode(_tok[2]);
if (j1 == null || j2 == null)
throw new InputException(ErrorCode.Err203, SectType.PIPES, _tok[0]);
if (j1.Equals(j2))
throw new InputException(ErrorCode.Err222, SectType.PIPES, _tok[0]);
if (!_tok[3].ToDouble(out double length) || length <= 0.0 ||
!_tok[4].ToDouble(out double diam) || diam <= 0.0 ||
!_tok[5].ToDouble(out double rcoeff) || rcoeff <= 0.0)
throw new InputException(ErrorCode.Err202, SectType.PIPES, _tok[0]);
if (_tok.Count == 7)
{
if (_tok[6].Match(Keywords.w_CV)) pipe.HasCheckValve = true;
else if (_tok[6].Match(Keywords.w_CLOSED)) status = StatusType.CLOSED;
else if (_tok[6].Match(Keywords.w_OPEN)) status = StatusType.OPEN;
else if (!_tok[6].ToDouble(out lcoeff) || lcoeff < 0)
throw new InputException(ErrorCode.Err202, SectType.PIPES, _tok[0]);
}
if (_tok.Count == 8)
{
if (!_tok[6].ToDouble(out lcoeff) || lcoeff < 0)
throw new InputException(ErrorCode.Err202, SectType.PIPES, _tok[0]);
if (_tok[7].Match(Keywords.w_CV)) pipe.HasCheckValve = true;
else if (_tok[7].Match(Keywords.w_CLOSED)) status = StatusType.CLOSED;
else if (_tok[7].Match(Keywords.w_OPEN)) status = StatusType.OPEN;
else
throw new InputException(ErrorCode.Err202, SectType.PIPES, _tok[0]);
}
pipe.FirstNode = j1;
pipe.SecondNode = j2;
pipe.Lenght = length;
pipe.Diameter = diam;
pipe.Kc = rcoeff;
pipe.Km = lcoeff;
pipe.Kb = double.NaN;
pipe.Kw = double.NaN;
pipe.Status = status;
pipe.RptFlag = false;
if (!string.IsNullOrEmpty(_comment))
pipe.Comment = _comment;
}
private void ParsePump()
{
int m;
double[] x = new double[6];
if (net.GetLink(_tok[0]) != null)
throw new InputException(ErrorCode.Err215, SectType.PUMPS, _tok[0]);
if (_tok.Count < 4)
throw new InputException(ErrorCode.Err201, SectType.PUMPS, _line);
Node j1 = net.GetNode(_tok[1]),
j2 = net.GetNode(_tok[2]);
if (j1 == null || j2 == null)
throw new InputException(ErrorCode.Err203, SectType.PUMPS, _tok[0]);
if (j1.Equals(j2))
throw new InputException(ErrorCode.Err222, SectType.PUMPS, _tok[0]);
Pump pump = new Pump(_tok[0])
{
FirstNode = j1,
SecondNode = j2,
};
net.Links.Add(pump);
if (!string.IsNullOrEmpty(_comment)) pump.Comment = _comment;
// If 4-th token is a number then input follows Version 1.x format
// so retrieve pump curve parameters
if (_tok[3].ToDouble(out x[0]))
{
m = 1;
for (int j = 4; j < _tok.Count; j++)
{
if (!_tok[j].ToDouble(out x[m]))
throw new InputException(ErrorCode.Err202, SectType.PUMPS, _tok[0]);
m++;
}
GetPumpCurve(pump, m, x); /* Get pump curve params */
return;
}
/* Otherwise input follows Version 2 format */
/* so retrieve keyword/value pairs. */
m = 4;
while (m < _tok.Count)
{
if (_tok[m - 1].Match(Keywords.w_POWER))
{ /* Const. HP curve */
if (!_tok[m].ToDouble(out double y) || y <= 0.0)
throw new InputException(ErrorCode.Err202, SectType.PUMPS, _tok[0]);
pump.Ptype = PumpType.CONST_HP;
pump.Km = y;
}
else if (_tok[m - 1].Match(Keywords.w_HEAD))
{ /* Custom pump curve */
Curve t = net.GetCurve(_tok[m]);
if (t == null)
throw new InputException(ErrorCode.Err206, SectType.PUMPS, _tok[0]);
pump.HCurve = t;
}
else if (_tok[m - 1].Match(Keywords.w_PATTERN))
{ /* Speed/status pattern */
Pattern p = net.GetPattern(_tok[m]);
if (p == null)
throw new InputException(ErrorCode.Err205, SectType.PUMPS, _tok[0]);
pump.UPat = p;
}
else if (_tok[m - 1].Match(Keywords.w_SPEED))
{ /* Speed setting */
if (!_tok[m].ToDouble(out double y) || y < 0.0)
throw new InputException(ErrorCode.Err202, SectType.PUMPS, _tok[0]);
pump.Kc = y;
}
else
{
throw new InputException(ErrorCode.Err201, SectType.PUMPS, _line);
}
m += 2;
}
}
private void ParseValve()
{
int n = _tok.Count;
StatusType status = StatusType.ACTIVE;
string key = _tok[0];
double setting, lcoeff = 0.0;
if (net.GetLink(key) != null)
throw new InputException(ErrorCode.Err215, SectType.VALVES, _tok[0]);
if (n < 6)
throw new InputException(ErrorCode.Err201, SectType.VALVES, _line);
Node j1 = net.GetNode(_tok[1]),
j2 = net.GetNode(_tok[2]);
if (j1 == null || j2 == null)
throw new InputException(ErrorCode.Err203, SectType.VALVES, _tok[0]);
if (j1.Equals(j2))
throw new InputException(ErrorCode.Err222, SectType.VALVES, _tok[0]);
if (!_tok[4].TryParse(out ValveType type))
throw new InputException(ErrorCode.Err201, SectType.VALVES, _line);
if (!_tok[3].ToDouble(out double diam) || diam <= 0.0)
throw new InputException(ErrorCode.Err202, SectType.VALVES, _tok[0]);
Valve valve = new Valve(key, type);
net.Links.Add(valve);
if (type == ValveType.GPV)
{
Curve t = net.GetCurve(_tok[5]);
if (t == null)
throw new InputException(ErrorCode.Err206, SectType.VALVES, _tok[0]);
setting = net.Curves.IndexOf(t);
log.Warning("GPV Valve, index as roughness !");
valve.Curve = t;
status = StatusType.OPEN;
}
else if (!_tok[5].ToDouble(out setting))
{
throw new InputException(ErrorCode.Err202, SectType.VALVES, _tok[0]);
}
if (n >= 7)
{
if (!_tok[6].ToDouble(out lcoeff))
{
throw new InputException(ErrorCode.Err202, SectType.VALVES, _tok[0]);
}
}
if (j1.NodeType > NodeType.Junction || j2.NodeType > NodeType.Junction)
{
if (type == ValveType.PRV || type == ValveType.PSV || type == ValveType.FCV)
throw new InputException(ErrorCode.Err219, SectType.VALVES, _tok[0]);
}
if (!Valvecheck(net, type, j1, j2))
throw new InputException(ErrorCode.Err220, SectType.VALVES, _tok[0]);
valve.FirstNode = j1;
valve.SecondNode = j2;
valve.Diameter = diam;
valve.Lenght = 0.0d;
valve.Kc = setting;
valve.Km = lcoeff;
valve.Kb = 0.0d;
valve.Kw = 0.0d;
valve.Status = status;
valve.RptFlag = false;
if (!string.IsNullOrEmpty(_comment))
valve.Comment = _comment;
}
private void ParsePattern()
{
Pattern pat = net.GetPattern(_tok[0]);
if (pat == null)
{
pat = new Pattern(_tok[0]);
net.Patterns.Add(pat);
}
for (int i = 1; i < _tok.Count; i++)
{
if (!_tok[i].ToDouble(out double x))
throw new InputException(ErrorCode.Err202, SectType.PATTERNS, _tok[0]);
pat.Add(x);
}
}
private void ParseCurve()
{
Curve cur = net.GetCurve(_tok[0]);
if (cur == null)
{
cur = new Curve(_tok[0]);
net.Curves.Add(cur);
}
if (!_tok[1].ToDouble(out double x) || !_tok[2].ToDouble(out double y))
throw new InputException(ErrorCode.Err202, SectType.CURVES, _tok[0]);
cur.Add(x, y);
}
private void ParseCoordinate()
{
if (_tok.Count < 3)
throw new InputException(ErrorCode.Err201, SectType.COORDINATES, _line);
Node node = net.GetNode(_tok[0]);
if (node == null)
throw new InputException(ErrorCode.Err203, SectType.COORDINATES, _tok[0]);
if (!_tok[1].ToDouble(out double x) || !_tok[2].ToDouble(out double y))
throw new InputException(ErrorCode.Err202, SectType.COORDINATES, _tok[0]);
node.Coordinate = new EnPoint(x, y);
}
private void ParseLabel()
{
if (_tok.Count < 3)
throw new InputException(ErrorCode.Err201, SectType.LABELS, _line);
if (!_tok[0].ToDouble(out double x) || !_tok[1].ToDouble(out double y))
throw new InputException(ErrorCode.Err201, SectType.LABELS, _line);
string text = _tok[2].Replace("\"", "");
Label label = new Label(text)
{
Position = new EnPoint(x, y)
};
net.Labels.Add(label);
}
private void ParseVertice()
{
if (_tok.Count < 3)
throw new InputException(ErrorCode.Err201, SectType.VERTICES, _line);
Link link = net.GetLink(_tok[0]);
if (link == null)
throw new InputException(ErrorCode.Err204, SectType.VERTICES, _tok[0]);
if (!_tok[1].ToDouble(out double x) || !_tok[2].ToDouble(out double y))
throw new InputException(ErrorCode.Err202, SectType.VERTICES, _tok[0]);
link.Vertices.Add(new EnPoint(x, y));
}
private void ParseControl()
{
StatusType status = StatusType.ACTIVE;
double setting = double.NaN, level = 0.0;
TimeSpan time = TimeSpan.Zero;
if (_tok.Count < 6)
throw new InputException(ErrorCode.Err201, SectType.CONTROLS, _line);
Node node = null;
Link link = net.GetLink(_tok[1]);
if (link == null)
throw new InputException(ErrorCode.Err204, SectType.CONTROLS, _line);
LinkType ltype = link.LinkType;
if (link.LinkType == LinkType.Pipe && ((Pipe)link).HasCheckValve)
throw new InputException(ErrorCode.Err207, SectType.CONTROLS, _line);
if (_tok[2].Match(StatusType.OPEN.Keyword2()))
{
status = StatusType.OPEN;
switch (link.LinkType)
{
case LinkType.Pump:
setting = 1.0;
break;
case LinkType.VALVE:
if (((Valve)link).ValveType == ValveType.GPV)
setting = link.Kc;
break;
}
}
else if (_tok[2].Match(StatusType.CLOSED.Keyword2()))
{
status = StatusType.CLOSED;
switch (link.LinkType)
{
case LinkType.Pump:
setting = 0.0;
break;
case LinkType.VALVE:
if (((Valve)link).ValveType == ValveType.GPV)
setting = link.Kc;
break;
}
}
else if (ltype == LinkType.VALVE && ((Valve)link).ValveType == ValveType.GPV)
{
throw new InputException(ErrorCode.Err206, SectType.CONTROLS, _line);
}
else if (!_tok[2].ToDouble(out setting))
{
throw new InputException(ErrorCode.Err202, SectType.CONTROLS, _line);
}
if (ltype == LinkType.Pump || ltype == LinkType.Pipe)
{
if (!double.IsNaN(setting))
{
if (setting < 0.0)
throw new InputException(ErrorCode.Err202, SectType.CONTROLS, _line);
status = setting.IsZero() ? StatusType.CLOSED : StatusType.OPEN;
}
}
ControlType ctype;
if (_tok[4].Match(Keywords.w_TIME))
ctype = ControlType.Timer;
else if (_tok[4].Match(Keywords.w_CLOCKTIME))
ctype = ControlType.TimeOfDay;
else
{
if (_tok.Count < 8)
throw new InputException(ErrorCode.Err201, SectType.CONTROLS, _line);
if ((node = net.GetNode(_tok[5])) == null)
throw new InputException(ErrorCode.Err203, SectType.CONTROLS, _line);
if (_tok[6].Match(Keywords.w_BELOW)) ctype = ControlType.LowLevel;
else if (_tok[6].Match(Keywords.w_ABOVE)) ctype = ControlType.HiLevel;
else
throw new InputException(ErrorCode.Err201, SectType.CONTROLS, _line);
}
switch (ctype)
{
case ControlType.Timer:
case ControlType.TimeOfDay:
time = _tok.Count > 6
? Utilities.ToTimeSpan(_tok[5], _tok[6])
: Utilities.ToTimeSpan(_tok[5]);
if (time == TimeSpan.MinValue)
throw new InputException(ErrorCode.Err201, SectType.CONTROLS, _line);
break;
case ControlType.LowLevel:
case ControlType.HiLevel:
if (!_tok[7].ToDouble(out level))
throw new InputException(ErrorCode.Err202, SectType.CONTROLS, _line);
break;
}
Control cntr = new Control
{
Link = link,
Node = node,
Type = ctype,
Status = status,
Setting = setting,
Time = ctype == ControlType.TimeOfDay ? time.TimeOfDay() : time,
Grade = level
};
net.Controls.Add(cntr);
}
private void ParseSource()
{
int n = _tok.Count;
Pattern pat = null;
if (n < 2)
throw new InputException(ErrorCode.Err201, SectType.SOURCES, _line);
Node node = net.GetNode(_tok[0]);
if (node == null)
throw new InputException(ErrorCode.Err203, SectType.SOURCES, _tok[0]);
/* NOTE: Under old format, SourceType not supplied so let */
/* i = index of token that contains quality value. */
int i = 2; /* Token with quality value */
if (!_tok[1].TryParse(out SourceType type))
{
i = 1;
type = SourceType.Concen;
}
if (!_tok[i].ToDouble(out double c0))
{
/* Illegal WQ value */
throw new InputException(ErrorCode.Err202, SectType.SOURCES, _tok[0]);
}
if (n > i + 1 && !string.IsNullOrEmpty(_tok[i + 1]) && _tok[i + 1] != "*")
{
if ((pat = net.GetPattern(_tok[i + 1])) == null)
throw new InputException(ErrorCode.Err205, SectType.SOURCES, _tok[0]);
}
node.QualSource = new QualSource(type, c0, pat);
}
private void ParseEmitter()
{
int n = _tok.Count;
Node node;
if (n < 2) throw
new InputException(ErrorCode.Err201, SectType.EMITTERS, _line);
if ((node = net.GetNode(_tok[0])) == null)
throw new InputException(ErrorCode.Err203, SectType.EMITTERS, _tok[0]);
if (node.NodeType != NodeType.Junction)
throw new InputException(ErrorCode.Err209, SectType.EMITTERS, _tok[0]);
if (!_tok[1].ToDouble(out double k) || k < 0.0)
throw new InputException(ErrorCode.Err202, SectType.EMITTERS, _tok[0]);
node.Ke = k;
}
private void ParseQuality()
{
int n = _tok.Count;
double c0;
if (n < 2) return;
/* Single node entered */
if (n == 2)
{
Node node = net.GetNode(_tok[0]);
if (node == null) return;
if (!_tok[1].ToDouble(out c0))
throw new InputException(ErrorCode.Err209, SectType.QUALITY, _tok[0]);
node.C0 = c0;
}
else
{
/* Node range entered */
if (!_tok[2].ToDouble(out c0))
throw new InputException(ErrorCode.Err209, SectType.QUALITY, _tok[0]);
/* If numerical range supplied, then use numerical comparison */
if (Atol(_tok[0], out int i0) && Atol(_tok[1], out int i1))
{
foreach (Node node in net.Nodes)
{
if (Atol(node.Name, out int i) && i >= i0 && i <= i1)
node.C0 = c0;
}
}
else
{
foreach (Node node in net.Nodes)
{
if (string.Compare(_tok[0], node.Name, StringComparison.Ordinal) <= 0 &&
string.Compare(_tok[1], node.Name, StringComparison.Ordinal) >= 0)
node.C0 = c0;
}
}
}
}
private void ParseReaction()
{
int item, n = _tok.Count;
double y;
if (n < 3) return;
if (_tok[0].Match(Keywords.w_ORDER))
{ /* Reaction order */
if (!_tok[n - 1].ToDouble(out y))
throw new InputException(ErrorCode.Err213, SectType.REACTIONS, _line);
if (_tok[1].Match(Keywords.w_BULK)) net.BulkOrder = y;
else if (_tok[1].Match(Keywords.w_TANK)) net.TankOrder = y;
else if (_tok[1].Match(Keywords.w_WALL))
{
if (y.IsZero()) net.WallOrder = 0.0;
else if (y.EqualsTo(1.0)) net.WallOrder = 1.0;
else throw new InputException(ErrorCode.Err213, SectType.REACTIONS, _line);
}
else throw new InputException(ErrorCode.Err213, SectType.REACTIONS, _line);
return;
}
if (_tok[0].Match(Keywords.w_ROUGHNESS))
{ /* Roughness factor */
if (!_tok[n - 1].ToDouble(out y))
throw new InputException(ErrorCode.Err213, SectType.REACTIONS, _line);
net.RFactor = y;
return;
}
if (_tok[0].Match(Keywords.w_LIMITING))
{ /* Limiting potential */
if (!_tok[n - 1].ToDouble(out y))
throw new InputException(ErrorCode.Err213, SectType.REACTIONS, _line);
net.CLimit = y;
return;
}
if (_tok[0].Match(Keywords.w_GLOBAL))
{ /* Global rates */
if (!_tok[n - 1].ToDouble(out y))
throw new InputException(ErrorCode.Err213, SectType.REACTIONS, _line);
if (_tok[1].Match(Keywords.w_BULK)) net.KBulk = y;
else if (_tok[1].Match(Keywords.w_WALL)) net.KWall = y;
else throw new InputException(ErrorCode.Err201, SectType.REACTIONS, _line);
return;
}
/* Individual rates */
if (_tok[0].Match(Keywords.w_BULK)) item = 1;
else if (_tok[0].Match(Keywords.w_WALL)) item = 2;
else if (_tok[0].Match(Keywords.w_TANK)) item = 3;
else throw new InputException(ErrorCode.Err201, SectType.REACTIONS, _line);
_tok[0] = _tok[1];
if (item == 3)
{
/* Tank rates */
if (!_tok[n - 1].ToDouble(out y))
throw new InputException(ErrorCode.Err209, SectType.REACTIONS, _tok[1]);
if (n == 3)
{
Node node;
if ((node = net.GetNode(_tok[1])) == null)
throw new InputException(ErrorCode.Err208, SectType.REACTIONS, _tok[1]);
Tank tank = node as Tank;
if (tank == null) return;
tank.Kb = y;
}
else
{
/* If numerical range supplied, then use numerical comparison */
if (Atol(_tok[1], out int i1) && Atol(_tok[2], out int i2))
{
foreach (Tank tank in net.Tanks)
{
if (Atol(tank.Name, out int i) && i >= i1 && i <= i2)
tank.Kb = y;
}
}
else
{
foreach (Tank tank in net.Tanks)
{
if (string.Compare(_tok[1], tank.Name, StringComparison.Ordinal) <= 0 &&
string.Compare(_tok[2], tank.Name, StringComparison.Ordinal) >= 0)
tank.Kb = y;
}
}
}
}
else
{ /* Link rates */
if (!_tok[n - 1].ToDouble(out y))
throw new InputException(ErrorCode.Err211, SectType.REACTIONS, _tok[1]);
if (net.Links.Count == 0) return;
if (n == 3)
{ /* Single link */
Link link;
if ((link = net.GetLink(_tok[1])) == null) return;
if (item == 1) link.Kb = y;
else link.Kw = y;
}
else
{
/* Range of links */
/* If numerical range supplied, then use numerical comparison */
if (Atol(_tok[1], out int i1) && Atol(_tok[2], out int i2))
{
foreach (Link link in net.Links)
{
if (Atol(link.Name, out int i) && i >= i1 && i <= i2)
{
if (item == 1) link.Kb = y;
else link.Kw = y;
}
}
}
else
foreach (Link link in net.Links)
{
if (string.Compare(_tok[1], link.Name, StringComparison.Ordinal) <= 0 &&
string.Compare(_tok[2], link.Name, StringComparison.Ordinal) >= 0)
{
if (item == 1) link.Kb = y;
else link.Kw = y;
}
}
}
}
}
private void ParseMixing()
{
int n = _tok.Count;
if (net.Nodes.Count == 0)
throw new InputException(ErrorCode.Err208, SectType.MIXING, _tok[0]);
if (n < 2) return;
Node node = net.GetNode(_tok[0]);
if (node == null)
throw new InputException(ErrorCode.Err208, SectType.MIXING, _tok[0]);
if (node.NodeType != NodeType.Junction) return;
Tank tank = (Tank)node;
if (!_tok[1].TryParse(out MixType type))
throw new InputException(ErrorCode.Err201, SectType.MIXING, _line);
var v = 1.0;
if (type == MixType.Mix2 && n == 3)
{
if (!_tok[2].ToDouble(out v))
{
throw new InputException(ErrorCode.Err209, SectType.MIXING, _tok[0]);
}
}
if (v.IsZero())
v = 1.0;
if (tank.NodeType == NodeType.Reservoir) return;
tank.MixModel = type;
tank.V1Max = v;
}
private void ParseStatus()
{
int n = _tok.Count - 1;
double y = 0.0;
StatusType status = StatusType.ACTIVE;
if (net.Links.Count == 0)
throw new InputException(ErrorCode.Err210, SectType.STATUS, _tok[0]);
if (n < 1)
throw new InputException(ErrorCode.Err201, SectType.STATUS, _line);
if (_tok[n].Match(Keywords.w_OPEN)) status = StatusType.OPEN;
else if (_tok[n].Match(Keywords.w_CLOSED)) status = StatusType.CLOSED;
else if (!_tok[n].ToDouble(out y) || y < 0.0)
throw new InputException(ErrorCode.Err211, SectType.STATUS, _tok[0]);
if (n == 1)
{
Link link = net.GetLink(_tok[0]);
if (link == null) return;
switch (link.LinkType)
{
case LinkType.Pipe:
if (((Pipe)link).HasCheckValve)
throw new InputException(ErrorCode.Err211, SectType.STATUS, _tok[0]);
break;
case LinkType.VALVE:
if (((Valve)link).ValveType == ValveType.GPV && status == StatusType.ACTIVE)
throw new InputException(ErrorCode.Err211, SectType.STATUS, _tok[0]);
break;
}
ChangeStatus(link, status, y);
}
else
{
/* If numerical range supplied, then use numerical comparison */
if (Atol(_tok[0], out int i0) && Atol(_tok[1], out int i1))
{
foreach (Link link in net.Links)
{
if (Atol(link.Name, out int i) && i >= i0 && i <= i1)
ChangeStatus(link, status, y);
}
}
else
foreach (Link j in net.Links)
if (string.Compare(_tok[0], j.Name, StringComparison.Ordinal) <= 0 &&
string.Compare(_tok[1], j.Name, StringComparison.Ordinal) >= 0)
ChangeStatus(j, status, y);
}
}
private void ParseEnergy()
{
int n = _tok.Count;
double y;
if (n < 3)
throw new InputException(ErrorCode.Err201, SectType.ENERGY, _line);
if (_tok[0].Match(Keywords.w_DMNDCHARGE))
{
if (!_tok[2].ToDouble(out y))
throw new InputException(ErrorCode.Err213, SectType.ENERGY, _line);
net.DCost = y;
return;
}
Pump pump;
if (_tok[0].Match(Keywords.w_GLOBAL))
{
pump = null;
}
else if (_tok[0].Match(Keywords.w_PUMP))
{
if (n < 4)
throw new InputException(ErrorCode.Err201, SectType.ENERGY, _line);
Link link = net.GetLink(_tok[1]);
if (link == null || link.LinkType != LinkType.Pump)
throw new InputException(ErrorCode.Err216, SectType.ENERGY, _tok[0]);
pump = (Pump)link;
}
else
throw new InputException(ErrorCode.Err201, SectType.ENERGY, _line);
if (_tok[n - 2].Match(Keywords.w_PRICE))
{
if (!_tok[n - 1].ToDouble(out y))
{
throw pump == null
? new InputException(ErrorCode.Err213, SectType.ENERGY, _line)
: new InputException(ErrorCode.Err217, SectType.ENERGY, _tok[0]);
}
if (pump == null)
net.ECost = y;
else
pump.ECost = y;
return;
}
if (_tok[n - 2].Match(Keywords.w_PATTERN))
{
Pattern t = net.GetPattern(_tok[n - 1]);
if (t == null)
{
throw pump == null
? new InputException(ErrorCode.Err213, SectType.ENERGY, _line)
: new InputException(ErrorCode.Err217, SectType.ENERGY, _tok[0]);
}
if (pump == null)
net.EPatId = t.Name;
else
pump.EPat = t;
return;
}
if (_tok[n - 2].Match(Keywords.w_EFFIC))
{
if (pump == null)
{
if (!_tok[n - 1].ToDouble(out y) || y <= 0.0)
throw new InputException(ErrorCode.Err213, SectType.ENERGY, _line);
net.EPump = y;
}
else
{
Curve t = net.GetCurve(_tok[n - 1]);
if (t == null)
throw new InputException(ErrorCode.Err217, SectType.ENERGY, _tok[0]);
pump.ECurve = t;
}
return;
}
throw new InputException(ErrorCode.Err201, SectType.ENERGY, _line);
}
private void ParseReport()
{
int n = _tok.Count - 1;
//FieldType i;
double y;
if (n < 1)
throw new InputException(ErrorCode.Err201, SectType.REPORT, _line);
if (_tok[0].Match(Keywords.w_PAGE))
{
if (!_tok[n].ToDouble(out y))
throw new InputException(ErrorCode.Err213, SectType.REPORT, _line);
if (y < 0.0 || y > 255.0)
throw new InputException(ErrorCode.Err213, SectType.REPORT, _line);
net.PageSize = (int)y;
return;
}
if (_tok[0].Match(Keywords.w_STATUS))
{
if (_tok[n].TryParse(out StatusLevel flag))
{
net.StatFlag = flag;
}
return;
}
if (_tok[0].Match(Keywords.w_SUMMARY))
{
if (_tok[n].Match(Keywords.w_NO)) net.SummaryFlag = false;
if (_tok[n].Match(Keywords.w_YES)) net.SummaryFlag = true;
return;
}
if (_tok[0].Match(Keywords.w_MESSAGES))
{
if (_tok[n].Match(Keywords.w_NO)) net.MessageFlag = false;
if (_tok[n].Match(Keywords.w_YES)) net.MessageFlag = true;
return;
}
if (_tok[0].Match(Keywords.w_ENERGY))
{
if (_tok[n].Match(Keywords.w_NO)) net.EnergyFlag = false;
if (_tok[n].Match(Keywords.w_YES)) net.EnergyFlag = true;
return;
}
if (_tok[0].Match(Keywords.w_NODE))
{
if (_tok[n].Match(Keywords.w_NONE))
{
net.NodeFlag = ReportFlag.FALSE;
}
else if (_tok[n].Match(Keywords.w_ALL))
{
net.NodeFlag = ReportFlag.TRUE;
}
else
{
if (net.Nodes.Count == 0)
throw new InputException(ErrorCode.Err208, SectType.REPORT, _tok[1]);
for (int i = 1; i <= n; i++)
{
Node node = net.GetNode(_tok[i]);
if (node == null)
throw new InputException(ErrorCode.Err208, SectType.REPORT, _tok[i]);
node.RptFlag = true;
}
net.NodeFlag = ReportFlag.SOME;
}
return;
}
if (_tok[0].Match(Keywords.w_LINK))
{
if (_tok[n].Match(Keywords.w_NONE))
net.LinkFlag = ReportFlag.FALSE;
else if (_tok[n].Match(Keywords.w_ALL))
net.LinkFlag = ReportFlag.TRUE;
else
{
if (net.Links.Count == 0)
throw new InputException(ErrorCode.Err210, SectType.REPORT, _tok[1]);
for (int i = 1; i <= n; i++)
{
Link link = net.GetLink(_tok[i]);
if (link == null)
throw new InputException(ErrorCode.Err210, SectType.REPORT, _tok[i]);
link.RptFlag = true;
}
net.LinkFlag = ReportFlag.SOME;
}
return;
}
FieldsMap fMap = net.FieldsMap;
if (_tok[0].TryParse(out FieldType iFieldId))
{
if (iFieldId > FieldType.FRICTION)
throw new InputException(ErrorCode.Err201, SectType.REPORT, _line);
if (_tok.Count == 1 || _tok[1].Match(Keywords.w_YES))
{
fMap.GetField(iFieldId).Enabled = true;
return;
}
if (_tok[1].Match(Keywords.w_NO))
{
fMap.GetField(iFieldId).Enabled = false;
return;
}
if (_tok.Count < 3)
throw new InputException(ErrorCode.Err201, SectType.REPORT, _line);
if (!_tok[1].TryParse(out RangeType rj))
throw new InputException(ErrorCode.Err201, SectType.REPORT, _line);
if (!_tok[2].ToDouble(out y))
throw new InputException(ErrorCode.Err201, SectType.REPORT, _line);
if (rj == RangeType.PREC)
{
fMap.GetField(iFieldId).Enabled = true;
fMap.GetField(iFieldId).Precision = (int)Math.Round(y); //roundOff(y));
}
else
fMap.GetField(iFieldId).SetRptLim(rj, y);
return;
}
if (_tok[0].Match(Keywords.w_FILE))
{
net.AltReport = _tok[1];
return;
}
throw new InputException(ErrorCode.Err201, SectType.REPORT, _line);
}
private void ParseOption()
{
int n = _tok.Count - 1;
bool notHandled = OptionChoice(n);
if (notHandled)
notHandled = OptionValue(n);
if (notHandled)
{
net.ExtraOptions[_tok[0]] = _tok[1];
}
}
///Handles options that are choice values, such as quality type, for example.
/// number of tokens
/// true is it didn't handle the option.
private bool OptionChoice(int n)
{
if (n < 0)
throw new InputException(ErrorCode.Err201, SectType.OPTIONS, _line);
if (_tok[0].Match(Keywords.w_UNITS))
{
if (n < 1)
return false;
if (!_tok[1].TryParse(out FlowUnitsType type))
throw new InputException(ErrorCode.Err201, SectType.OPTIONS, _line);
net.FlowFlag = type;
}
else if (_tok[0].Match(Keywords.w_PRESSURE))
{
if (n < 1) return false;
if (!_tok[1].TryParse(out PressUnitsType value))
{
throw new InputException(ErrorCode.Err201, SectType.OPTIONS, _line);
}
net.PressFlag = value;
}
else if (_tok[0].Match(Keywords.w_HEADLOSS))
{
if (n < 1) return false;
if (!_tok[1].TryParse(out HeadLossFormulaType value))
throw new InputException(ErrorCode.Err201, SectType.OPTIONS, _line);
net.FormFlag = value;
}
else if (_tok[0].Match(Keywords.w_HYDRAULIC))
{
if (n < 2) return false;
if (!_tok[1].TryParse(out HydType value))
throw new InputException(ErrorCode.Err201, SectType.OPTIONS, _line);
net.HydFlag = value;
net.HydFname = _tok[2];
}
else if (_tok[0].Match(Keywords.w_QUALITY))
{
if (n < 1)
return false;
net.QualFlag = _tok[1].TryParse(out QualType type)
? type
: QualType.Chem;
switch (net.QualFlag)
{
case QualType.Chem:
net.ChemName = _tok[1];
if (n >= 2)
net.ChemUnits = _tok[2];
break;
case QualType.Trace:
_tok[0] = "";
if (n < 2)
throw new InputException(ErrorCode.Err212, SectType.OPTIONS, _line);
_tok[0] = _tok[2];
Node node = net.GetNode(_tok[2]);
if (node == null)
throw new InputException(ErrorCode.Err212, SectType.OPTIONS, _line);
net.TraceNode = node.Name;
net.ChemName = Keywords.u_PERCENT;
net.ChemUnits = _tok[2];
break;
case QualType.Age:
net.ChemName = Keywords.w_AGE;
net.ChemUnits = Keywords.u_HOURS;
break;
}
}
else if (_tok[0].Match(Keywords.w_MAP))
{
if (n < 1)
return false;
net.MapFname = _tok[1];
}
else if (_tok[0].Match(Keywords.w_UNBALANCED))
{
if (n < 1)
return false;
if (_tok[1].Match(Keywords.w_STOP))
{
net.ExtraIter = -1;
}
else if (_tok[1].Match(Keywords.w_CONTINUE))
{
if (n >= 2)
{
if (!_tok[2].ToDouble(out double d))
throw new InputException(ErrorCode.Err201, SectType.OPTIONS, _line);
net.ExtraIter = (int)d;
}
else
net.ExtraIter = 0;
}
else
{
throw new InputException(ErrorCode.Err201, SectType.OPTIONS, _line);
}
}
else if (_tok[0].Match(Keywords.w_PATTERN))
{
if (n < 1)
return false;
net.DefPatId = _tok[1];
}
else
return true;
return false;
}
private bool OptionValue(int n)
{
string name = _tok[0];
/* Check for obsolete SEGMENTS keyword */
if (name.Match(Keywords.w_SEGMENTS))
return false;
/* Check for missing value (which is permissible) */
int nvalue = name.Match(Keywords.w_SPECGRAV) ||
name.Match(Keywords.w_EMITTER) ||
name.Match(Keywords.w_DEMAND)
? 2
: 1;
string keyword = null;
foreach (string k in optionValueKeywords)
{
if (name.Match(k))
{
keyword = k;
break;
}
}
if (keyword == null) return true;
name = keyword;
if (!_tok[nvalue].ToDouble(out double y))
throw new InputException(ErrorCode.Err213, SectType.OPTIONS, _line);
if (name.Match(Keywords.w_TOLERANCE))
{
if (y < 0.0)
throw new InputException(ErrorCode.Err213, SectType.OPTIONS, _line);
net.Ctol = y;
return false;
}
if (name.Match(Keywords.w_DIFFUSIVITY))
{
if (y < 0.0)
throw new InputException(ErrorCode.Err213, SectType.OPTIONS, _line);
net.Diffus = y;
return false;
}
if (name.Match(Keywords.w_DAMPLIMIT))
{
net.DampLimit = y;
return false;
}
if (y <= 0.0)
throw new InputException(ErrorCode.Err213, SectType.OPTIONS, _line);
if (name.Match(Keywords.w_VISCOSITY)) net.Viscos = y;
else if (name.Match(Keywords.w_SPECGRAV)) net.SpGrav = y;
else if (name.Match(Keywords.w_TRIALS)) net.MaxIter = (int)y;
else if (name.Match(Keywords.w_ACCURACY))
{
y = Math.Max(y, 1e-5);
y = Math.Min(y, 1e-1);
net.HAcc = y;
}
else if (name.Match(Keywords.w_HTOL)) net.HTol = y;
else if (name.Match(Keywords.w_QTOL)) net.QTol = y;
else if (name.Match(Keywords.w_RQTOL))
{
if (y >= 1.0)
throw new InputException(ErrorCode.Err213, SectType.OPTIONS, _line);
net.RQtol = y;
}
else if (name.Match(Keywords.w_CHECKFREQ)) net.CheckFreq = (int)y;
else if (name.Match(Keywords.w_MAXCHECK)) net.MaxCheck = (int)y;
else if (name.Match(Keywords.w_EMITTER)) net.QExp = 1.0 / y;
else if (name.Match(Keywords.w_DEMAND)) net.DMult = y;
return false;
}
private void ParseTime()
{
int n = _tok.Count - 1;
if (n < 1)
throw new InputException(ErrorCode.Err201, SectType.TIMES, _line);
if (_tok[0].Match(Keywords.w_STATISTIC))
{
if (!_tok[n].TryParse(out TstatType type))
throw new InputException(ErrorCode.Err201, SectType.TIMES, _line);
net.TstatFlag = type;
return;
}
TimeSpan t;
if ((t = Utilities.ToTimeSpan(_tok[n])) == TimeSpan.MinValue &&
(t = Utilities.ToTimeSpan(_tok[n - 1])) == TimeSpan.MinValue &&
(t = Utilities.ToTimeSpan(_tok[n - 1], _tok[n])) == TimeSpan.MinValue)
throw new InputException(ErrorCode.Err213, SectType.TIMES, _line);
if (_tok[0].Match(Keywords.w_DURATION))
net.Duration = t;
else if (_tok[0].Match(Keywords.w_HYDRAULIC))
net.HStep = t;
else if (_tok[0].Match(Keywords.w_QUALITY))
net.QStep = t;
else if (_tok[0].Match(Keywords.w_RULE))
net.RuleStep = t;
else if (_tok[0].Match(Keywords.w_MINIMUM)) { }
else if (_tok[0].Match(Keywords.w_PATTERN))
{
if (_tok[1].Match(Keywords.w_TIME))
net.PStep = t;
else if (_tok[1].Match(Keywords.w_START))
net.PStart = t;
else
throw new InputException(ErrorCode.Err201, SectType.TIMES, _line);
}
else if (_tok[0].Match(Keywords.w_REPORT))
{
if (_tok[1].Match(Keywords.w_TIME))
net.RStep = t;
else if (_tok[1].Match(Keywords.w_START))
net.RStart = t;
else
throw new InputException(ErrorCode.Err201, SectType.TIMES, _line);
}
else if (_tok[0].Match(Keywords.w_START))
net.Tstart = t.TimeOfDay();
else
throw new InputException(ErrorCode.Err201, SectType.TIMES, _line);
}
private static SectType FindSectionType(string line)
{
if (string.IsNullOrEmpty(line)) return (SectType)(-1);
for (var type = SectType.TITLE; type <= SectType.END; type++)
{
string sectName = '[' + type.ToString() + ']';
// if(line.Contains(type.parseStr())) return type;
// if (line.IndexOf(type.parseStr(), StringComparison.OrdinalIgnoreCase) >= 0) {
if (line.StartsWith(sectName, StringComparison.OrdinalIgnoreCase))
{
return type;
}
}
return (SectType)(-1);
}
private void ParseTag()
{
int n = _tok.Count;
if (n < 3)
throw new InputException(ErrorCode.Err201, SectType.DEMANDS, _line);
Element el;
if (_tok[0].Match(Keywords.w_NODE))
{
if ((el = net.GetNode(_tok[1])) == null)
throw new InputException(ErrorCode.Err203, SectType.TAGS, _tok[1]);
}
else if (_tok[0].Match(Keywords.w_LINK))
{
if ((el = net.GetLink(_tok[2])) == null)
throw new InputException(ErrorCode.Err204, SectType.TAGS, _tok[1]);
}
else
{
throw new InputException(ErrorCode.Err201, SectType.TAGS, _line);
}
el.Tag = _tok[3];
}
private void ParseDemand()
{
int n = _tok.Count;
Pattern pat = null;
if (n < 2)
throw new InputException(ErrorCode.Err201, SectType.DEMANDS, _line);
if (!_tok[1].ToDouble(out double y))
throw new InputException(ErrorCode.Err202, SectType.DEMANDS, _tok[0]);
if (_tok[0].Match(Keywords.w_MULTIPLY))
{
if (y <= 0.0)
throw new InputException(ErrorCode.Err202, SectType.DEMANDS, _tok[0]);
net.DMult = y;
return;
}
Node node = net.GetNode(_tok[0]);
if (node == null || node.NodeType != NodeType.Junction)
throw new InputException(ErrorCode.Err208, SectType.DEMANDS, _tok[0]);
if (n >= 3)
{
pat = net.GetPattern(_tok[2]);
if (pat == null)
throw new InputException(ErrorCode.Err205, SectType.DEMANDS, _line);
}
node.Demands.Add(new Demand(y, pat));
}
private void ParseRule()
{
_tok[0].TryParse(out Rulewords key);
if (key == Rulewords.RULE)
{
_currentRule = new Rule(_tok[1]);
net.Rules.Add(_currentRule);
}
else
{
_currentRule?.Code.Add(_line);
}
}
}
}