Add EN_openX function
EN_openX allows an EPANET input file to be opened even if it has errors. This required re-arranging code, mainly in input3.c, so that default values are assigned to an object before its input line is parsed.
This commit is contained in:
217
src/input2.c
217
src/input2.c
@@ -7,7 +7,7 @@ Description: reads and interprets network data from an EPANET input file
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 02/03/2020
|
||||
Last Updated: 09/28/2023
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -21,17 +21,13 @@ Last Updated: 02/03/2020
|
||||
#include "hash.h"
|
||||
#include "text.h"
|
||||
|
||||
#define MAXERRS 10 // Max. input errors reported
|
||||
|
||||
extern char *SectTxt[]; // Input section keywords (see ENUMSTXT.H)
|
||||
|
||||
// Exported functions
|
||||
int addnodeID(Network *n, int, char *);
|
||||
int addlinkID(Network *n, int, char *);
|
||||
|
||||
// Imported functions
|
||||
extern int powercurve(double, double, double, double, double, double *,
|
||||
double *, double *);
|
||||
int addnodeID(Network *, int, char *);
|
||||
int addlinkID(Network *, int, char *);
|
||||
int getunitsoption(Project *, char *);
|
||||
int getheadlossoption(Project *, char *);
|
||||
|
||||
// Local functions
|
||||
static int newline(Project *, int, char *);
|
||||
@@ -100,7 +96,11 @@ int netsize(Project *pr)
|
||||
if (sect == _END) break;
|
||||
continue;
|
||||
}
|
||||
else continue;
|
||||
else
|
||||
{
|
||||
sect = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Add to count of current object
|
||||
@@ -122,6 +122,12 @@ int netsize(Project *pr)
|
||||
errcode = addcurve(&pr->network, tok);
|
||||
parser->MaxCurves = pr->network.Ncurves;
|
||||
break;
|
||||
case _OPTIONS:
|
||||
if (match(tok, w_UNITS))
|
||||
getunitsoption(pr, strtok(line, SEPSTR));
|
||||
else if (match(tok, w_HEADLOSS))
|
||||
getheadlossoption(pr, strtok(line, SEPSTR));
|
||||
break;
|
||||
}
|
||||
if (errcode) break;
|
||||
}
|
||||
@@ -226,9 +232,11 @@ int readdata(Project *pr)
|
||||
}
|
||||
else
|
||||
{
|
||||
inperrmsg(pr, 201, sect, line);
|
||||
sect = -1;
|
||||
parser->ErrTok = 0;
|
||||
errsum++;
|
||||
break;
|
||||
inperrmsg(pr, 299, sect, line);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,23 +252,13 @@ int readdata(Project *pr)
|
||||
errsum++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
errcode = 200;
|
||||
break;
|
||||
}
|
||||
else continue;
|
||||
}
|
||||
|
||||
// Stop if reach end of file or max. error count
|
||||
if (errsum == MAXERRS) break;
|
||||
}
|
||||
|
||||
// Check for errors
|
||||
if (errsum > 0) errcode = 200;
|
||||
|
||||
// Determine pump curve parameters
|
||||
if (!errcode) errcode = getpumpparams(pr);
|
||||
|
||||
// Free input buffer
|
||||
free(parser->X);
|
||||
return errcode;
|
||||
@@ -307,6 +305,7 @@ int newline(Project *pr, int sect, char *line)
|
||||
if (ruledata(pr) > 0)
|
||||
{
|
||||
ruleerrmsg(pr);
|
||||
deleterule(pr, pr->network.Nrules);
|
||||
return 200;
|
||||
}
|
||||
else return 0;
|
||||
@@ -333,127 +332,6 @@ int newline(Project *pr, int sect, char *line)
|
||||
return 201;
|
||||
}
|
||||
|
||||
int getpumpparams(Project *pr)
|
||||
/*
|
||||
**-------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: returns error code
|
||||
** Purpose: computes pump curve coefficients for all pumps
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
int i, k, errcode = 0;
|
||||
char errmsg[MAXMSG+1];
|
||||
|
||||
for (i = 1; i <= net->Npumps; i++)
|
||||
{
|
||||
errcode = updatepumpparams(pr, i);
|
||||
if (errcode)
|
||||
{
|
||||
k = net->Pump[i].Link;
|
||||
sprintf(pr->Msg, "Error %d: %s %s",
|
||||
errcode, geterrmsg(errcode, errmsg), net->Link[k].ID);
|
||||
writeline(pr, pr->Msg);
|
||||
return 200;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int updatepumpparams(Project *pr, int pumpindex)
|
||||
/*
|
||||
**-------------------------------------------------------------
|
||||
** Input: pumpindex = index of a pump
|
||||
** Output: returns error code
|
||||
** Purpose: computes & checks a pump's head curve coefficients
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Network *net = &pr->network;
|
||||
Spump *pump;
|
||||
Scurve *curve;
|
||||
|
||||
int m;
|
||||
int curveindex;
|
||||
int npts = 0;
|
||||
int errcode = 0;
|
||||
double a, b, c, h0 = 0.0, h1 = 0.0, h2 = 0.0, q1 = 0.0, q2 = 0.0;
|
||||
|
||||
pump = &net->Pump[pumpindex];
|
||||
if (pump->Ptype == CONST_HP) // Constant Hp pump
|
||||
{
|
||||
pump->H0 = 0.0;
|
||||
pump->R = -8.814 * net->Link[pump->Link].Km;
|
||||
pump->N = -1.0;
|
||||
pump->Hmax = BIG; // No head limit
|
||||
pump->Qmax = BIG; // No flow limit
|
||||
pump->Q0 = 1.0; // Init. flow = 1 cfs
|
||||
return errcode;
|
||||
}
|
||||
|
||||
else if (pump->Ptype == NOCURVE) // Pump curve specified
|
||||
{
|
||||
curveindex = pump->Hcurve;
|
||||
if (curveindex == 0) return 226;
|
||||
curve = &net->Curve[curveindex];
|
||||
curve->Type = PUMP_CURVE;
|
||||
npts = curve->Npts;
|
||||
|
||||
// Generic power function curve
|
||||
if (npts == 1)
|
||||
{
|
||||
pump->Ptype = POWER_FUNC;
|
||||
q1 = curve->X[0];
|
||||
h1 = curve->Y[0];
|
||||
h0 = 1.33334 * h1;
|
||||
q2 = 2.0 * q1;
|
||||
h2 = 0.0;
|
||||
}
|
||||
|
||||
// 3 point curve with shutoff head
|
||||
else if (npts == 3 && curve->X[0] == 0.0)
|
||||
{
|
||||
pump->Ptype = POWER_FUNC;
|
||||
h0 = curve->Y[0];
|
||||
q1 = curve->X[1];
|
||||
h1 = curve->Y[1];
|
||||
q2 = curve->X[2];
|
||||
h2 = curve->Y[2];
|
||||
}
|
||||
|
||||
// Custom pump curve
|
||||
else
|
||||
{
|
||||
pump->Ptype = CUSTOM;
|
||||
for (m = 1; m < npts; m++)
|
||||
{
|
||||
if (curve->Y[m] >= curve->Y[m - 1]) return 227;
|
||||
}
|
||||
pump->Qmax = curve->X[npts - 1];
|
||||
pump->Q0 = (curve->X[0] + pump->Qmax) / 2.0;
|
||||
pump->Hmax = curve->Y[0];
|
||||
}
|
||||
|
||||
// Compute shape factors & limits of power function curves
|
||||
if (pump->Ptype == POWER_FUNC)
|
||||
{
|
||||
if (!powercurve(h0, h1, h2, q1, q2, &a, &b, &c)) return 227;
|
||||
else
|
||||
{
|
||||
pump->H0 = -a;
|
||||
pump->R = -b;
|
||||
pump->N = c;
|
||||
pump->Q0 = q1;
|
||||
pump->Qmax = pow((-a / b), (1.0 / c));
|
||||
pump->Hmax = h0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int addnodeID(Network *net, int n, char *id)
|
||||
/*
|
||||
**-------------------------------------------------------------
|
||||
@@ -564,6 +442,51 @@ int addcurve(Network *network, char *id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getunitsoption(Project *pr, char *units)
|
||||
/*
|
||||
**-------------------------------------------------------------
|
||||
** Input: units = name of flow units to be used
|
||||
** Output: returns 1 if successful, 0 if not
|
||||
** Purpose: sets the flows units to be used by a project.
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Parser *parser = &pr->parser;
|
||||
if (match(units, w_CFS)) parser->Flowflag = CFS;
|
||||
else if (match(units, w_GPM)) parser->Flowflag = GPM;
|
||||
else if (match(units, w_AFD)) parser->Flowflag = AFD;
|
||||
else if (match(units, w_MGD)) parser->Flowflag = MGD;
|
||||
else if (match(units, w_IMGD)) parser->Flowflag = IMGD;
|
||||
else if (match(units, w_LPS)) parser->Flowflag = LPS;
|
||||
else if (match(units, w_LPM)) parser->Flowflag = LPM;
|
||||
else if (match(units, w_CMH)) parser->Flowflag = CMH;
|
||||
else if (match(units, w_CMD)) parser->Flowflag = CMD;
|
||||
else if (match(units, w_MLD)) parser->Flowflag = MLD;
|
||||
else if (match(units, w_CMS)) parser->Flowflag = CMS;
|
||||
else if (match(units, w_SI)) parser->Flowflag = LPS;
|
||||
else return 0;
|
||||
if (parser->Flowflag >= LPS) parser->Unitsflag = SI;
|
||||
else parser->Unitsflag = US;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int getheadlossoption(Project *pr, char *formula)
|
||||
/*
|
||||
**-------------------------------------------------------------
|
||||
** Input: formula = name of head loss formula to be used
|
||||
** Output: returns 1 if successful, 0 if not
|
||||
** Purpose: sets the head loss formula to be used by a project.
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
if (match(formula, w_HW)) hyd->Formflag = HW;
|
||||
else if (match(formula, w_DW)) hyd->Formflag = DW;
|
||||
else if (match(formula, w_CM)) hyd->Formflag = CM;
|
||||
else return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int findmatch(char *line, char *keyword[])
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
@@ -799,7 +722,11 @@ void inperrmsg(Project *pr, int err, int sect, char *line)
|
||||
else strcpy(tok, "");
|
||||
|
||||
// write error message to report file
|
||||
sprintf(pr->Msg, "Error %d: %s %s in %s section:",
|
||||
if (err == 299)
|
||||
sprintf(pr->Msg, "Error %d: %s %s: section contents ignored.",
|
||||
err, geterrmsg(err, errStr), tok);
|
||||
else
|
||||
sprintf(pr->Msg, "Error %d: %s %s in %s section:",
|
||||
err, geterrmsg(err, errStr), tok, SectTxt[sect]);
|
||||
writeline(pr, pr->Msg);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user