Network validity checks added to openhyd()

Checks on illegal valve connections made whenever API creates a new link, changes its end nodes, or changes its type.
This commit is contained in:
Lew Rossman
2018-12-20 08:36:05 -05:00
parent a66f5a2c92
commit 3ce0361c1d
6 changed files with 118 additions and 77 deletions

View File

@@ -203,7 +203,6 @@ int DLLEXPORT EN_open(EN_Project p, const char *f1, const char *f2, const char *
errmsg(p, errcode); errmsg(p, errcode);
return errcode; return errcode;
} }
writelogo(p);
// Allocate memory for project's data arrays // Allocate memory for project's data arrays
writewin(p->viewprog, FMT100); writewin(p->viewprog, FMT100);
@@ -2592,7 +2591,7 @@ int DLLEXPORT EN_addlink(EN_Project p, char *id, EN_LinkType linkType,
Network *net = &p->network; Network *net = &p->network;
Hydraul *hyd = &p->hydraul; Hydraul *hyd = &p->hydraul;
int i, n, size; int i, n, size, errcode;
int n1, n2; int n1, n2;
Slink *link; Slink *link;
Spump *pump; Spump *pump;
@@ -2604,6 +2603,9 @@ int DLLEXPORT EN_addlink(EN_Project p, char *id, EN_LinkType linkType,
// Check if a link with same id already exists // Check if a link with same id already exists
if (EN_getlinkindex(p, id, &i) == 0) return 215; if (EN_getlinkindex(p, id, &i) == 0) return 215;
// Check for valid link type
if (linkType < CVPIPE || linkType > GPV) return 251;
// Lookup the link's from and to nodes // Lookup the link's from and to nodes
n1 = hashtable_find(net->NodeHashTable, fromNode); n1 = hashtable_find(net->NodeHashTable, fromNode);
n2 = hashtable_find(net->NodeHashTable, toNode); n2 = hashtable_find(net->NodeHashTable, toNode);
@@ -2612,10 +2614,16 @@ int DLLEXPORT EN_addlink(EN_Project p, char *id, EN_LinkType linkType,
// Check that id name is not too long // Check that id name is not too long
if (strlen(id) > MAXID) return 250; if (strlen(id) > MAXID) return 250;
net->Nlinks++; // Check that valve link has legal connections
n = net->Nlinks; if (linkType > PUMP)
{
errcode = valvecheck(p, linkType, n1, n2);
if (errcode) return errcode;
}
// Grow link-related arrays to accomodate the new link // Grow link-related arrays to accomodate the new link
net->Nlinks++;
n = net->Nlinks;
size = (n + 1) * sizeof(Slink); size = (n + 1) * sizeof(Slink);
net->Link = (Slink *)realloc(net->Link, size); net->Link = (Slink *)realloc(net->Link, size);
size = (n + 1) * sizeof(double); size = (n + 1) * sizeof(double);
@@ -2624,6 +2632,7 @@ int DLLEXPORT EN_addlink(EN_Project p, char *id, EN_LinkType linkType,
size = (n + 1) * sizeof(StatusType); size = (n + 1) * sizeof(StatusType);
hyd->LinkStatus = (StatusType *)realloc(hyd->LinkStatus, size); hyd->LinkStatus = (StatusType *)realloc(hyd->LinkStatus, size);
// Set properties for the new link
link = &net->Link[n]; link = &net->Link[n];
strncpy(link->ID, id, MAXID); strncpy(link->ID, id, MAXID);
@@ -2636,7 +2645,7 @@ int DLLEXPORT EN_addlink(EN_Project p, char *id, EN_LinkType linkType,
net->Pump = (Spump *)realloc(net->Pump, size); net->Pump = (Spump *)realloc(net->Pump, size);
pump = &net->Pump[net->Npumps]; pump = &net->Pump[net->Npumps];
pump->Link = n; pump->Link = n;
pump->Ptype = 0; pump->Ptype = NOCURVE;
pump->Q0 = 0; pump->Q0 = 0;
pump->Qmax = 0; pump->Qmax = 0;
pump->Hmax = 0; pump->Hmax = 0;
@@ -2938,6 +2947,10 @@ int DLLEXPORT EN_setlinktype(EN_Project p, int *index, EN_LinkType type, int act
EN_getnodeid(p, n1, id1); EN_getnodeid(p, n1, id1);
EN_getnodeid(p, n2, id2); EN_getnodeid(p, n2, id2);
// Check for illegal valve connections
errcode = valvecheck(p, type, n1, n2);
if (errcode) return errcode;
// Delete the original link (and any controls containing it) // Delete the original link (and any controls containing it)
EN_deletelink(p, i, actionCode); EN_deletelink(p, i, actionCode);
@@ -2979,7 +2992,7 @@ int DLLEXPORT EN_setlinknodes(EN_Project p, int index, int node1, int node2)
*/ */
{ {
Network *net = &p->network; Network *net = &p->network;
int type; int type, errcode;
// Cannot modify network structure while solvers are active // Cannot modify network structure while solvers are active
if (p->hydraul.OpenHflag || p->quality.OpenQflag) return 262; if (p->hydraul.OpenHflag || p->quality.OpenQflag) return 262;
@@ -2993,14 +3006,10 @@ int DLLEXPORT EN_setlinknodes(EN_Project p, int index, int node1, int node2)
// Check for illegal valve connection // Check for illegal valve connection
type = net->Link[index].Type; type = net->Link[index].Type;
if (type == EN_PRV || type == EN_PSV || type == EN_FCV) if (type > PUMP)
{ {
// Can't be connected to a fixed grade node errcode = valvecheck(p, type, node1, node2);
if (node1 > net->Njuncs || if (errcode) return errcode;
node2 > net->Njuncs) return 219;
// Can't be connected to another pressure/flow control valve
if (!valvecheck(p, type, node1, node2)) return 220;
} }
// Assign new end nodes to link // Assign new end nodes to link

View File

@@ -29,6 +29,7 @@ int buildadjlists(Network *);
void freeadjlists(Network *); void freeadjlists(Network *);
int incontrols(Project *, int, int); int incontrols(Project *, int, int);
int valvecheck(Project *, int, int, int);
int findnode(Network *, char *); int findnode(Network *, char *);
int findlink(Network *, char *); int findlink(Network *, char *);
int findtank(Network *, int); int findtank(Network *, int);
@@ -88,7 +89,6 @@ int statusdata(Project *);
int reportdata(Project *); int reportdata(Project *);
int timedata(Project *); int timedata(Project *);
int optiondata(Project *); int optiondata(Project *);
int valvecheck(Project *, int, int, int);
// ------- RULES.C ------------------ // ------- RULES.C ------------------

View File

@@ -771,11 +771,19 @@ void pumpcoeff(Project *pr, int k)
return; return;
} }
// Obtain reference to pump object & its speed setting // Obtain reference to pump object
q = ABS(hyd->LinkFlow[k]); q = ABS(hyd->LinkFlow[k]);
p = findpump(&pr->network, k); p = findpump(&pr->network, k);
pump = &pr->network.Pump[p]; pump = &pr->network.Pump[p];
// If no pump curve treat pump as an open valve
if (pump->Ptype == NOCURVE)
{
hyd->P[k] = 1.0 / CSMALL;
hyd->Y[k] = hyd->LinkFlow[k];
return;
}
// Get pump curve coefficients for custom pump curve // Get pump curve coefficients for custom pump curve
// (Other pump types have pre-determined coeffs.) // (Other pump types have pre-determined coeffs.)
if (pump->Ptype == CUSTOM) if (pump->Ptype == CUSTOM)

View File

@@ -58,12 +58,26 @@ int openhyd(Project *pr)
int errcode = 0; int errcode = 0;
Slink *link; Slink *link;
// Check for too few nodes & no fixed grade nodes
if (pr->network.Nnodes < 2) errcode = 223;
else if (pr->network.Ntanks == 0) errcode = 224;
// Allocate memory for sparse matrix structures (see SMATRIX.C) // Allocate memory for sparse matrix structures (see SMATRIX.C)
ERRCODE(createsparse(pr)); ERRCODE(createsparse(pr));
// Allocate memory for hydraulic variables // Allocate memory for hydraulic variables
ERRCODE(allocmatrix(pr)); ERRCODE(allocmatrix(pr));
// Check for unconnected nodes
if (!errcode) for (i = 1; i <= pr->network.Njuncs; i++)
{
if (pr->network.Adjlist[i] == NULL)
{
errcode = 233;
break;
}
}
// Initialize link flows // Initialize link flows
if (!errcode) for (i = 1; i <= pr->network.Nlinks; i++) if (!errcode) for (i = 1; i <= pr->network.Nlinks; i++)
{ {

View File

@@ -514,14 +514,13 @@ int valvedata(Project *pr)
else if (!getfloat(parser->Tok[5], &setting)) return setError(parser, 5, 202); else if (!getfloat(parser->Tok[5], &setting)) return setError(parser, 5, 202);
if (n >= 7 && !getfloat(parser->Tok[6], &lcoeff)) return setError(parser, 6, 202); if (n >= 7 && !getfloat(parser->Tok[6], &lcoeff)) return setError(parser, 6, 202);
// Check that PRV, PSV, or FCV not connected to a tank & // Check for illegal connections
// check for illegal connections between pairs of valves if (valvecheck(pr, type, j1, j2))
if (type == PRV || type == PSV || type == FCV)
{ {
if (j1 > net->Njuncs) return setError(parser, 1, 219); if (j1 > net->Njuncs) return setError(parser, 1, 219);
if (j2 > net->Njuncs) return setError(parser, 2, 219); else if (j2 > net->Njuncs) return setError(parser, 2, 219);
else return setError(parser, -1, 220);
} }
if (!valvecheck(pr, type, j1, j2)) return setError(parser, -1, 220);
// Save valve data // Save valve data
link = &net->Link[net->Nlinks]; link = &net->Link[net->Nlinks];
@@ -2064,59 +2063,6 @@ int powercurve(double h0, double h1, double h2, double q1, double q2,
return 1; return 1;
} }
int valvecheck(Project *pr, int type, int j1, int j2)
/*
**--------------------------------------------------------------
** Input: type = valve type
** j1 = index of upstream node
** j2 = index of downstream node
** Output: returns 1 for legal connection, 0 otherwise
** Purpose: checks for legal connections between PRVs & PSVs
**--------------------------------------------------------------
*/
{
Network *net = &pr->network;
int k, vj1, vj2;
LinkType vtype;
Slink *link;
Svalve *valve;
// Examine each existing valve
for (k = 1; k <= net->Nvalves; k++)
{
valve = &net->Valve[k];
link = &net->Link[valve->Link];
vj1 = link->N1;
vj2 = link->N2;
vtype = link->Type;
// Cannot have two PRVs sharing downstream nodes or in series
if (vtype == PRV && type == PRV)
{
if (vj2 == j2 || vj2 == j1 || vj1 == j2) return 0;
}
// Cannot have two PSVs sharing upstream nodes or in series
if (vtype == PSV && type == PSV)
{
if (vj1 == j1 || vj1 == j2 || vj2 == j1) return 0;
}
// Cannot have PSV connected to downstream node of PRV
if (vtype == PSV && type == PRV && vj1 == j2) return 0;
if (vtype == PRV && type == PSV && vj2 == j1) return 0;
// Cannot have PSV connected to downstream node of FCV
// nor have PRV connected to upstream node of FCV
if (vtype == FCV && type == PSV && vj2 == j1) return 0;
if (vtype == FCV && type == PRV && vj1 == j2) return 0;
if (vtype == PSV && type == FCV && vj1 == j2) return 0;
if (vtype == PRV && type == FCV && vj2 == j1) return 0;
}
return 1;
}
void changestatus(Network *net, int j, StatusType status, double y) void changestatus(Network *net, int j, StatusType status, double y)
/* /*
**-------------------------------------------------------------- **--------------------------------------------------------------

View File

@@ -60,8 +60,8 @@ int openfiles(Project *pr, const char *f1, const char *f2, const char *f3)
else pr->outfile.Outflag = SCRATCH; else pr->outfile.Outflag = SCRATCH;
// Check that file names are not identical // Check that file names are not identical
if (strcomp(f1, f2) || strcomp(f1, f3) || if (strlen(f1) > 0 && (strcomp(f1, f2) || strcomp(f1, f3))) return 301;
(strcomp(f2, f3) && (strlen(f2) > 0 || strlen(f3) > 0))) return 301; if (strlen(f3) > 0 && strcomp(f2, f3)) return 301;
// Attempt to open input and report files // Attempt to open input and report files
if (strlen(f1) > 0) if (strlen(f1) > 0)
@@ -69,7 +69,12 @@ int openfiles(Project *pr, const char *f1, const char *f2, const char *f3)
if ((pr->parser.InFile = fopen(f1, "rt")) == NULL) return 302; if ((pr->parser.InFile = fopen(f1, "rt")) == NULL) return 302;
} }
if (strlen(f2) == 0) pr->report.RptFile = stdout; if (strlen(f2) == 0) pr->report.RptFile = stdout;
else if ((pr->report.RptFile = fopen(f2, "wt")) == NULL) return 303; else
{
pr->report.RptFile = fopen(f2, "wt");
if (pr->report.RptFile == NULL) return 303;
}
writelogo(pr);
return 0; return 0;
} }
@@ -625,6 +630,65 @@ int incontrols(Project *pr, int objType, int index)
return 0; return 0;
} }
int valvecheck(Project *pr, int type, int j1, int j2)
/*
**--------------------------------------------------------------
** Input: type = valve type
** j1 = index of upstream node
** j2 = index of downstream node
** Output: returns an error code
** Purpose: checks for illegal connections between valves
**--------------------------------------------------------------
*/
{
Network *net = &pr->network;
int k, vj1, vj2;
LinkType vtype;
Slink *link;
Svalve *valve;
if (type == PRV || type == PSV || type == FCV)
{
// Can't be connected to a fixed grade node
if (j1 > net->Njuncs || j2 > net->Njuncs) return 219;
// Examine each existing valve
for (k = 1; k <= net->Nvalves; k++)
{
valve = &net->Valve[k];
link = &net->Link[valve->Link];
vj1 = link->N1;
vj2 = link->N2;
vtype = link->Type;
// Cannot have two PRVs sharing downstream nodes or in series
if (vtype == PRV && type == PRV)
{
if (vj2 == j2 || vj2 == j1 || vj1 == j2) return 220;
}
// Cannot have two PSVs sharing upstream nodes or in series
if (vtype == PSV && type == PSV)
{
if (vj1 == j1 || vj1 == j2 || vj2 == j1) return 220;
}
// Cannot have PSV connected to downstream node of PRV
if (vtype == PSV && type == PRV && vj1 == j2) return 220;
if (vtype == PRV && type == PSV && vj2 == j1) return 220;
// Cannot have PSV connected to downstream node of FCV
// nor have PRV connected to upstream node of FCV
if (vtype == FCV && type == PSV && vj2 == j1) return 220;
if (vtype == FCV && type == PRV && vj1 == j2) return 220;
if (vtype == PSV && type == FCV && vj1 == j2) return 220;
if (vtype == PRV && type == FCV && vj2 == j1) return 220;
}
}
return 0;
}
int findnode(Network *network, char *id) int findnode(Network *network, char *id)
/*---------------------------------------------------------------- /*----------------------------------------------------------------
** Input: id = node ID ** Input: id = node ID