diff --git a/src/epanet.c b/src/epanet.c index 447e98f..c1bfbfe 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -7,7 +7,7 @@ Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE - Last Updated: 02/14/2025 + Last Updated: 04/19/2025 ****************************************************************************** */ @@ -3397,7 +3397,7 @@ int DLLEXPORT EN_addlink(EN_Project p, const char *id, int linkType, link->Type = linkType; link->N1 = n1; link->N2 = n2; - link->Status = OPEN; + link->InitStatus = OPEN; if (linkType == PUMP) { @@ -3426,12 +3426,13 @@ int DLLEXPORT EN_addlink(EN_Project p, const char *id, int linkType, link->Kc = 0.0; // Valve setting. link->Km = 0.0; // Loss coeff link->Len = 0.0; - link->Status = ACTIVE; + link->InitStatus = ACTIVE; } link->Kb = 0; link->Kw = 0; link->LeakArea = 0; link->LeakExpan = 0; + link->InitSetting = link->Kc; link->R = 0; link->Rc = 0; link->Rpt = 0; @@ -3685,7 +3686,7 @@ int DLLEXPORT EN_setlinktype(EN_Project p, int *index, int linkType, int actionC if (oldType <= PIPE && linkType <= PIPE) { net->Link[i].Type = linkType; - if (linkType == CVPIPE) net->Link[i].Status = OPEN; + if (linkType == CVPIPE) net->Link[i].InitStatus = OPEN; return 0; } @@ -3788,8 +3789,6 @@ int DLLEXPORT EN_getlinkvalue(EN_Project p, int index, int property, double *val Slink *Link = net->Link; Spump *Pump = net->Pump; double *Ucf = p->Ucf; - double *LinkFlow = hyd->LinkFlow; - double *LinkSetting = hyd->LinkSetting; // Check for valid arguments *value = 0.0; @@ -3827,18 +3826,19 @@ int DLLEXPORT EN_getlinkvalue(EN_Project p, int index, int property, double *val break; case EN_INITSTATUS: - if (Link[index].Status <= CLOSED) v = 0.0; + if (Link[index].InitStatus <= CLOSED) v = 0.0; else v = 1.0; + if (Link[index].Type > PUMP && Link[index].InitStatus > OPEN) v = 2.0; break; case EN_INITSETTING: - if (Link[index].Type == PIPE || Link[index].Type == CVPIPE) - { - return EN_getlinkvalue(p, index, EN_ROUGHNESS, value); - } - v = Link[index].Kc; + v = Link[index].InitSetting; switch (Link[index].Type) { + case CVPIPE: + case PIPE: + if (hyd->Formflag == DW) v = v * (1000.0 * Ucf[ELEV]); + break; case PRV: case PSV: case PBV: @@ -3849,9 +3849,6 @@ int DLLEXPORT EN_getlinkvalue(EN_Project p, int index, int property, double *val default: break; } - if (Link[index].Kc == MISSING) { - v = MISSING; - } break; case EN_KBULK: @@ -3864,7 +3861,7 @@ int DLLEXPORT EN_getlinkvalue(EN_Project p, int index, int property, double *val case EN_FLOW: if (hyd->LinkStatus[index] <= CLOSED) v = 0.0; - else v = LinkFlow[index] * Ucf[FLOW]; + else v = hyd->LinkFlow[index] * Ucf[FLOW]; break; case EN_VELOCITY: @@ -3872,7 +3869,7 @@ int DLLEXPORT EN_getlinkvalue(EN_Project p, int index, int property, double *val else if (hyd->LinkStatus[index] <= CLOSED) v = 0.0; else { - q = ABS(LinkFlow[index]); + q = ABS(hyd->LinkFlow[index]); a = PI * SQR(Link[index].Diam) / 4.0; v = q / a * Ucf[VELOCITY]; } @@ -3891,6 +3888,8 @@ int DLLEXPORT EN_getlinkvalue(EN_Project p, int index, int property, double *val case EN_STATUS: if (hyd->LinkStatus[index] <= CLOSED) v = 0.0; else v = 1.0; + if (Link[index].Type > PUMP && + hyd->LinkStatus[index] > OPEN) v = 2.0; break; case EN_SETTING: @@ -3898,8 +3897,8 @@ int DLLEXPORT EN_getlinkvalue(EN_Project p, int index, int property, double *val { return EN_getlinkvalue(p, index, EN_ROUGHNESS, value); } - if (LinkSetting[index] == MISSING) v = 0.0; - else v = LinkSetting[index]; + if (hyd->LinkSetting[index] == MISSING) v = 0.0; + else v = hyd->LinkSetting[index]; switch (Link[index].Type) { case PRV: @@ -4059,7 +4058,6 @@ int DLLEXPORT EN_setlinkvalue(EN_Project p, int index, int property, double valu Slink *Link = net->Link; double *Ucf = p->Ucf; - double *LinkSetting = hyd->LinkSetting; char s; double r; int pumpIndex, patIndex, curveIndex; @@ -4095,7 +4093,8 @@ int DLLEXPORT EN_setlinkvalue(EN_Project p, int index, int property, double valu if (value <= 0.0) return 211; Link[index].Kc = value; if (hyd->Formflag == DW) Link[index].Kc /= (1000.0 * Ucf[ELEV]); - resistcoeff(p, index); + if (p->hydraul.OpenHflag) resistcoeff(p, index); + else Link[index].InitSetting = Link[index].Kc; } break; @@ -4113,14 +4112,15 @@ int DLLEXPORT EN_setlinkvalue(EN_Project p, int index, int property, double valu // Cannot set status for a check valve if (Link[index].Type == CVPIPE) return 207; s = (char)ROUND(value); - if (s < 0 || s > 1) return 211; + if (s < 0 || s > 2) return 211; + s = s + CLOSED; if (property == EN_INITSTATUS) { - setlinkstatus(p, index, s, &Link[index].Status, &Link[index].Kc); + Link[index].InitStatus = s; } else { - setlinkstatus(p, index, s, &hyd->LinkStatus[index], &LinkSetting[index]); + setlinkstatus(p, index, s, &hyd->LinkStatus[index], &hyd->LinkSetting[index]); } break; @@ -4128,7 +4128,8 @@ int DLLEXPORT EN_setlinkvalue(EN_Project p, int index, int property, double valu case EN_SETTING: if (Link[index].Type == PIPE || Link[index].Type == CVPIPE) { - return EN_setlinkvalue(p, index, EN_ROUGHNESS, value); + EN_setlinkvalue(p, index, EN_ROUGHNESS, value); + if (property == EN_INITSETTING) Link[index].InitSetting = Link[index].Kc; } else { @@ -4155,12 +4156,13 @@ int DLLEXPORT EN_setlinkvalue(EN_Project p, int index, int property, double valu } if (property == EN_INITSETTING) { - setlinksetting(p, index, value, &Link[index].Status, &Link[index].Kc); + Link[index].Kc = value; + Link[index].InitSetting = value; } else { setlinksetting(p, index, value, &hyd->LinkStatus[index], - &LinkSetting[index]); + &hyd->LinkSetting[index]); } } break; @@ -4253,6 +4255,7 @@ int DLLEXPORT EN_setlinkvalue(EN_Project p, int index, int property, double valu curveIndex = ROUND(value); if (curveIndex < 0 || curveIndex > net->Ncurves) return 206; Link[index].Kc = curveIndex; + if (hyd->OpenHflag == FALSE) Link[index].InitSetting = curveIndex; } break; diff --git a/src/hydraul.c b/src/hydraul.c index ae40ad6..903e7b9 100755 --- a/src/hydraul.c +++ b/src/hydraul.c @@ -1,13 +1,13 @@ /* ****************************************************************************** Project: OWA EPANET - Version: 2.2 + Version: 2.3 Module: hydraul.c Description: implements EPANET's hydraulic engine Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE - Last Updated: 06/26/2024 + Last Updated: 04/19/2025 ****************************************************************************** */ @@ -71,7 +71,7 @@ int openhyd(Project *pr) if (!errcode) for (i = 1; i <= pr->network.Nlinks; i++) { link = &pr->network.Link[i]; - initlinkflow(pr, i, link->Status, link->Kc); + initlinkflow(pr, i, link->InitStatus, link->Kc); } else closehyd(pr); return errcode; @@ -124,9 +124,22 @@ void inithyd(Project *pr, int initflag) link->ResultIndex = i; // Initialize status and setting - hyd->LinkStatus[i] = link->Status; - hyd->LinkSetting[i] = link->Kc; - + hyd->LinkStatus[i] = link->InitStatus; + hyd->LinkSetting[i] = link->InitSetting; + + // Setting of non-ACTIVE FCV, PRV, PSV valves is "MISSING" + switch (link->Type) + { + case FCV: + case PRV: + case PSV: + if (link->InitStatus != ACTIVE) + { + link->Kc = MISSING; + hyd->LinkSetting[i] = MISSING; + } + } + // Compute flow resistance resistcoeff(pr, i); diff --git a/src/inpfile.c b/src/inpfile.c index 84ff42e..2968353 100644 --- a/src/inpfile.c +++ b/src/inpfile.c @@ -7,7 +7,7 @@ Description: saves network data to an EPANET formatted text file Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE -Last Updated: 03/11/2025 +Last Updated: 04/19/2025 ****************************************************************************** */ @@ -210,7 +210,7 @@ int saveinpfile(Project *pr, const char *fname) if (link->Type <= PIPE) { d = link->Diam; - kc = link->Kc; + kc = link->InitSetting; if (hyd->Formflag == DW) kc = kc * pr->Ucf[ELEV] * 1000.0; km = link->Km * SQR(d) * SQR(d) / 0.02517; @@ -219,7 +219,7 @@ int saveinpfile(Project *pr, const char *fname) link->Len * pr->Ucf[LENGTH], d * pr->Ucf[DIAM], kc, km); if (link->Type == CVPIPE) sprintf(s2, "CV"); - else if (link->Status == CLOSED) sprintf(s2, "CLOSED"); + else if (link->InitStatus == CLOSED) sprintf(s2, "CLOSED"); else strcpy(s2, " "); fprintf(f, "\n%s\t%-6s", s, s2); if (link->Comment) fprintf(f, "\t;%s", link->Comment); @@ -267,9 +267,9 @@ int saveinpfile(Project *pr, const char *fname) } // Optional speed setting - if (link->Kc != 1.0) + if (link->InitSetting != 1.0) { - sprintf(s1, "\tSPEED %.4f", link->Kc); + sprintf(s1, "\tSPEED %.4f", link->InitSetting); strcat(s, s1); } @@ -289,8 +289,7 @@ int saveinpfile(Project *pr, const char *fname) d = link->Diam; // Valve setting - kc = link->Kc; - if (kc == MISSING) kc = 0.0; + kc = link->InitSetting; switch (link->Type) { case FCV: @@ -312,7 +311,7 @@ int saveinpfile(Project *pr, const char *fname) LinkTxt[link->Type]); // For GPV, setting = head curve index - if (link->Type == GPV && (j = ROUND(link->Kc)) > 0) + if (link->Type == GPV && (j = ROUND(kc)) > 0) { sprintf(s1, "%-31s\t%-12.4f", net->Curve[j].ID, km); } @@ -384,7 +383,7 @@ int saveinpfile(Project *pr, const char *fname) link = &net->Link[i]; if (link->Type <= PUMP) { - if (link->Status == CLOSED) + if (link->InitStatus == CLOSED) { fprintf(f, "\n %-31s\t%s", link->ID, StatTxt[CLOSED]); } @@ -395,21 +394,21 @@ int saveinpfile(Project *pr, const char *fname) n = findpump(net, i); pump = &net->Pump[n]; if (pump->Hcurve == 0 && pump->Ptype != CONST_HP && - link->Kc != 1.0) + link->InitSetting != 1.0) { - fprintf(f, "\n %-31s\t%-.4f", link->ID, link->Kc); + fprintf(f, "\n %-31s\t%-.4f", link->ID, link->InitSetting); } } } - // Write fixed-status PRVs & PSVs (setting = MISSING) - else if (link->Kc == MISSING) + // Write fixed-status valves + else { - if (link->Status == OPEN) + if (link->InitStatus == OPEN) { fprintf(f, "\n %-31s\t%s", link->ID, StatTxt[OPEN]); } - if (link->Status == CLOSED) + if (link->InitStatus == CLOSED) { fprintf(f, "\n%-31s\t%s", link->ID, StatTxt[CLOSED]); } diff --git a/src/input1.c b/src/input1.c index 1074dec..ad15dba 100644 --- a/src/input1.c +++ b/src/input1.c @@ -1,13 +1,13 @@ /* ****************************************************************************** Project: OWA EPANET -Version: 2.2 +Version: 2.3 Module: input1.c Description: retrieves network data from an EPANET input file Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE -Last Updated: 06/15/2024 +Last Updated: 04/19/2025 ****************************************************************************** */ @@ -624,6 +624,7 @@ void convertunits(Project *pr) break; } } + link->InitSetting = link->Kc; } // Convert units on control settings diff --git a/src/input3.c b/src/input3.c index 8568379..df12783 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/10/2025 +Last Updated: 04/19/2025 ****************************************************************************** */ @@ -391,7 +391,8 @@ int pipedata(Project *pr) link->LeakArea = 0.0; link->LeakExpan = 0.0; link->Type = PIPE; - link->Status = OPEN; + link->InitStatus = OPEN; + link->InitSetting = link->Kc; link->Rpt = 0; link->ResultIndex = 0; link->Comment = xstrcpy(&link->Comment, parser->Comment, MAXMSG); @@ -420,8 +421,8 @@ int pipedata(Project *pr) if (n > 6) { if (match(parser->Tok[6], w_CV)) link->Type = CVPIPE; - else if (match(parser->Tok[6], w_CLOSED)) link->Status = CLOSED; - else if (match(parser->Tok[6], w_OPEN)) link->Status = OPEN; + else if (match(parser->Tok[6], w_CLOSED)) link->InitStatus = CLOSED; + else if (match(parser->Tok[6], w_OPEN)) link->InitStatus = OPEN; else { if (!getfloat(parser->Tok[6], &x) || x < 0.0) @@ -437,8 +438,8 @@ int pipedata(Project *pr) return setError(parser, 6, 202); link->Km = x; if (match(parser->Tok[7], w_CV)) link->Type = CVPIPE; - else if (match(parser->Tok[7], w_CLOSED)) link->Status = CLOSED; - else if (match(parser->Tok[7], w_OPEN)) link->Status = OPEN; + else if (match(parser->Tok[7], w_CLOSED)) link->InitStatus = CLOSED; + else if (match(parser->Tok[7], w_OPEN)) link->InitStatus = OPEN; else return setError(parser, 7, 213); } return 0; @@ -500,7 +501,8 @@ int pumpdata(Project *pr) link->LeakArea = 0.0; link->LeakExpan = 0.0; link->Type = PUMP; - link->Status = OPEN; + link->InitStatus = OPEN; + link->InitSetting = 1.0; link->Rpt = 0; link->ResultIndex = 0; link->Comment = xstrcpy(&link->Comment, parser->Comment, MAXMSG); @@ -545,6 +547,7 @@ int pumpdata(Project *pr) else return setError(parser, m-1, 201);; m = m + 2; // Move to next keyword token } + link->InitSetting = link->Kc; return 0; } @@ -621,7 +624,8 @@ int valvedata(Project *pr) link->LeakArea = 0.0; link->LeakExpan = 0.0; link->Type = type; - link->Status = ACTIVE; + link->InitStatus = ACTIVE; + link->InitSetting = 0.0; link->Rpt = 0; link->ResultIndex = 0; link->Comment = xstrcpy(&link->Comment, parser->Comment, MAXMSG); @@ -641,7 +645,7 @@ int valvedata(Project *pr) if (c == 0) return setError(parser, 5, 206); link->Kc = c; net->Curve[c].Type = HLOSS_CURVE; - link->Status = OPEN; + link->InitStatus = OPEN; } else { @@ -663,7 +667,8 @@ int valvedata(Project *pr) net->Valve[net->Nvalves].Curve = c; net->Curve[c].Type = VALVE_CURVE; if (link->Kc > 100.0) link->Kc = 100.0; - } + } + link->InitSetting = link->Kc; return 0; } @@ -2212,7 +2217,8 @@ int tagdata(Project *pr) xstrcpy(&net->Link[j].Tag, parser->Tok[2], MAXMSG); } return 0; -} +} + void changestatus(Network *net, int j, StatusType status, double y) /* **-------------------------------------------------------------- @@ -2221,11 +2227,10 @@ void changestatus(Network *net, int j, StatusType status, double y) ** y = numerical setting (pump speed, valve ** setting) ** Output: none -** Purpose: changes status or setting of a link +** Purpose: changes initial status or setting of a link ** ** NOTE: If status = ACTIVE, then a numerical setting (y) was -** supplied. If status = OPEN/CLOSED, then numerical -** setting is 0. +** supplied. **-------------------------------------------------------------- */ { @@ -2233,7 +2238,7 @@ void changestatus(Network *net, int j, StatusType status, double y) if (link->Type == PIPE || link->Type == GPV) { - if (status != ACTIVE) link->Status = status; + if (status != ACTIVE) link->InitStatus = status; } else if (link->Type == PUMP) { @@ -2245,12 +2250,13 @@ void changestatus(Network *net, int j, StatusType status, double y) } else if (status == OPEN) link->Kc = 1.0; else if (status == CLOSED) link->Kc = 0.0; - link->Status = status; + link->InitStatus = status; + link->InitSetting = link->Kc; } else if (link->Type >= PRV) { - link->Kc = y; - link->Status = status; - if (status != ACTIVE) link->Kc = MISSING; + if (status == ACTIVE) link->Kc = y; + link->InitStatus = status; + link->InitSetting = link->Kc; } } diff --git a/src/types.h b/src/types.h index 53b97b1..2bd2629 100755 --- a/src/types.h +++ b/src/types.h @@ -7,7 +7,7 @@ Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE - Last Updated: 02/14/2025 + Last Updated: 04/19/2025 ****************************************************************************** */ @@ -408,7 +408,7 @@ typedef struct // Link Object int N2; // end node index double Diam; // diameter double Len; // length - double Kc; // roughness + double Kc; // pipe roughness, pump speed, valve setting double Km; // minor loss coeff. double Kb; // bulk react. coeff. double Kw; // wall react. coef. @@ -417,7 +417,8 @@ typedef struct // Link Object double LeakArea; // leak area (sq mm per 100 pipe length units double LeakExpan; // leak expansion (sq mm per unit of head) LinkType Type; // link type - StatusType Status; // initial status + StatusType InitStatus; // initial status + double InitSetting; // initial setting Pvertices Vertices; // internal vertex coordinates int Rpt; // reporting flag int ResultIndex; // saved result index