From edcd4b69c7d1f6f849a276292f0c0f246b1ee6bb Mon Sep 17 00:00:00 2001 From: Lew Rossman Date: Fri, 5 Apr 2019 13:02:39 -0400 Subject: [PATCH 1/2] Eliminates use of temporary linked lists to process Patterns & Curves (issue #449) --- src/epanet.c | 68 ++++++------ src/funcs.h | 10 +- src/input1.c | 1 + src/input2.c | 291 +++++++++++++------------------------------------- src/input3.c | 202 +++++++++++++++++------------------ src/project.c | 146 ++++++++++++------------- src/types.h | 26 +---- 7 files changed, 295 insertions(+), 449 deletions(-) diff --git a/src/epanet.c b/src/epanet.c index 30894fc..55b1265 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -172,10 +172,7 @@ int DLLEXPORT EN_init(EN_Project p, const char *rptFile, const char *outFile, initunits(p); inittanks(p); convertunits(p); - - // Initialize the default demand pattern p->parser.MaxPats = 0; - getpatterns(p); p->Openflag = TRUE; return errcode; } @@ -230,10 +227,6 @@ int DLLEXPORT EN_open(EN_Project p, const char *inpFile, const char *rptFile, p->parser.InFile = NULL; } - // Free temporary linked lists used for Patterns & Curves - freeTmplist(p->parser.Patlist); - freeTmplist(p->parser.Curvelist); - // If using previously saved hydraulics file then open it if (p->outfile.Hydflag == USE) ERRCODE(openhydfile(p)); @@ -3943,7 +3936,6 @@ int DLLEXPORT EN_addpattern(EN_Project p, char *id) { Network *net = &p->network; Parser *parser = &p->parser; - Hydraul *hyd = &p->hydraul; int i, n, err = 0; Spattern *pat; @@ -4231,6 +4223,7 @@ int DLLEXPORT EN_addcurve(EN_Project p, char *id) curve = &net->Curve[n]; strcpy(curve->ID, id); curve->Comment = NULL; + curve->Capacity = 1; curve->Npts = 1; curve->Type = GENERIC_CURVE; curve->X = (double *)calloc(1, sizeof(double)); @@ -4302,20 +4295,11 @@ int DLLEXPORT EN_getcurveindex(EN_Project p, char *id, int *index) **---------------------------------------------------------------- */ { - int i; - *index = 0; if (!p->Openflag) return 102; - for (i = 1; i <= p->network.Ncurves; i++) - { - if (strcmp(id, p->network.Curve[i].ID) == 0) - { - *index = i; - return 0; - } - } - *index = 0; - return 206; + *index = findcurve(&p->network, id); + if (*index == 0) return 206; + return 0; } int DLLEXPORT EN_getcurveid(EN_Project p, int index, char *id) @@ -4404,8 +4388,8 @@ int DLLEXPORT EN_getcurvevalue(EN_Project p, int curveIndex, int pointIndex, if (!p->Openflag) return 102; if (curveIndex < 1 || curveIndex > p->network.Ncurves) return 206; if (pointIndex < 1 || pointIndex > p->network.Curve[curveIndex].Npts) return 251; - *x = (double)p->network.Curve[curveIndex].X[pointIndex - 1]; - *y = (double)p->network.Curve[curveIndex].Y[pointIndex - 1]; + *x = p->network.Curve[curveIndex].X[pointIndex - 1]; + *y = p->network.Curve[curveIndex].Y[pointIndex - 1]; return 0; } @@ -4419,18 +4403,43 @@ int DLLEXPORT EN_setcurvevalue(EN_Project p, int curveIndex, int pointIndex, ** Output: none ** Returns: error code ** Purpose: sets the value of a specific point on a data curve +** Note: if pointIndex exceeds the curve's length a new point is added. **---------------------------------------------------------------- */ { Network *net = &p->network; Scurve *curve; + double x1 = -1.e37, x2 = 1.e37; + int n = pointIndex - 1; + // Check for valid input if (!p->Openflag) return 102; if (curveIndex <= 0 || curveIndex > net->Ncurves) return 206; curve = &net->Curve[curveIndex]; - if (pointIndex <= 0 || pointIndex > curve->Npts) return 251; - curve->X[pointIndex - 1] = x; - curve->Y[pointIndex - 1] = y; + if (pointIndex <= 0) return 251; + + // Check that new point maintains increasing x values + if (n - 1 >= 0) x1 = curve->X[n-1]; + if (n + 1 < curve->Npts) x2 = curve->X[n+1]; + if (x <= x1 || x >= x2) return 230; + + // Expand curve if need be + if (pointIndex > curve->Npts) pointIndex = curve->Npts + 1; + if (pointIndex >= curve->Capacity) + { + if (resizecurve(curve, curve->Capacity + 10) > 0) return 101; + } + + // Increase curve's number of points if need be + if (pointIndex > curve->Npts) + { + curve->Npts++; + n = curve->Npts - 1; + } + + // Insert new point into curve + curve->X[n] = x; + curve->Y[n] = y; return 0; } @@ -4490,15 +4499,12 @@ int DLLEXPORT EN_setcurve(EN_Project p, int index, double *xValues, // Check that x values are increasing for (j = 1; j < nPoints; j++) if (xValues[j-1] >= xValues[j]) return 230; - // Re-set number of points & reallocate memory for values + // Expand size of curve's data arrays if need be curve = &net->Curve[index]; - curve->Npts = nPoints; - curve->X = (double *)realloc(curve->X, nPoints * sizeof(double)); - curve->Y = (double *)realloc(curve->Y, nPoints * sizeof(double)); - if (curve->X == NULL) return 101; - if (curve->Y == NULL) return 101; + if (resizecurve(curve, nPoints) > 0) return 101; // Load values into curve + curve->Npts = nPoints; for (j = 0; j < nPoints; j++) { curve->X[j] = xValues[j]; diff --git a/src/funcs.h b/src/funcs.h index 6fffeb3..ac17b55 100755 --- a/src/funcs.h +++ b/src/funcs.h @@ -7,7 +7,7 @@ Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE - Last Updated: 03/17/2019 + Last Updated: 04/03/2019 ****************************************************************************** */ #ifndef FUNCS_H @@ -17,8 +17,6 @@ void initpointers(Project *); int allocdata(Project *); -void freeTmplist(STmplist *); -void freeFloatlist(SFloatlist *); void freedata(Project *); int openfiles(Project *, const char *, const char *,const char *); @@ -36,8 +34,12 @@ int findlink(Network *, char *); int findtank(Network *, int); int findvalve(Network *, int); int findpump(Network *, int); +int findpattern(Network *, char *); +int findcurve(Network *, char *); + void adjustpatterns(Network *, int); void adjustcurves(Network *, int); +int resizecurve(Scurve *, int); int getcomment(Network *, int, int, char *); int setcomment(Network *, int, int, const char *); @@ -65,8 +67,6 @@ void convertunits(Project *); int netsize(Project *); int readdata(Project *); int updatepumpparams(Project *, int); -int getpatterns(Project *); -int getcurves(Project *); int findmatch(char *, char *[]); int match(const char *, const char *); int gettokens(char *, char **, int, char *); diff --git a/src/input1.c b/src/input1.c index 6b900a5..219caaf 100644 --- a/src/input1.c +++ b/src/input1.c @@ -331,6 +331,7 @@ void adjustdata(Project *pr) } // Use default pattern if none assigned to a demand + parser->DefPat = findpattern(net, parser->DefPatID); if (parser->DefPat > 0) for (i = 1; i <= net->Nnodes; i++) { node = &net->Node[i]; diff --git a/src/input2.c b/src/input2.c index 0508ee4..482103e 100644 --- a/src/input2.c +++ b/src/input2.c @@ -35,7 +35,6 @@ extern char *SectTxt[]; // Input section keywords (see ENUMSTXT.H) // Exported functions int addnodeID(Network *n, int, char *); int addlinkID(Network *n, int, char *); -STmplist *getlistitem(char *, STmplist *); // Imported functions extern int powercurve(double, double, double, double, double, double *, @@ -43,8 +42,8 @@ extern int powercurve(double, double, double, double, double, double *, // Local functions static int newline(Project *, int, char *); -static int addpattern(Parser *, char *); -static int addcurve(Parser *, char *); +static int addpattern(Network *, char *); +static int addcurve(Network *, char *); static int unlinked(Project *); static int getpumpparams(Project *); static void inperrmsg(Project *, int, int, char *); @@ -65,6 +64,7 @@ int netsize(Project *pr) char *tok; // First token of line int sect, newsect; // Input data sections int errcode = 0; // Error code + Spattern *pattern; // Initialize object counts parser->MaxJuncs = 0; @@ -77,13 +77,20 @@ int netsize(Project *pr) parser->MaxCurves = 0; sect = -1; - // Add a default demand pattern - parser->MaxPats = -1; - addpattern(parser,""); - if (parser->InFile == NULL) return 0; + // Add a "dummy" time pattern with index of 0 and a single multiplier + // of 1.0 to be used by all demands not assigned a pattern + pr->network.Npats = -1; + errcode = addpattern(&pr->network, ""); + if (errcode) return errcode; + pattern = &pr->network.Pattern[0]; + pattern->Length = 1; + pattern[0].F = (double *)calloc(1, sizeof(double)); + pattern[0].F[0] = 1.0; + parser->MaxPats = pr->network.Npats; // Make a pass through input file counting number of each object + if (parser->InFile == NULL) return 0; while (fgets(line, MAXLINE, parser->InFile) != NULL) { // Skip blank lines & those beginning with a comment @@ -115,8 +122,14 @@ int netsize(Project *pr) case _VALVES: parser->MaxValves++; break; case _CONTROLS: parser->MaxControls++; break; case _RULES: addrule(parser,tok); break; - case _PATTERNS: errcode = addpattern(parser, tok); break; - case _CURVES: errcode = addcurve(parser, tok); break; + case _PATTERNS: + errcode = addpattern(&pr->network, tok); + parser->MaxPats = pr->network.Npats; + break; + case _CURVES: + errcode = addcurve(&pr->network, tok); + parser->MaxCurves = pr->network.Ncurves; + break; } if (errcode) break; } @@ -166,12 +179,15 @@ int readdata(Project *pr) net->Nvalves = 0; net->Ncontrols = 0; net->Nrules = 0; - net->Ncurves = parser->MaxCurves; - net->Npats = parser->MaxPats; + + // Patterns & Curves were created previously in netsize() + parser->MaxPats = net->Npats; + parser->MaxCurves = net->Ncurves; parser->PrevPat = NULL; parser->PrevCurve = NULL; + + // Initialize full line comment, input data section and error count parser->LineComment[0] = '\0'; - sect = -1; errsum = 0; @@ -257,9 +273,7 @@ int readdata(Project *pr) // Check for unlinked nodes if (!errcode) errcode = unlinked(pr); - // Get pattern & curve data from temporary lists - if (!errcode) errcode = getpatterns(pr); - if (!errcode) errcode = getcurves(pr); + // Determine pump curve parameters if (!errcode) errcode = getpumpparams(pr); // Free input buffer @@ -487,7 +501,7 @@ int addlinkID(Network *net, int n, char *id) return 1; } -int addpattern(Parser *parser, char *id) +int addpattern(Network *network, char *id) /* **------------------------------------------------------------- ** Input: id = pattern ID label @@ -496,34 +510,33 @@ int addpattern(Parser *parser, char *id) **-------------------------------------------------------------- */ { - STmplist *patlist; + int n = network->Npats; + Spattern *pattern; - // Check if ID is same as last one processed - if (parser->Patlist != NULL && strcmp(id, parser->Patlist->ID) == 0) return 0; - - // Check that pattern was not already created - if (getlistitem(id, parser->Patlist) == NULL) + // Check if pattern was already created + if (n > 0) { - // Update pattern count & create new list element - (parser->MaxPats)++; - patlist = (STmplist *)malloc(sizeof(STmplist)); - if (patlist == NULL) return 101; - - // Initialize list element properties - else - { - patlist->i = parser->MaxPats; - strncpy(patlist->ID, id, MAXID); - patlist->x = NULL; - patlist->y = NULL; - patlist->next = parser->Patlist; - parser->Patlist = patlist; - } + if (strcmp(id, network->Pattern[n].ID) == 0) return 0; + if (findpattern(network, id) > 0) return 0; } + if (strlen(id) > MAXID) return 250; + + // Update pattern count & add a new pattern to the database + n = n + 2; + network->Pattern = (Spattern *)realloc(network->Pattern, n * sizeof(Spattern)); + if (network->Pattern == NULL) return 101; + (network->Npats)++; + + // Initialize the pattern + pattern = &network->Pattern[network->Npats]; + strncpy(pattern->ID, id, MAXID); + pattern->Comment = NULL; + pattern->Length = 0; + pattern->F = NULL; return 0; } -int addcurve(Parser *parser, char *id) +int addcurve(Network *network, char *id) /* **------------------------------------------------------------- ** Input: id = curve ID label @@ -532,51 +545,33 @@ int addcurve(Parser *parser, char *id) **-------------------------------------------------------------- */ { - STmplist *curvelist; + int n = network->Ncurves; + Scurve *curve; - // Check if ID is same as last one processed - if (parser->Curvelist != NULL && strcmp(id, parser->Curvelist->ID) == 0) return 0; - - // Check that curve was not already created - if (getlistitem(id, parser->Curvelist) == NULL) + // Check if was already created + if (n > 0) { - // Update curve count & create new list element - (parser->MaxCurves)++; - curvelist = (STmplist *)malloc(sizeof(STmplist)); - if (curvelist == NULL) return 101; - - // Initialize list element properties - else - { - curvelist->i = parser->MaxCurves; - strncpy(curvelist->ID, id, MAXID); - curvelist->x = NULL; - curvelist->y = NULL; - curvelist->next = parser->Curvelist; - parser->Curvelist = curvelist; - } + if (strcmp(id, network->Curve[n].ID) == 0) return 0; + if (findcurve(network, id) > 0) return 0; } + if (strlen(id) > MAXID) return 250; + + n = n + 2; + network->Curve = (Scurve *)realloc(network->Curve, n * sizeof(Scurve)); + if (network->Curve == NULL) return 101; + (network->Ncurves)++; + + // Initialize the curve + curve = &network->Curve[network->Ncurves]; + strncpy(curve->ID, id, MAXID); + curve->Comment = NULL; + curve->Capacity = 0; + curve->Npts = 0; + curve->X = NULL; + curve->Y = NULL; return 0; } -STmplist *getlistitem(char *id, STmplist *list) -/* -**------------------------------------------------------------- -** Input: id = ID label -** list = pointer to head of a temporary list -** Output: returns list item with requested ID label -** Purpose: searches for item in temporary list -**------------------------------------------------------------- -*/ -{ - STmplist *item; - for (item = list; item != NULL; item = item->next) - { - if (strcmp(item->ID, id) == 0) return item; - } - return NULL; -} - int unlinked(Project *pr) /* **-------------------------------------------------------------- @@ -625,144 +620,6 @@ int unlinked(Project *pr) return errcode; } -int getpatterns(Project *pr) -/* -**----------------------------------------------------------- -** Input: none -** Output: returns error code -** Purpose: retrieves pattern data from temporary linked list -**------------------------------------------------------------- -*/ -{ - Network *net = &pr->network; - Hydraul *hyd = &pr->hydraul; - Parser *parser = &pr->parser; - - int i, j; - SFloatlist *f; - STmplist *tmppattern; - Spattern *pattern; - - // Start at head of the list of patterns - tmppattern = parser->Patlist; - - // Traverse list of temporary patterns - while (tmppattern != NULL) - { - // Get index of temporary pattern in network's Pattern array - i = tmppattern->i; - - // Check if this is the default pattern - if (strcmp(tmppattern->ID, parser->DefPatID) == 0) parser->DefPat = i; - - // Copy temporary patttern to network's pattern - if (i >= 0 && i <= parser->MaxPats) - { - pattern = &net->Pattern[i]; - strcpy(pattern->ID, tmppattern->ID); - - /* Give pattern a length of at least 1 */ - if (pattern->Length == 0) pattern->Length = 1; - - // Allocate array of pattern factors - pattern->F = (double *)calloc(pattern->Length, sizeof(double)); - if (pattern->F == NULL) return 101; - - // Start at head of temporary pattern multiplier list - // (which holds multipliers in reverse order) - f = tmppattern->x; - j = pattern->Length - 1; - - // Use at least one multiplier equal to 1.0 - if (f == NULL) pattern->F[0] = 1.0; - - // Traverse temporary multiplier list, copying Pattern array */ - else while (f != NULL && j >= 0) - { - pattern->F[j] = f->value; - f = f->next; - j--; - } - } - tmppattern = tmppattern->next; - } - return 0; -} - -int getcurves(Project *pr) -/* -**----------------------------------------------------------- -** Input: none -** Output: returns error code -** Purpose: retrieves curve data from temporary linked list -**----------------------------------------------------------- -*/ -{ - Network *net = &pr->network; - Parser *parser = &pr->parser; - - int i, j; - double x; - char errmsg[MAXMSG+1]; - SFloatlist *fx, *fy; - STmplist *tmpcurve; - Scurve *curve; - - // Traverse list of temporary curves - tmpcurve = parser->Curvelist; - while (tmpcurve != NULL) - { - // Get index of temporary curve in network's Curve array - i = tmpcurve->i; - - // Copy temporary curve to network's curve - if (i >= 1 && i <= parser->MaxCurves) - { - curve = &net->Curve[i]; - strcpy(curve->ID, tmpcurve->ID); - - // Check that network curve has data points - if (curve->Npts <= 0) - { - sprintf(pr->Msg, "Error 230: %s %s", geterrmsg(230, errmsg), curve->ID); - writeline(pr, pr->Msg); - return 200; - } - - // Allocate memory for network's curve data - curve->X = (double *)calloc(curve->Npts, sizeof(double)); - curve->Y = (double *)calloc(curve->Npts, sizeof(double)); - if (curve->X == NULL || curve->Y == NULL) return 101; - - // Traverse list of x,y data - x = BIG; - fx = tmpcurve->x; - fy = tmpcurve->y; - j = curve->Npts - 1; - while (fx != NULL && fy != NULL && j >= 0) - { - // Check that x data is in ascending order - if (fx->value >= x) - { - sprintf(pr->Msg, "Error 230: %s %s", geterrmsg(230, errmsg), curve->ID); - writeline(pr, pr->Msg); - return 200; - } - x = fx->value; - - // Copy x,y data to network's curve - curve->X[j] = fx->value; - fx = fx->next; - curve->Y[j] = fy->value; - fy = fy->next; - j--; - } - } - tmpcurve = tmpcurve->next; - } - return 0; -} - int findmatch(char *line, char *keyword[]) /* **-------------------------------------------------------------- @@ -828,8 +685,8 @@ int gettokens(char *s, char** Tok, int maxToks, char *comment) **-------------------------------------------------------------- */ { - int m, n; - size_t len; + int n; + size_t len, m; char *c, *c2; // clear comment diff --git a/src/input3.c b/src/input3.c index 2a32179..2035d8d 100644 --- a/src/input3.c +++ b/src/input3.c @@ -7,7 +7,7 @@ Description: parses network data from a line of an EPANET input file Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE -Last Updated: 03/17/2019 +Last Updated: 04/03/2019 ****************************************************************************** */ @@ -40,7 +40,6 @@ int powercurve(double, double, double, double, double, double *, double *, // Imported Functions extern int addnodeID(Network *, int, char *); extern int addlinkID(Network *, int, char *); -extern STmplist *getlistitem(char *, STmplist *); // Local functions static int optionchoice(Project *, int); @@ -87,7 +86,6 @@ int juncdata(Project *pr) double el, // elevation y = 0.0; // base demand Pdemand demand; // demand record - STmplist *patlist; // list of demands Snode *node; // Add new junction to data base @@ -104,9 +102,8 @@ int juncdata(Project *pr) if (n >= 3 && !getfloat(parser->Tok[2], &y)) return setError(parser, 2, 202); if (n >= 4) { - patlist = getlistitem(parser->Tok[3], parser->Patlist); - if (patlist == NULL) return setError(parser, 3, 205); - p = patlist->i; + p = findpattern(net, parser->Tok[3]); + if (p == 0) return setError(parser, 3, 205); } // Save junction data @@ -162,7 +159,6 @@ int tankdata(Project *pr) minvol = 0.0, // Minimum volume diam = 0.0, // Diameter area; // X-sect. area - STmplist *tmplist; Snode *node; Stank *tank; @@ -186,9 +182,8 @@ int tankdata(Project *pr) // Head pattern supplied if (n == 3) { - tmplist = getlistitem(parser->Tok[2], parser->Patlist); - if (tmplist == NULL) return setError(parser, 2, 205); - pattern = tmplist->i; + pattern = findpattern(net, parser->Tok[2]); + if (pattern == 0) return setError(parser, 2, 205); } } else if (n < 6) return 201; @@ -205,9 +200,8 @@ int tankdata(Project *pr) // If volume curve supplied check it exists if (n == 8) { - tmplist = getlistitem(parser->Tok[7], parser->Curvelist); - if (tmplist == NULL) return setError(parser, 7, 206); - curve = tmplist->i; + curve = findcurve(net, parser->Tok[7]); + if (curve == 0) return setError(parser, 7, 206); net->Curve[curve].Type = VOLUME_CURVE; } if (initlevel < 0.0) return setError(parser, 2, 209); @@ -357,12 +351,12 @@ int pumpdata(Project *pr) Network *net = &pr->network; Parser *parser = &pr->parser; - int j, + int j, m, // Token array indexes j1, // Start-node index j2, // End-node index - m, n; // # data items + n, // # data items + c, p; // Curve & Pattern indexes double y; - STmplist *tmplist; // Temporary list Slink *link; Spump *pump; @@ -432,15 +426,15 @@ int pumpdata(Project *pr) } else if (match(parser->Tok[m - 1], w_HEAD)) // Custom pump curve { - tmplist = getlistitem(parser->Tok[m], parser->Curvelist); - if (tmplist == NULL) return setError(parser, m, 206); - pump->Hcurve = tmplist->i; + c = findcurve(net, parser->Tok[m]); + if (c == 0) return setError(parser, m, 206); + pump->Hcurve = c; } else if (match(parser->Tok[m - 1], w_PATTERN)) // Speed/status pattern { - tmplist = getlistitem(parser->Tok[m], parser->Patlist); - if (tmplist == NULL) return setError(parser, m, 205); - pump->Upat = tmplist->i; + p = findpattern(net, parser->Tok[m]); + if (p == 0) return setError(parser, m, 205); + pump->Upat = p; } else if (match(parser->Tok[m - 1], w_SPEED)) // Speed setting { @@ -469,7 +463,8 @@ int valvedata(Project *pr) Network *net = &pr->network; Parser *parser = &pr->parser; - int j1, // Start-node index + int c, // Curve index + j1, // Start-node index j2, // End-node index n; // # data items char status = ACTIVE, // Valve status @@ -477,7 +472,6 @@ int valvedata(Project *pr) double diam = 0.0, // Valve diameter setting, // Valve setting lcoeff = 0.0; // Minor loss coeff. - STmplist *tmplist; // Temporary list Slink *link; // Add new valve to data base @@ -508,10 +502,10 @@ int valvedata(Project *pr) // Find headloss curve for GPV if (type == GPV) { - tmplist = getlistitem(parser->Tok[5], parser->Curvelist); - if (tmplist == NULL) return setError(parser, 5, 206); - setting = tmplist->i; - net->Curve[tmplist->i].Type = HLOSS_CURVE; + c = findcurve(net, parser->Tok[5]); + if (c == 0) return setError(parser, 5, 206); + setting = c; + net->Curve[c].Type = HLOSS_CURVE; status = OPEN; } else if (!getfloat(parser->Tok[5], &setting)) return setError(parser, 5, 202); @@ -558,43 +552,47 @@ int patterndata(Project *pr) Network *net = &pr->network; Parser *parser = &pr->parser; - int i, n; + int i, j, n, n1; double x; - SFloatlist *f; - STmplist *p; Spattern *pattern; + // "n" is the number of pattern factors contained in the line n = parser->Ntokens - 1; if (n < 1) return 201; - // Check for a new pattern - if (parser->PrevPat != NULL && - strcmp(parser->Tok[0], parser->PrevPat->ID) == 0) p = parser->PrevPat; + // Check if previous input line was for the same pattern + if (parser->PrevPat && strcmp(parser->Tok[0], parser->PrevPat->ID) == 0) + { + pattern = parser->PrevPat; + } + + // Otherwise retrieve pattern from the network's Pattern array else { - p = getlistitem(parser->Tok[0], parser->Patlist); - if (p == NULL) return setError(parser, 0, 205); - pattern = &(net->Pattern[p->i]); - pattern->Comment = xstrcpy(&pattern->Comment, parser->Comment, MAXMSG); + i = findpattern(net, parser->Tok[0]); + if (i == 0) return setError(parser, 0, 205); + pattern = &(net->Pattern[i]); + if (pattern->Comment == NULL && parser->Comment[0]) + { + pattern->Comment = xstrcpy(&pattern->Comment, parser->Comment, MAXMSG); + } } + // Expand size of the pattern's factors array + n1 = pattern->Length; + pattern->Length += n; + pattern->F = realloc(pattern->F, pattern->Length * sizeof(double)); + // Add parsed multipliers to the pattern - for (i = 1; i <= n; i++) + for (j = 1; j <= n; j++) { - if (!getfloat(parser->Tok[i], &x)) return setError(parser, i, 202); - f = (SFloatlist *)malloc(sizeof(SFloatlist)); - if (f == NULL) return 101; - f->value = x; - f->next = p->x; - p->x = f; + if (!getfloat(parser->Tok[j], &x)) return setError(parser, j, 202); + pattern->F[n1 + j - 1] = x; } - // Save # multipliers for pattern - net->Pattern[p->i].Length += n; - - // Set previous pattern pointer - parser->PrevPat = p; - return (0); + // Save a reference to this pattern for processing additional pattern data + parser->PrevPat = pattern; + return 0; } int curvedata(Project *pr) @@ -612,46 +610,46 @@ int curvedata(Project *pr) Network *net = &pr->network; Parser *parser = &pr->parser; + int i; double x, y; - SFloatlist *fx, *fy; - STmplist *c; Scurve *curve; - // Check for valid curve ID - if (parser->Ntokens < 3) return 201; - if (parser->PrevCurve != NULL && - strcmp(parser->Tok[0], parser->PrevCurve->ID) == 0) c = parser->PrevCurve; - else - { - c = getlistitem(parser->Tok[0], parser->Curvelist); - if (c == NULL) return setError(parser, 0, 206); - curve = &(net->Curve[c->i]); - curve->Comment = xstrcpy(&curve->Comment, parser->Comment, MAXMSG); - } - // Check for valid data + if (parser->Ntokens < 3) return 201; if (!getfloat(parser->Tok[1], &x)) return setError(parser, 1, 202); if (!getfloat(parser->Tok[2], &y)) return setError(parser, 2, 202); - // Add new data point to curve - fx = (SFloatlist *)malloc(sizeof(SFloatlist)); - if (fx == NULL) return 101; - fy = (SFloatlist *)malloc(sizeof(SFloatlist)); - if (fy == NULL) + // Check if previous input line was for the same curve + if (parser->PrevCurve && strcmp(parser->Tok[0], parser->PrevCurve->ID) == 0) { - free(fx); - return 101; + curve = parser->PrevCurve; } - fx->value = x; - fx->next = c->x; - c->x = fx; - fy->value = y; - fy->next = c->y; - c->y = fy; - net->Curve[c->i].Npts++; - // Save the pointer to this curve - parser->PrevCurve = c; + // Otherwise retrieve curve from the network's Curve array + else + { + i = findcurve(net, parser->Tok[0]); + if (i == 0) return setError(parser, 0, 206); + curve = &(net->Curve[i]); + if (curve->Comment == NULL && parser->Comment[0]) + { + curve->Comment = xstrcpy(&curve->Comment, parser->Comment, MAXMSG); + } + } + + // Expand size of data arrays if need be + if (curve->Capacity == curve->Npts) + { + if (resizecurve(curve, curve->Capacity + 10) > 0) return 101; + } + + // Add new data point to curve + curve->X[curve->Npts] = x; + curve->Y[curve->Npts] = y; + curve->Npts++; + + // Save a reference to this curve for processing additional curve data + parser->PrevCurve = curve; return 0; } @@ -713,7 +711,6 @@ int demanddata(Project *pr) double y; Pdemand demand; Pdemand cur_demand; - STmplist *patlist; // Extract data from tokens n = parser->Ntokens; @@ -733,9 +730,8 @@ int demanddata(Project *pr) if (j > net->Njuncs) return 0; if (n >= 3) { - patlist = getlistitem(parser->Tok[2], parser->Patlist); - if (patlist == NULL) return setError(parser, 2, 205); - p = patlist->i; + p = findpattern(net, parser->Tok[2]); + if (p == 0) return setError(parser, 2, 205); } // Replace any demand entered in [JUNCTIONS] section @@ -746,7 +742,10 @@ int demanddata(Project *pr) // with what is specified in this section demand->Base = y; demand->Pat = p; - demand->Name = xstrcpy(&demand->Name, parser->Comment, MAXMSG); + if (parser->Comment[0]) + { + demand->Name = xstrcpy(&demand->Name, parser->Comment, MAXID); + } hyd->NodeDemand[j] = MISSING; // marker - next iteration will append a new category. } @@ -759,7 +758,11 @@ int demanddata(Project *pr) if (demand == NULL) return 101; demand->Base = y; demand->Pat = p; - demand->Name = xstrcpy(&demand->Name, parser->Comment, MAXMSG); + demand->Name = NULL; + if (parser->Comment[0]) + { + demand->Name = xstrcpy(&demand->Name, parser->Comment, MAXID); + } demand->next = NULL; cur_demand->next = demand; } @@ -900,7 +903,6 @@ int sourcedata(Project *pr) p = 0; // Time pattern index char type = CONCEN; // Source type double c0 = 0; // Initial quality - STmplist *patlist; Psource source; // Check for enough tokens & that source node exists @@ -929,9 +931,8 @@ int sourcedata(Project *pr) if (n > i + 1 && strlen(parser->Tok[i + 1]) > 0 && strcmp(parser->Tok[i + 1], "*") != 0) { - patlist = getlistitem(parser->Tok[i + 1], parser->Patlist); - if (patlist == NULL) return setError(parser, i+1, 205); - p = patlist->i; + p = findpattern(net, parser->Tok[i + 1]); + if (p == 0) return setError(parser, i + 1, 205); } // Destroy any existing source assigned to node @@ -1335,10 +1336,9 @@ int energydata(Project *pr) Hydraul *hyd = &pr->hydraul; Parser *parser = &pr->parser; - int j, k, n; + int j, k, n, p, c; double y; - STmplist *listitem; Slink *Link = net->Link; Spump *Pump = net->Pump; @@ -1385,10 +1385,10 @@ int energydata(Project *pr) // Price PATTERN being set else if (match(parser->Tok[n - 2], w_PATTERN)) { - listitem = getlistitem(parser->Tok[n - 1], parser->Patlist); - if (listitem == NULL) return setError(parser, n - 1, 205); - if (j == 0) hyd->Epat = listitem->i; - else Pump[j].Epat = listitem->i; + p = findpattern(net, parser->Tok[n - 1]); + if (p == 0) return setError(parser, n - 1, 205); + if (j == 0) hyd->Epat = p; + else Pump[j].Epat = p; return 0; } @@ -1403,10 +1403,10 @@ int energydata(Project *pr) } else { - listitem = getlistitem(parser->Tok[n - 1], parser->Curvelist); - if (listitem == NULL) return setError(parser, n - 1, 206); - Pump[j].Ecurve = listitem->i; - net->Curve[listitem->i].Type = EFFIC_CURVE; + c = findcurve(net, parser->Tok[n - 1]); + if (c == 0) return setError(parser, n - 1, 206); + Pump[j].Ecurve = c; + net->Curve[c].Type = EFFIC_CURVE; } return 0; } diff --git a/src/project.c b/src/project.c index a2e5654..1ee3295 100644 --- a/src/project.c +++ b/src/project.c @@ -7,7 +7,7 @@ Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE - Last Updated: 03/17/2019 + Last Updated: 04/03/2019 ****************************************************************************** */ @@ -274,9 +274,6 @@ void initpointers(Project *pr) pr->network.NodeHashTable = NULL; pr->network.LinkHashTable = NULL; - pr->parser.Patlist = NULL; - pr->parser.Curvelist = NULL; - pr->hydraul.smatrix.Aii = NULL; pr->hydraul.smatrix.Aij = NULL; pr->hydraul.smatrix.F = NULL; @@ -317,10 +314,10 @@ int allocdata(Project *pr) if (!errcode) { n = pr->parser.MaxNodes + 1; - pr->network.Node = (Snode *)calloc(n, sizeof(Snode)); + pr->network.Node = (Snode *)calloc(n, sizeof(Snode)); pr->hydraul.NodeDemand = (double *)calloc(n, sizeof(double)); pr->hydraul.NodeHead = (double *)calloc(n, sizeof(double)); - pr->quality.NodeQual = (double *)calloc(n, sizeof(double)); + pr->quality.NodeQual = (double *)calloc(n, sizeof(double)); ERRCODE(MEMCHECK(pr->network.Node)); ERRCODE(MEMCHECK(pr->hydraul.NodeDemand)); ERRCODE(MEMCHECK(pr->hydraul.NodeHead)); @@ -331,8 +328,8 @@ int allocdata(Project *pr) if (!errcode) { n = pr->parser.MaxLinks + 1; - pr->network.Link = (Slink *)calloc(n, sizeof(Slink)); - pr->hydraul.LinkFlow = (double *)calloc(n, sizeof(double)); + pr->network.Link = (Slink *)calloc(n, sizeof(Slink)); + pr->hydraul.LinkFlow = (double *)calloc(n, sizeof(double)); pr->hydraul.LinkSetting = (double *)calloc(n, sizeof(double)); pr->hydraul.LinkStatus = (StatusType *)calloc(n, sizeof(StatusType)); ERRCODE(MEMCHECK(pr->network.Link)); @@ -341,8 +338,8 @@ int allocdata(Project *pr) ERRCODE(MEMCHECK(pr->hydraul.LinkStatus)); } - // Allocate memory for tanks, sources, pumps, valves, - // controls, demands, time patterns, & operating curves + // Allocate memory for tanks, sources, pumps, valves, and controls + // (memory for Patterns and Curves arrays expanded as each is added) if (!errcode) { pr->network.Tank = @@ -353,35 +350,15 @@ int allocdata(Project *pr) (Svalve *)calloc(pr->parser.MaxValves + 1, sizeof(Svalve)); pr->network.Control = (Scontrol *)calloc(pr->parser.MaxControls + 1, sizeof(Scontrol)); - pr->network.Pattern = - (Spattern *)calloc(pr->parser.MaxPats + 1, sizeof(Spattern)); - pr->network.Curve = - (Scurve *)calloc(pr->parser.MaxCurves + 1, sizeof(Scurve)); ERRCODE(MEMCHECK(pr->network.Tank)); ERRCODE(MEMCHECK(pr->network.Pump)); ERRCODE(MEMCHECK(pr->network.Valve)); ERRCODE(MEMCHECK(pr->network.Control)); - ERRCODE(MEMCHECK(pr->network.Pattern)); - ERRCODE(MEMCHECK(pr->network.Curve)); } - // Initialize pointers used in patterns, curves, and demand category lists + // Initialize pointers used in nodes and links if (!errcode) { - for (n = 0; n <= pr->parser.MaxPats; n++) - { - pr->network.Pattern[n].Length = 0; - pr->network.Pattern[n].F = NULL; - pr->network.Pattern[n].Comment = NULL; - } - for (n = 0; n <= pr->parser.MaxCurves; n++) - { - pr->network.Curve[n].Npts = 0; - pr->network.Curve[n].Type = GENERIC_CURVE; - pr->network.Curve[n].X = NULL; - pr->network.Curve[n].Y = NULL; - pr->network.Curve[n].Comment = NULL; - } for (n = 0; n <= pr->parser.MaxNodes; n++) { pr->network.Node[n].D = NULL; // node demand @@ -399,43 +376,6 @@ int allocdata(Project *pr) return errcode; } -void freeTmplist(STmplist *t) -/*---------------------------------------------------------------- -** Input: t = pointer to start of a temporary list -** Output: none -** Purpose: frees memory used for temporary storage -** of pattern & curve data -**---------------------------------------------------------------- -*/ -{ - STmplist *tnext; - while (t != NULL) - { - tnext = t->next; - freeFloatlist(t->x); - freeFloatlist(t->y); - free(t); - t = tnext; - } -} - -void freeFloatlist(SFloatlist *f) -/*---------------------------------------------------------------- -** Input: f = pointer to start of list of floats -** Output: none -** Purpose: frees memory used for storing list of floats -**---------------------------------------------------------------- -*/ -{ - SFloatlist *fnext; - while (f != NULL) - { - fnext = f->next; - free(f); - f = fnext; - } -} - void freedata(Project *pr) /*---------------------------------------------------------------- ** Input: none @@ -446,7 +386,6 @@ void freedata(Project *pr) { int j; Pdemand demand, nextdemand; - Psource source; // Free memory for computed results free(pr->hydraul.NodeDemand); @@ -474,8 +413,7 @@ void freedata(Project *pr) demand = nextdemand; } // Free memory used for WQ source data - source = pr->network.Node[j].S; - free(source); + free(pr->network.Node[j].S); free(pr->network.Node[j].Comment); } free(pr->network.Node); @@ -511,7 +449,8 @@ void freedata(Project *pr) // Free memory for curves if (pr->network.Curve != NULL) { - for (j = 0; j <= pr->parser.MaxCurves; j++) + // There is no Curve[0] + for (j = 1; j <= pr->parser.MaxCurves; j++) { free(pr->network.Curve[j].X); free(pr->network.Curve[j].Y); @@ -809,6 +748,40 @@ int findvalve(Network *network, int index) return NOTFOUND; } +int findpattern(Network *network, char *id) +/*---------------------------------------------------------------- +** Input: id = time pattern ID +** Output: none +** Returns: time pattern index, or 0 if pattern not found +** Purpose: finds index of time pattern given its ID +**---------------------------------------------------------------- +*/ +{ + int i; + for (i = 1; i <= network->Npats; i++) + { + if (strcmp(id, network->Pattern[i].ID) == 0) return i; + } + return 0; +} + +int findcurve(Network *network, char *id) +/*---------------------------------------------------------------- +** Input: id = data curve ID +** Output: none +** Returns: data curve index, or 0 if curve not found +** Purpose: finds index of data curve given its ID +**---------------------------------------------------------------- +*/ +{ + int i; + for (i = 1; i <= network->Ncurves; i++) + { + if (strcmp(id, network->Curve[i].ID) == 0) return i; + } + return 0; +} + void adjustpattern(int *pat, int index) /*---------------------------------------------------------------- ** Local function that modifies a reference to a deleted time pattern @@ -904,6 +877,35 @@ void adjustcurves(Network *network, int index) } } +int resizecurve(Scurve *curve, int size) +/*---------------------------------------------------------------- +** Input: curve = a data curve object +** size = desired number of curve data points +** Output: error code +** Purpose: resizes a data curve to a desired size +**---------------------------------------------------------------- +*/ +{ + double *x; + double *y; + + if (curve->Capacity < size) + { + x = (double *)realloc(curve->X, size * sizeof(double)); + if (x == NULL) return 101; + y = (double *)realloc(curve->Y, size * sizeof(double)); + if (y == NULL) + { + free(x); + return 101; + } + curve->X = x; + curve->Y = y; + curve->Capacity = size; + } + return 0; +} + int getcomment(Network *network, int object, int index, char *comment) //---------------------------------------------------------------- // Input: object = a type of network object diff --git a/src/types.h b/src/types.h index 0f574ce..476afac 100755 --- a/src/types.h +++ b/src/types.h @@ -317,23 +317,6 @@ struct IDstring // Holds component ID label char ID[MAXID+1]; }; -struct Floatlist // Element of List of Numbers -{ - double value; // element's numerical value - struct Floatlist *next; // next element on the list -}; -typedef struct Floatlist SFloatlist; - -struct Tmplist // Item of Temporary List of Objects -{ - int i; // object's index - char ID[MAXID+1]; // object's ID name - SFloatlist *x; // list of data values - SFloatlist *y; // list of data values - struct Tmplist *next; // next object on list -}; -typedef struct Tmplist STmplist; // Pointer to temporary list of objects - typedef struct // Time Pattern Object { char ID[MAXID+1]; // pattern ID @@ -348,6 +331,7 @@ typedef struct // Curve Object char *Comment; // curve comment CurveType Type; // curve type int Npts; // number of points + int Capacity; // size of X & Y arrays double *X; // x-values double *Y; // y-values } Scurve; @@ -576,12 +560,8 @@ typedef struct { Pressflag, // Pressure units flag DefPat; // Default demand pattern - STmplist - *Patlist, // Temporary time pattern list - *PrevPat, // Previous pattern list element - *Curvelist, // Temporary list of curves - *PrevCurve; // Previous curve list element - + Spattern *PrevPat; // Previous pattern processed + Scurve *PrevCurve; // Previous curve processed double *X; // Temporary array for curve data } Parser; From b2a8b55bc64e0c6fc8ea6508efba19e0a118fe5a Mon Sep 17 00:00:00 2001 From: Lew Rossman Date: Fri, 5 Apr 2019 16:28:55 -0400 Subject: [PATCH 2/2] Update input2.c --- src/input2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/input2.c b/src/input2.c index 482103e..5adb3e4 100644 --- a/src/input2.c +++ b/src/input2.c @@ -564,6 +564,7 @@ int addcurve(Network *network, char *id) // Initialize the curve curve = &network->Curve[network->Ncurves]; strncpy(curve->ID, id, MAXID); + curve->Type = GENERIC_CURVE; curve->Comment = NULL; curve->Capacity = 0; curve->Npts = 0;