epyt-flow 0.14.1__py3-none-any.whl → 0.14.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. epyt_flow/EPANET/EPANET/SRC_engines/AUTHORS +8 -40
  2. epyt_flow/EPANET/EPANET/SRC_engines/LICENSE +3 -3
  3. epyt_flow/EPANET/EPANET/SRC_engines/Readme_SRC_Engines.txt +18 -0
  4. epyt_flow/EPANET/EPANET/SRC_engines/enumstxt.h +7 -24
  5. epyt_flow/EPANET/EPANET/SRC_engines/epanet.c +374 -726
  6. epyt_flow/EPANET/EPANET/SRC_engines/epanet2.c +32 -128
  7. epyt_flow/EPANET/EPANET/SRC_engines/epanet2.def +131 -0
  8. epyt_flow/EPANET/EPANET/SRC_engines/errors.dat +1 -7
  9. epyt_flow/EPANET/EPANET/SRC_engines/funcs.h +14 -40
  10. epyt_flow/EPANET/EPANET/SRC_engines/hash.c +177 -177
  11. epyt_flow/EPANET/EPANET/SRC_engines/hash.h +28 -28
  12. epyt_flow/EPANET/EPANET/SRC_engines/hydcoeffs.c +40 -192
  13. epyt_flow/EPANET/EPANET/SRC_engines/hydraul.c +46 -101
  14. epyt_flow/EPANET/EPANET/SRC_engines/hydsolver.c +24 -85
  15. epyt_flow/EPANET/EPANET/SRC_engines/hydstatus.c +63 -29
  16. epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2.h +37 -70
  17. epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2_2.h +234 -408
  18. epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2_enums.h +37 -87
  19. epyt_flow/EPANET/EPANET/SRC_engines/inpfile.c +79 -153
  20. epyt_flow/EPANET/EPANET/SRC_engines/input1.c +94 -59
  21. epyt_flow/EPANET/EPANET/SRC_engines/input2.c +202 -73
  22. epyt_flow/EPANET/EPANET/SRC_engines/input3.c +351 -446
  23. epyt_flow/EPANET/EPANET/SRC_engines/main.c +93 -0
  24. epyt_flow/EPANET/EPANET/SRC_engines/mempool.c +4 -8
  25. epyt_flow/EPANET/EPANET/SRC_engines/mempool.h +23 -23
  26. epyt_flow/EPANET/EPANET/SRC_engines/output.c +4 -5
  27. epyt_flow/EPANET/EPANET/SRC_engines/project.c +75 -407
  28. epyt_flow/EPANET/EPANET/SRC_engines/quality.c +2 -12
  29. epyt_flow/EPANET/EPANET/SRC_engines/qualreact.c +13 -70
  30. epyt_flow/EPANET/EPANET/SRC_engines/qualroute.c +5 -7
  31. epyt_flow/EPANET/EPANET/SRC_engines/report.c +20 -88
  32. epyt_flow/EPANET/EPANET/SRC_engines/rules.c +6 -144
  33. epyt_flow/EPANET/EPANET/SRC_engines/smatrix.c +19 -19
  34. epyt_flow/EPANET/EPANET/SRC_engines/text.h +5 -16
  35. epyt_flow/EPANET/EPANET/SRC_engines/types.h +19 -73
  36. epyt_flow/EPANET/compile_linux.sh +1 -1
  37. epyt_flow/EPANET/compile_macos.sh +1 -1
  38. epyt_flow/VERSION +1 -1
  39. epyt_flow/simulation/scada/scada_data.py +1 -1
  40. epyt_flow/utils.py +66 -0
  41. epyt_flow/visualization/visualization_utils.py +4 -2
  42. {epyt_flow-0.14.1.dist-info → epyt_flow-0.14.2.dist-info}/METADATA +1 -1
  43. {epyt_flow-0.14.1.dist-info → epyt_flow-0.14.2.dist-info}/RECORD +46 -52
  44. epyt_flow/EPANET/EPANET/SRC_engines/flowbalance.c +0 -186
  45. epyt_flow/EPANET/EPANET/SRC_engines/leakage.c +0 -527
  46. epyt_flow/EPANET/EPANET/SRC_engines/util/cstr_helper.c +0 -59
  47. epyt_flow/EPANET/EPANET/SRC_engines/util/cstr_helper.h +0 -38
  48. epyt_flow/EPANET/EPANET/SRC_engines/util/errormanager.c +0 -92
  49. epyt_flow/EPANET/EPANET/SRC_engines/util/errormanager.h +0 -39
  50. epyt_flow/EPANET/EPANET/SRC_engines/util/filemanager.c +0 -212
  51. epyt_flow/EPANET/EPANET/SRC_engines/util/filemanager.h +0 -81
  52. epyt_flow/EPANET/EPANET/SRC_engines/validate.c +0 -408
  53. {epyt_flow-0.14.1.dist-info → epyt_flow-0.14.2.dist-info}/WHEEL +0 -0
  54. {epyt_flow-0.14.1.dist-info → epyt_flow-0.14.2.dist-info}/licenses/LICENSE +0 -0
  55. {epyt_flow-0.14.1.dist-info → epyt_flow-0.14.2.dist-info}/top_level.txt +0 -0
@@ -1,13 +1,13 @@
1
1
  /*
2
2
  ******************************************************************************
3
3
  Project: OWA EPANET
4
- Version: 2.3
4
+ Version: 2.2
5
5
  Module: epanet.c
6
6
  Description: implementation of EPANET's API functions
7
7
  Authors: see AUTHORS
8
8
  Copyright: see AUTHORS
9
9
  License: see LICENSE
10
- Last Updated: 04/23/2025
10
+ Last Updated: 11/15/2019
11
11
  ******************************************************************************
12
12
  */
13
13
 
@@ -143,7 +143,7 @@ int DLLEXPORT EN_init(EN_Project p, const char *rptFile, const char *outFile,
143
143
  p->report.Rptflag = 1;
144
144
 
145
145
  // Check for valid arguments
146
- if (unitsType < 0 || unitsType > CMS) return 251;
146
+ if (unitsType < 0 || unitsType > CMD) return 251;
147
147
  if (headLossType < 0 || headLossType > CM) return 251;
148
148
 
149
149
  // Open files
@@ -179,29 +179,61 @@ int DLLEXPORT EN_open(EN_Project p, const char *inpFile, const char *rptFile,
179
179
  ** outFile = name of binary output file
180
180
  ** Output: none
181
181
  ** Returns: error code
182
- ** Purpose: reads an EPANET input file with no errors allowed.
183
- **----------------------------------------------------------------
184
- */
185
- {
186
- writewin(p->viewprog, FMT100);
187
- return openproject(p, inpFile, rptFile, outFile, FALSE);
188
- }
189
-
190
- int DLLEXPORT EN_openX(EN_Project p, const char *inpFile,
191
- const char *rptFile, const char *outFile)
192
- /*----------------------------------------------------------------
193
- ** Input: inpFile = name of input file
194
- ** rptFile = name of report file
195
- ** outFile = name of binary output file
196
- ** Output: none
197
- ** Returns: error code
198
- ** Purpose: reads an EPANET input file with errors allowed.
182
+ ** Purpose: opens an EPANET input file & reads in network data
199
183
  **----------------------------------------------------------------
200
184
  */
201
185
  {
202
- writewin(p->viewprog, FMT100);
203
- return openproject(p, inpFile, rptFile, outFile, TRUE);
204
- }
186
+ int errcode = 0;
187
+
188
+ // Set system flags
189
+ p->Openflag = FALSE;
190
+ p->hydraul.OpenHflag = FALSE;
191
+ p->quality.OpenQflag = FALSE;
192
+ p->outfile.SaveHflag = FALSE;
193
+ p->outfile.SaveQflag = FALSE;
194
+ p->Warnflag = FALSE;
195
+ p->report.Messageflag = TRUE;
196
+ p->report.Rptflag = 1;
197
+
198
+ // Initialize data arrays to NULL
199
+ initpointers(p);
200
+
201
+ // Open input & report files
202
+ ERRCODE(openfiles(p, inpFile, rptFile, outFile));
203
+ if (errcode > 0)
204
+ {
205
+ errmsg(p, errcode);
206
+ return errcode;
207
+ }
208
+
209
+ // Allocate memory for project's data arrays
210
+ writewin(p->viewprog, FMT100);
211
+ ERRCODE(netsize(p));
212
+ ERRCODE(allocdata(p));
213
+
214
+ // Read input data
215
+ ERRCODE(getdata(p));
216
+
217
+ // Close input file
218
+ if (p->parser.InFile != NULL)
219
+ {
220
+ fclose(p->parser.InFile);
221
+ p->parser.InFile = NULL;
222
+ }
223
+
224
+ // If using previously saved hydraulics file then open it
225
+ if (p->outfile.Hydflag == USE) ERRCODE(openhydfile(p));
226
+
227
+ // Write input summary to report file
228
+ if (!errcode)
229
+ {
230
+ if (p->report.Summaryflag) writesummary(p);
231
+ writetime(p, FMT104);
232
+ p->Openflag = TRUE;
233
+ }
234
+ else errmsg(p, errcode);
235
+ return errcode;
236
+ }
205
237
 
206
238
  int DLLEXPORT EN_gettitle(EN_Project p, char *line1, char *line2, char *line3)
207
239
  /*----------------------------------------------------------------
@@ -219,8 +251,7 @@ int DLLEXPORT EN_gettitle(EN_Project p, char *line1, char *line2, char *line3)
219
251
  return 0;
220
252
  }
221
253
 
222
- int DLLEXPORT EN_settitle(EN_Project p, const char *line1,
223
- const char *line2, const char *line3)
254
+ int DLLEXPORT EN_settitle(EN_Project p, char *line1, char *line2, char *line3)
224
255
  /*----------------------------------------------------------------
225
256
  ** Input: line1, line2, line3 = project's title lines
226
257
  ** Returns: error code
@@ -248,8 +279,7 @@ int DLLEXPORT EN_getcomment(EN_Project p, int object, int index, char *comment)
248
279
  return getcomment(&p->network, object, index, comment);
249
280
  }
250
281
 
251
- int DLLEXPORT EN_setcomment(EN_Project p, int object, int index,
252
- const char *comment)
282
+ int DLLEXPORT EN_setcomment(EN_Project p, int object, int index, char *comment)
253
283
  /*----------------------------------------------------------------
254
284
  ** Input: object = a type of object (see EN_ObjectType)
255
285
  ** index = the object's index
@@ -262,32 +292,6 @@ int DLLEXPORT EN_setcomment(EN_Project p, int object, int index,
262
292
  return setcomment(&p->network, object, index, comment);
263
293
  }
264
294
 
265
- int DLLEXPORT EN_gettag(EN_Project p, int object, int index, char *tag)
266
- /*----------------------------------------------------------------
267
- ** Input: object = either EN_NODE or EN_LINK
268
- ** index = the object's index
269
- ** Output: tag = the tag string assigned to the object
270
- ** Returns: error code
271
- ** Purpose: Retrieves an object's tag string
272
- **----------------------------------------------------------------
273
- */
274
- {
275
- return gettag(&p->network, object, index, tag);
276
- }
277
-
278
- int DLLEXPORT EN_settag(EN_Project p, int object, int index,
279
- const char *tag)
280
- /*----------------------------------------------------------------
281
- ** Input: object = either EN_NODE or EN_LINK
282
- ** index = the object's index
283
- ** tag = a descriptive comment to assign
284
- ** Returns: error code
285
- ** Purpose: Assigns a tag string to an object
286
- **----------------------------------------------------------------
287
- */
288
- {
289
- return settag(&p->network, object, index, tag);
290
- }
291
295
  int DLLEXPORT EN_getcount(EN_Project p, int object, int *count)
292
296
  /*----------------------------------------------------------------
293
297
  ** Input: object = type of object to count (see EN_CountType)
@@ -353,6 +357,7 @@ int DLLEXPORT EN_close(EN_Project p)
353
357
  */
354
358
  {
355
359
  // Free all project data
360
+ if (p->Openflag) writetime(p, FMT105);
356
361
  freedata(p);
357
362
 
358
363
  // Close output file
@@ -488,11 +493,7 @@ int DLLEXPORT EN_openH(EN_Project p)
488
493
 
489
494
  // Open hydraulics solver
490
495
  ERRCODE(openhyd(p));
491
- if (!errcode)
492
- {
493
- p->hydraul.OpenHflag = TRUE;
494
- writetime(p, FMT104);
495
- }
496
+ if (!errcode) p->hydraul.OpenHflag = TRUE;
496
497
  else errmsg(p, errcode);
497
498
  return errcode;
498
499
  }
@@ -535,10 +536,6 @@ int DLLEXPORT EN_initH(EN_Project p, int initFlag)
535
536
  return errcode;
536
537
  }
537
538
  }
538
-
539
- // Open pipe leakage modeling system
540
- errcode = openleakage(p);
541
- if (errcode) return errcode;
542
539
 
543
540
  // Initialize hydraulics solver
544
541
  inithyd(p, fflag);
@@ -593,11 +590,7 @@ int DLLEXPORT EN_closeH(EN_Project p)
593
590
  */
594
591
  {
595
592
  if (!p->Openflag) return 102;
596
- if (p->hydraul.OpenHflag)
597
- {
598
- closeleakage(p);
599
- closehyd(p);
600
- }
593
+ if (p->hydraul.OpenHflag) closehyd(p);
601
594
  p->hydraul.OpenHflag = FALSE;
602
595
  return 0;
603
596
  }
@@ -839,7 +832,6 @@ int DLLEXPORT EN_closeQ(EN_Project p)
839
832
  closequal(p);
840
833
  p->quality.OpenQflag = FALSE;
841
834
  closeoutfile(p);
842
- writetime(p, FMT105);
843
835
  return 0;
844
836
  }
845
837
 
@@ -849,35 +841,7 @@ int DLLEXPORT EN_closeQ(EN_Project p)
849
841
 
850
842
  ********************************************************************/
851
843
 
852
-
853
- int DLLEXPORT EN_setreportcallback(EN_Project p, void (*callback)(void*,void*,const char*))
854
- /*----------------------------------------------------------------
855
- ** Input: callback = a pointer to a reporting function
856
- ** Output: none
857
- ** Returns: error code
858
- ** Purpose: replaces EPANET's normal use of a designated report file
859
- **----------------------------------------------------------------
860
- */
861
- {
862
- p->report.reportCallback = callback;
863
- return 0;
864
- }
865
-
866
- int DLLEXPORT EN_setreportcallbackuserdata(EN_Project p, void *userData)
867
- /*----------------------------------------------------------------
868
- ** Input: userData = a pointer to a client-side data object
869
- ** Output: none
870
- ** Returns: error code
871
- ** Purpose: sets the client-side data object used in conjunction with
872
- ** the callback function in EN_setreportcallback
873
- **----------------------------------------------------------------
874
- */
875
- {
876
- p->report.reportCallbackUserData = userData;
877
- return 0;
878
- }
879
-
880
- int DLLEXPORT EN_writeline(EN_Project p, const char *line)
844
+ int DLLEXPORT EN_writeline(EN_Project p, char *line)
881
845
  /*----------------------------------------------------------------
882
846
  ** Input: line = line of text
883
847
  ** Output: none
@@ -913,7 +877,7 @@ int DLLEXPORT EN_report(EN_Project p)
913
877
  return errcode;
914
878
  }
915
879
 
916
- int DLLEXPORT EN_copyreport(EN_Project p, const char *filename)
880
+ int DLLEXPORT EN_copyreport(EN_Project p, char *filename)
917
881
  /*----------------------------------------------------------------
918
882
  ** Input: filename = name of file to receive copy of report
919
883
  ** Output: none
@@ -962,7 +926,7 @@ int DLLEXPORT EN_resetreport(EN_Project p)
962
926
  return 0;
963
927
  }
964
928
 
965
- int DLLEXPORT EN_setreport(EN_Project p, const char *format)
929
+ int DLLEXPORT EN_setreport(EN_Project p, char *format)
966
930
  /*----------------------------------------------------------------
967
931
  ** Input: format = a report formatting command
968
932
  ** Output: none
@@ -1019,7 +983,7 @@ int DLLEXPORT EN_getversion(int *version)
1019
983
 
1020
984
  int DLLEXPORT EN_geterror(int errcode, char *errmsg, int maxLen)
1021
985
  /*----------------------------------------------------------------
1022
- ** Input: errcode = an error or warning code
986
+ ** Input: errcode = an error or warnng code
1023
987
  ** maxLen = maximum characters that errmsg can hold
1024
988
  ** Output: errmsg = text of error/warning message
1025
989
  ** Returns: error code
@@ -1092,9 +1056,6 @@ int DLLEXPORT EN_getstatistic(EN_Project p, int type, double *value)
1092
1056
  case EN_DEMANDREDUCTION:
1093
1057
  *value = p->hydraul.DemandReduction;
1094
1058
  break;
1095
- case EN_LEAKAGELOSS:
1096
- *value = p->hydraul.LeakageLoss;
1097
- break;
1098
1059
  case EN_MASSBALANCE:
1099
1060
  *value = p->quality.MassBalance.ratio;
1100
1061
  break;
@@ -1226,18 +1187,7 @@ int DLLEXPORT EN_getoption(EN_Project p, int option, double *value)
1226
1187
  case EN_CONCENLIMIT:
1227
1188
  v = qual->Climit * p->Ucf[QUALITY];
1228
1189
  break;
1229
- case EN_DEMANDPATTERN:
1230
- v = hyd->DefPat;
1231
- break;
1232
- case EN_EMITBACKFLOW:
1233
- v = hyd->EmitBackFlag;
1234
- break;
1235
- case EN_PRESS_UNITS:
1236
- v = (double)p->parser.Pressflag;
1237
- break;
1238
- case EN_STATUS_REPORT:
1239
- v = (double)( p->report.Statflag);
1240
- break;
1190
+
1241
1191
  default:
1242
1192
  return 251;
1243
1193
  }
@@ -1261,12 +1211,9 @@ int DLLEXPORT EN_setoption(EN_Project p, int option, double value)
1261
1211
 
1262
1212
  int Njuncs = net->Njuncs;
1263
1213
  double *Ucf = p->Ucf;
1264
- int i, j, pat, unit;
1214
+ int i, j, pat;
1265
1215
  double Ke, n, ucf;
1266
1216
 
1267
- double qfactor, hfactor, pfactor, dfactor;
1268
- double dcf, pcf, hcf, qcf;
1269
-
1270
1217
  if (!p->Openflag) return 102;
1271
1218
 
1272
1219
  // The EN_UNBALANCED option can be < 0 indicating that the simulation
@@ -1283,7 +1230,7 @@ int DLLEXPORT EN_setoption(EN_Project p, int option, double value)
1283
1230
  // All other option values must be non-negative
1284
1231
  if (value < 0.0) return 213;
1285
1232
 
1286
- // Process the specified option
1233
+ // Process the speficied option
1287
1234
  switch (option)
1288
1235
  {
1289
1236
  case EN_TRIALS:
@@ -1355,12 +1302,7 @@ int DLLEXPORT EN_setoption(EN_Project p, int option, double value)
1355
1302
 
1356
1303
  case EN_SP_GRAVITY:
1357
1304
  if (value <= 0.0) return 213;
1358
- if (p->parser.Pressflag == PSI ||
1359
- p->parser.Pressflag == KPA ||
1360
- p->parser.Pressflag == BAR)
1361
- {
1362
- Ucf[PRESSURE] *= (value / hyd->SpGrav);
1363
- }
1305
+ Ucf[PRESSURE] *= (value / hyd->SpGrav);
1364
1306
  hyd->SpGrav = value;
1365
1307
  break;
1366
1308
 
@@ -1402,42 +1344,6 @@ int DLLEXPORT EN_setoption(EN_Project p, int option, double value)
1402
1344
  qual->Climit = value / p->Ucf[QUALITY];
1403
1345
  break;
1404
1346
 
1405
- case EN_DEMANDPATTERN:
1406
- pat = ROUND(value);
1407
- if (pat < 0 || pat > net->Npats) return 205;
1408
- hyd->DefPat = pat;
1409
- break;
1410
-
1411
- case EN_EMITBACKFLOW:
1412
- if (value == 0.0 || value == 1.0) hyd->EmitBackFlag = (int)value;
1413
- else return 213;
1414
- break;
1415
-
1416
- case EN_PRESS_UNITS:
1417
- unit = ROUND(value);
1418
- if (unit < 0 || unit > FEET) return 205;
1419
- p->parser.Pressflag = unit;
1420
-
1421
- dfactor = Ucf[DEMAND];
1422
- pfactor = Ucf[PRESSURE];
1423
- hfactor = Ucf[HEAD];
1424
- qfactor = Ucf[FLOW];
1425
- initunits(p);
1426
-
1427
- // Update units in rules
1428
- dcf = Ucf[DEMAND] / dfactor;
1429
- pcf = Ucf[PRESSURE] / pfactor;
1430
- hcf = Ucf[HEAD] / hfactor;
1431
- qcf = Ucf[FLOW] / qfactor;
1432
- updateruleunits(p, dcf, pcf, hcf, qcf);
1433
- break;
1434
-
1435
- case EN_STATUS_REPORT:
1436
- i = ROUND(value);
1437
- if (i < EN_NO_REPORT || i > EN_FULL_REPORT) return 213;
1438
- p->report.Statflag = i;
1439
- break;
1440
-
1441
1347
  default:
1442
1348
  return 251;
1443
1349
  }
@@ -1470,9 +1376,8 @@ int DLLEXPORT EN_setflowunits(EN_Project p, int units)
1470
1376
  {
1471
1377
  Network *net = &p->network;
1472
1378
 
1473
- int i, j, oldUnitFlag;
1474
- double qfactor, vfactor, hfactor, efactor, pfactor, dfactor, xfactor, yfactor;
1475
- double dcf, pcf, hcf, qcf;
1379
+ int i, j;
1380
+ double qfactor, vfactor, hfactor, efactor, xfactor, yfactor;
1476
1381
  double *Ucf = p->Ucf;
1477
1382
 
1478
1383
  if (!p->Openflag) return 102;
@@ -1482,10 +1387,7 @@ int DLLEXPORT EN_setflowunits(EN_Project p, int units)
1482
1387
  vfactor = Ucf[VOLUME];
1483
1388
  hfactor = Ucf[HEAD];
1484
1389
  efactor = Ucf[ELEV];
1485
- pfactor = Ucf[PRESSURE];
1486
- dfactor = Ucf[DEMAND];
1487
1390
 
1488
- oldUnitFlag = p->parser.Unitsflag;
1489
1391
  p->parser.Flowflag = units;
1490
1392
  switch (units)
1491
1393
  {
@@ -1494,7 +1396,6 @@ int DLLEXPORT EN_setflowunits(EN_Project p, int units)
1494
1396
  case MLD:
1495
1397
  case CMH:
1496
1398
  case CMD:
1497
- case CMS:
1498
1399
  p->parser.Unitsflag = SI;
1499
1400
  break;
1500
1401
  default:
@@ -1503,20 +1404,10 @@ int DLLEXPORT EN_setflowunits(EN_Project p, int units)
1503
1404
  }
1504
1405
 
1505
1406
  // Revise pressure units depending on flow units
1506
- if (oldUnitFlag != p->parser.Unitsflag)
1507
- {
1508
- if (p->parser.Unitsflag == US) p->parser.Pressflag = PSI;
1509
- else p->parser.Pressflag = METERS;
1510
- }
1407
+ if (p->parser.Unitsflag != SI) p->parser.Pressflag = PSI;
1408
+ else if (p->parser.Pressflag == PSI) p->parser.Pressflag = METERS;
1511
1409
  initunits(p);
1512
1410
 
1513
- // Update pressure units in rules
1514
- dcf = Ucf[DEMAND] / dfactor;
1515
- pcf = Ucf[PRESSURE] / pfactor;
1516
- hcf = Ucf[HEAD] / hfactor;
1517
- qcf = Ucf[FLOW] / qfactor;
1518
- updateruleunits(p, dcf, pcf, hcf, qcf);
1519
-
1520
1411
  //update curves
1521
1412
  for (i = 1; i <= net->Ncurves; i++)
1522
1413
  {
@@ -1700,65 +1591,12 @@ int DLLEXPORT EN_settimeparam(EN_Project p, int param, long value)
1700
1591
  time->Qtime = value;
1701
1592
  break;
1702
1593
 
1703
- case EN_STARTTIME:
1704
- if (value > SECperDAY) return 213;
1705
- time->Tstart = value;
1706
- break;
1707
-
1708
1594
  default:
1709
1595
  return 251;
1710
1596
  }
1711
1597
  return 0;
1712
1598
  }
1713
1599
 
1714
-
1715
- /// get the time to next event, and give a reason for the time step truncation
1716
- int DLLEXPORT EN_timetonextevent(EN_Project p, int *eventType,
1717
- long *duration, int *elementIndex)
1718
- /*----------------------------------------------------------------
1719
- ** Input: none
1720
- ** Output: eventType = event causing a new time step
1721
- ** to occur (see EN_TimestepEvent)
1722
- ** duration = seconds until next time step occurs
1723
- ** elementIndex = index of tank node or simple control
1724
- ** that triggers a new time step
1725
- ** Returns: error code
1726
- ** Purpose: Get information about when the next hydraulic time step occurs
1727
- **----------------------------------------------------------------
1728
- */
1729
- {
1730
- Times *time = &p->times;
1731
- long hydStep, tankStep, controlStep;
1732
- int iTank, iControl;
1733
-
1734
- hydStep = time->Hstep;
1735
- tankStep = hydStep;
1736
- controlStep = hydStep;
1737
-
1738
- iTank = tanktimestep(p, &tankStep);
1739
- iControl = controltimestep(p, &controlStep);
1740
-
1741
- // return the lesser of the three step lengths
1742
- if (controlStep < tankStep) {
1743
- *eventType = (int)EN_STEP_CONTROLEVENT;
1744
- *duration = controlStep;
1745
- *elementIndex = iControl;
1746
- }
1747
- else if (tankStep < hydStep) {
1748
- *eventType = (int)EN_STEP_TANKEVENT;
1749
- *duration = tankStep;
1750
- *elementIndex = iTank;
1751
- }
1752
- else {
1753
- *eventType = (int)EN_STEP_HYD;
1754
- *duration = hydStep;
1755
- *elementIndex = 0;
1756
- }
1757
-
1758
- return 0;
1759
- }
1760
-
1761
-
1762
1600
  int DLLEXPORT EN_getqualinfo(EN_Project p, int *qualType, char *chemName,
1763
1601
  char *chemUnits, int *traceNode)
1764
1602
  /*----------------------------------------------------------------
@@ -1814,8 +1652,8 @@ int DLLEXPORT EN_getqualtype(EN_Project p, int *qualType, int *traceNode)
1814
1652
  return 0;
1815
1653
  }
1816
1654
 
1817
- int DLLEXPORT EN_setqualtype(EN_Project p, int qualType, const char *chemName,
1818
- const char *chemUnits, const char *traceNode)
1655
+ int DLLEXPORT EN_setqualtype(EN_Project p, int qualType, char *chemName,
1656
+ char *chemUnits, char *traceNode)
1819
1657
  /*----------------------------------------------------------------
1820
1658
  ** Input: qualType = type of quality analysis to run (see EN_QualityType)
1821
1659
  ** chemname = name of chemical constituent
@@ -1832,7 +1670,7 @@ int DLLEXPORT EN_setqualtype(EN_Project p, int qualType, const char *chemName,
1832
1670
  Quality *qual = &p->quality;
1833
1671
 
1834
1672
  double *Ucf = p->Ucf;
1835
- int i, oldQualFlag, traceNodeIndex = 0;
1673
+ int i, oldQualFlag, traceNodeIndex;
1836
1674
  double ccf = 1.0;
1837
1675
 
1838
1676
  if (!p->Openflag) return 102;
@@ -1844,7 +1682,6 @@ int DLLEXPORT EN_setqualtype(EN_Project p, int qualType, const char *chemName,
1844
1682
  if (traceNodeIndex == 0) return 212;
1845
1683
  }
1846
1684
 
1847
- qual->TraceNode = traceNodeIndex;
1848
1685
  oldQualFlag = qual->Qualflag;
1849
1686
  qual->Qualflag = qualType;
1850
1687
  qual->Ctol *= Ucf[QUALITY];
@@ -1859,6 +1696,8 @@ int DLLEXPORT EN_setqualtype(EN_Project p, int qualType, const char *chemName,
1859
1696
  }
1860
1697
  if (qual->Qualflag == TRACE) // Source trace analysis
1861
1698
  {
1699
+ qual->TraceNode = findnode(net, traceNode);
1700
+ if (qual->TraceNode == 0) return 212;
1862
1701
  strncpy(qual->ChemName, w_TRACE, MAXID);
1863
1702
  strncpy(qual->ChemUnits, u_PERCENT, MAXID);
1864
1703
  strcpy(rpt->Field[QUALITY].Units, u_PERCENT);
@@ -1893,7 +1732,7 @@ int DLLEXPORT EN_setqualtype(EN_Project p, int qualType, const char *chemName,
1893
1732
 
1894
1733
  ********************************************************************/
1895
1734
 
1896
- int DLLEXPORT EN_addnode(EN_Project p, const char *id, int nodeType, int *index)
1735
+ int DLLEXPORT EN_addnode(EN_Project p, char *id, int nodeType, int *index)
1897
1736
  /*----------------------------------------------------------------
1898
1737
  ** Input: id = node ID name
1899
1738
  ** nodeType = type of node (see EN_NodeType)
@@ -1922,21 +1761,17 @@ int DLLEXPORT EN_addnode(EN_Project p, const char *id, int nodeType, int *index)
1922
1761
 
1923
1762
  // Check if a node with same id already exists
1924
1763
  if (EN_getnodeindex(p, id, &i) == 0) return 215;
1925
-
1764
+
1926
1765
  // Check for valid node type
1927
- if (nodeType < EN_JUNCTION || nodeType > EN_TANK) return 251;
1766
+ if (nodeType < EN_JUNCTION || nodeType > EN_TANK) return 251;
1928
1767
 
1929
- // Grow node-related arrays to accommodate the new node
1768
+ // Grow node-related arrays to accomodate the new node
1930
1769
  size = (net->Nnodes + 2) * sizeof(Snode);
1931
1770
  net->Node = (Snode *)realloc(net->Node, size);
1932
1771
  size = (net->Nnodes + 2) * sizeof(double);
1933
1772
  hyd->NodeDemand = (double *)realloc(hyd->NodeDemand, size);
1934
1773
  qual->NodeQual = (double *)realloc(qual->NodeQual, size);
1935
1774
  hyd->NodeHead = (double *)realloc(hyd->NodeHead, size);
1936
- hyd->FullDemand = (double *)realloc(hyd->FullDemand, size);
1937
- hyd->EmitterFlow = (double *)realloc(hyd->EmitterFlow, size);
1938
- hyd->LeakageFlow = (double *)realloc(hyd->LeakageFlow, size);
1939
- hyd->DemandFlow = (double *)realloc(hyd->DemandFlow, size);
1940
1775
 
1941
1776
  // Actions taken when a new Junction is added
1942
1777
  if (nodeType == EN_JUNCTION)
@@ -1947,7 +1782,7 @@ int DLLEXPORT EN_addnode(EN_Project p, const char *id, int nodeType, int *index)
1947
1782
  hashtable_update(net->NodeHashTable, net->Node[i].ID, i + 1);
1948
1783
  net->Node[i + 1] = net->Node[i];
1949
1784
  }
1950
-
1785
+
1951
1786
  // set index of new Junction node
1952
1787
  net->Njuncs++;
1953
1788
  nIdx = net->Njuncs;
@@ -1973,7 +1808,7 @@ int DLLEXPORT EN_addnode(EN_Project p, const char *id, int nodeType, int *index)
1973
1808
  if (control->Node > net->Njuncs - 1) control->Node += 1;
1974
1809
  }
1975
1810
  // adjust indices of tanks/reservoirs in Rule premises (see RULES.C)
1976
- adjusttankrules(p, 1);
1811
+ adjusttankrules(p);
1977
1812
  }
1978
1813
 
1979
1814
  // Actions taken when a new Tank/Reservoir is added
@@ -2005,7 +1840,7 @@ int DLLEXPORT EN_addnode(EN_Project p, const char *id, int nodeType, int *index)
2005
1840
  tank->Pat = 0;
2006
1841
  tank->Vcurve = 0;
2007
1842
  tank->MixModel = 0;
2008
- tank->V1frac = 1;
1843
+ tank->V1max = 10000;
2009
1844
  tank->CanOverflow = FALSE;
2010
1845
  }
2011
1846
  net->Nnodes++;
@@ -2023,7 +1858,6 @@ int DLLEXPORT EN_addnode(EN_Project p, const char *id, int nodeType, int *index)
2023
1858
  node->X = MISSING;
2024
1859
  node->Y = MISSING;
2025
1860
  node->Comment = NULL;
2026
- node->Tag = NULL;
2027
1861
 
2028
1862
  // Insert new node into hash table
2029
1863
  hashtable_insert(net->NodeHashTable, node->ID, nIdx);
@@ -2083,7 +1917,6 @@ int DLLEXPORT EN_deletenode(EN_Project p, int index, int actionCode)
2083
1917
  freedemands(node);
2084
1918
  free(node->S);
2085
1919
  free(node->Comment);
2086
- free(node->Tag);
2087
1920
 
2088
1921
  // Shift position of higher entries in Node & Coord arrays down one
2089
1922
  for (i = index; i <= net->Nnodes - 1; i++)
@@ -2092,7 +1925,6 @@ int DLLEXPORT EN_deletenode(EN_Project p, int index, int actionCode)
2092
1925
  // ... update node's entry in the hash table
2093
1926
  hashtable_update(net->NodeHashTable, net->Node[i].ID, i);
2094
1927
  }
2095
- if (index < p->quality.TraceNode) (p->quality.TraceNode)--;
2096
1928
 
2097
1929
  // If deleted node is a tank, remove it from the Tank array
2098
1930
  if (nodeType != EN_JUNCTION)
@@ -2147,7 +1979,7 @@ int DLLEXPORT EN_deletenode(EN_Project p, int index, int actionCode)
2147
1979
  return 0;
2148
1980
  }
2149
1981
 
2150
- int DLLEXPORT EN_getnodeindex(EN_Project p, const char *id, int *index)
1982
+ int DLLEXPORT EN_getnodeindex(EN_Project p, char *id, int *index)
2151
1983
  /*----------------------------------------------------------------
2152
1984
  ** Input: id = node ID name
2153
1985
  ** Output: index = node index
@@ -2179,7 +2011,7 @@ int DLLEXPORT EN_getnodeid(EN_Project p, int index, char *id)
2179
2011
  return 0;
2180
2012
  }
2181
2013
 
2182
- int DLLEXPORT EN_setnodeid(EN_Project p, int index, const char *newid)
2014
+ int DLLEXPORT EN_setnodeid(EN_Project p, int index, char *newid)
2183
2015
  /*----------------------------------------------------------------
2184
2016
  ** Input: index = node index
2185
2017
  ** newid = new node ID name
@@ -2242,10 +2074,8 @@ int DLLEXPORT EN_getnodevalue(EN_Project p, int index, int property, double *val
2242
2074
  Network *net = &p->network;
2243
2075
  Hydraul *hyd = &p->hydraul;
2244
2076
  Quality *qual = &p->quality;
2245
- Parser *parser = &p->parser;
2246
2077
 
2247
2078
  double v = 0.0;
2248
- double ecfTmp; // Unit conversion factor for emitter pressure
2249
2079
  Psource source;
2250
2080
 
2251
2081
  Snode *Node = net->Node;
@@ -2290,8 +2120,7 @@ int DLLEXPORT EN_getnodevalue(EN_Project p, int index, int property, double *val
2290
2120
  v = 0.0;
2291
2121
  if (Node[index].Ke > 0.0)
2292
2122
  {
2293
- ecfTmp = (parser->Unitsflag == US) ? (PSIperFT * hyd->SpGrav) : MperFT;
2294
- v = Ucf[FLOW] / pow((ecfTmp * Node[index].Ke), (1.0 / hyd->Qexp));
2123
+ v = Ucf[FLOW] / pow((Ucf[PRESSURE] * Node[index].Ke), (1.0 / hyd->Qexp));
2295
2124
  }
2296
2125
  break;
2297
2126
 
@@ -2328,12 +2157,10 @@ int DLLEXPORT EN_getnodevalue(EN_Project p, int index, int property, double *val
2328
2157
 
2329
2158
  case EN_MIXZONEVOL:
2330
2159
  v = 0.0;
2331
- if (index > nJuncs)
2332
- v = Tank[index - nJuncs].V1frac * Tank[index - nJuncs].Vmax *
2333
- Ucf[VOLUME];
2160
+ if (index > nJuncs) v = Tank[index - nJuncs].V1max * Ucf[VOLUME];
2334
2161
  break;
2335
2162
 
2336
- case EN_DEMAND: // Consumer Demand + Emitter Flow + Leakage Flow
2163
+ case EN_DEMAND:
2337
2164
  v = hyd->NodeDemand[index] * Ucf[FLOW];
2338
2165
  break;
2339
2166
 
@@ -2390,9 +2217,9 @@ int DLLEXPORT EN_getnodevalue(EN_Project p, int index, int property, double *val
2390
2217
 
2391
2218
  case EN_MIXFRACTION:
2392
2219
  v = 1.0;
2393
- if (index > nJuncs)
2220
+ if (index > nJuncs && Tank[index - nJuncs].Vmax > 0.0)
2394
2221
  {
2395
- v = Tank[index - nJuncs].V1frac;
2222
+ v = Tank[index - nJuncs].V1max / Tank[index - nJuncs].Vmax;
2396
2223
  }
2397
2224
  break;
2398
2225
 
@@ -2410,34 +2237,14 @@ int DLLEXPORT EN_getnodevalue(EN_Project p, int index, int property, double *val
2410
2237
  if (Node[index].Type != TANK) return 0;
2411
2238
  v = Tank[index - nJuncs].CanOverflow;
2412
2239
  break;
2413
-
2240
+
2414
2241
  case EN_DEMANDDEFICIT:
2415
2242
  if (index > nJuncs) return 0;
2416
- // FullDemand contains node's required consumer demand
2417
- // while DemandFlow contains delivered consumer demand
2418
- if (hyd->FullDemand[index] <= 0.0) return 0;
2419
- v = (hyd->FullDemand[index] - hyd->DemandFlow[index]) * Ucf[FLOW];
2420
- if (v < 0.0) v = 0.0;
2421
- break;
2422
-
2423
- case EN_NODE_INCONTROL:
2424
- v = (double)incontrols(p, NODE, index);
2425
- break;
2426
-
2427
- case EN_EMITTERFLOW:
2428
- v = hyd->EmitterFlow[index] * Ucf[FLOW];
2429
- break;
2430
-
2431
- case EN_LEAKAGEFLOW:
2432
- v = hyd->LeakageFlow[index] * Ucf[FLOW];
2433
- break;
2434
-
2435
- case EN_DEMANDFLOW: // Consumer demand delivered
2436
- v = hyd->DemandFlow[index] * Ucf[FLOW];
2437
- break;
2438
-
2439
- case EN_FULLDEMAND: // Consumer demand requested
2440
- v = hyd->FullDemand[index] * Ucf[FLOW];
2243
+ // After an analysis, DemandFlow contains node's required demand
2244
+ // while NodeDemand contains delivered demand + emitter flow
2245
+ if (hyd->DemandFlow[index] < 0.0) return 0;
2246
+ v = (hyd->DemandFlow[index] -
2247
+ (hyd->NodeDemand[index] - hyd->EmitterFlow[index])) * Ucf[FLOW];
2441
2248
  break;
2442
2249
 
2443
2250
  default:
@@ -2447,25 +2254,6 @@ int DLLEXPORT EN_getnodevalue(EN_Project p, int index, int property, double *val
2447
2254
  return 0;
2448
2255
  }
2449
2256
 
2450
- int DLLEXPORT EN_getnodevalues(EN_Project p, int property, double *values)
2451
- /*----------------------------------------------------------------
2452
- ** Input: property = node property code (see EN_NodeProperty)
2453
- ** Output: values = array of node property values
2454
- ** Returns: error code
2455
- ** Purpose: retrieves an array of node property values
2456
- **----------------------------------------------------------------
2457
- */
2458
- {
2459
- int errcode = 0, i = 0;
2460
-
2461
- for (i = 1; i <= p->network.Nnodes; i++)
2462
- {
2463
- errcode = EN_getnodevalue(p, i, property, &values[i - 1]);
2464
- if (errcode != 0) { return errcode; }
2465
- }
2466
- return 0;
2467
- }
2468
-
2469
2257
  int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int property, double value)
2470
2258
  /*----------------------------------------------------------------
2471
2259
  ** Input: index = node index
@@ -2480,7 +2268,6 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int property, double valu
2480
2268
  Network *net = &p->network;
2481
2269
  Hydraul *hyd = &p->hydraul;
2482
2270
  Quality *qual = &p->quality;
2483
- Parser *parser = &p->parser;
2484
2271
 
2485
2272
  Snode *Node = net->Node;
2486
2273
  Stank *Tank = net->Tank;
@@ -2494,7 +2281,8 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int property, double valu
2494
2281
 
2495
2282
  int i, j, n;
2496
2283
  Psource source;
2497
- double hTmp, ecfTmp;
2284
+ double hTmp;
2285
+ double vTmp;
2498
2286
 
2499
2287
  if (!p->Openflag) return 102;
2500
2288
  if (index <= 0 || index > nNodes) return 203;
@@ -2536,13 +2324,8 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int property, double valu
2536
2324
  case EN_EMITTER:
2537
2325
  if (index > nJuncs) return 0;
2538
2326
  if (value < 0.0) return 209;
2539
- if (value > 0.0)
2540
- {
2541
- ecfTmp = (parser->Unitsflag == US) ? (PSIperFT * hyd->SpGrav) : MperFT;
2542
- value = pow((Ucf[FLOW] / value), hyd->Qexp) / ecfTmp;
2543
- }
2327
+ if (value > 0.0) value = pow((Ucf[FLOW] / value), hyd->Qexp) / Ucf[PRESSURE];
2544
2328
  Node[index].Ke = value;
2545
- if (hyd->EmitterFlow[index] == 0.0) hyd->EmitterFlow[index] = 1.0;
2546
2329
  break;
2547
2330
 
2548
2331
  case EN_INITQUAL:
@@ -2581,7 +2364,7 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int property, double valu
2581
2364
  break;
2582
2365
 
2583
2366
  case EN_TANKLEVEL:
2584
- if (index <= nJuncs) return 263;
2367
+ if (index <= nJuncs) return 0;
2585
2368
  j = index - nJuncs;
2586
2369
  if (Tank[j].A == 0.0) /* Tank is a reservoir */
2587
2370
  {
@@ -2605,9 +2388,9 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int property, double valu
2605
2388
 
2606
2389
  case EN_TANKDIAM:
2607
2390
  if (value <= 0.0) return 209; // invalid diameter
2608
- if (index <= nJuncs) return 263; // node is not a tank
2391
+ if (index <= nJuncs) return 0; // node is not a tank
2609
2392
  j = index - nJuncs; // tank index
2610
- if (Tank[j].A == 0.0) return 263; // tank is a reservoir
2393
+ if (Tank[j].A == 0.0) return 0; // tank is a reservoir
2611
2394
  value /= Ucf[ELEV]; // diameter in feet
2612
2395
  Tank[j].A = PI * SQR(value) / 4.0; // new tank area
2613
2396
  if (Tank[j].Vcurve > 0) // tank has a volume curve
@@ -2616,7 +2399,7 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int property, double valu
2616
2399
 
2617
2400
  // Since the volume curve no longer applies we assume that the tank's
2618
2401
  // shape below Hmin is cylindrical and Vmin equals area times Hmin
2619
- Tank[j].Vmin = Tank[j].A * (Tank[j].Hmin - Node[index].El);
2402
+ Tank[j].Vmin = Tank[j].A * Tank[j].Hmin;
2620
2403
  }
2621
2404
  // Since tank's area has changed its volumes must be updated
2622
2405
  // NOTE: For a non-volume curve tank we can't change the Vmin
@@ -2624,14 +2407,16 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int property, double valu
2624
2407
  // shape below Hmin. Vmin can always be changed by setting
2625
2408
  // EN_MINVOLUME in a subsequent function call.
2626
2409
  Tank[j].V0 = tankvolume(p, j, Tank[j].H0); // new init. volume
2410
+ vTmp = Tank[j].Vmax; // old max. volume
2627
2411
  Tank[j].Vmax = tankvolume(p, j, Tank[j].Hmax); // new max. volume
2412
+ Tank[j].V1max *= Tank[j].Vmax / vTmp; // new mix zone volume
2628
2413
  break;
2629
2414
 
2630
2415
  case EN_MINVOLUME:
2631
2416
  if (value < 0.0) return 209; // invalid volume
2632
- if (index <= nJuncs) return 263; // node is not a tank
2417
+ if (index <= nJuncs) return 0; // node is not a tank
2633
2418
  j = index - nJuncs; // tank index
2634
- if (Tank[j].A == 0.0) return 263; // tank is a reservoir
2419
+ if (Tank[j].A == 0.0) return 0; // tank is a reservoir
2635
2420
  i = Tank[j].Vcurve; // volume curve index
2636
2421
  if (i > 0) // tank has a volume curve
2637
2422
  {
@@ -2649,12 +2434,14 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int property, double valu
2649
2434
  // If the volume supplied by the function is 0 then the tank shape
2650
2435
  // below Hmin is assumed to be cylindrical and a new Vmin value is
2651
2436
  // computed. Otherwise Vmin is set to the supplied value.
2652
- if (value == 0.0) Tank[j].Vmin = Tank[j].A * (Tank[j].Hmin - Node[index].El);
2437
+ if (value == 0.0) Tank[j].Vmin = Tank[j].A * Tank[j].Hmin;
2653
2438
  else Tank[j].Vmin = value / Ucf[VOLUME];
2654
2439
 
2655
2440
  // Since Vmin changes the other volumes need updating
2656
2441
  Tank[j].V0 = tankvolume(p, j, Tank[j].H0); // new init. volume
2442
+ vTmp = Tank[j].Vmax; // old max. volume
2657
2443
  Tank[j].Vmax = tankvolume(p, j, Tank[j].Hmax); // new max. volume
2444
+ Tank[j].V1max *= Tank[j].Vmax / vTmp; // new mix zone volume
2658
2445
  }
2659
2446
  break;
2660
2447
 
@@ -2664,9 +2451,9 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int property, double valu
2664
2451
  i = ROUND(value); // curve index
2665
2452
  if (i <= 0 ||
2666
2453
  i > net->Ncurves) return 205; // invalid curve index
2667
- if (index <= nJuncs) return 263; // node not a tank
2454
+ if (index <= nJuncs) return 0; // node not a tank
2668
2455
  j = index - nJuncs; // tank index
2669
- if (Tank[j].A == 0.0) return 263; // tank is a reservoir
2456
+ if (Tank[j].A == 0.0) return 0; // tank is a reservoir
2670
2457
  curve = &net->Curve[i]; // curve object
2671
2458
 
2672
2459
  // Check that tank's min/max levels lie within curve
@@ -2679,16 +2466,18 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int property, double valu
2679
2466
  Tank[j].Vcurve = i; // assign curve to tank
2680
2467
  Tank[j].Vmin = tankvolume(p, j, Tank[j].Hmin); // new min. volume
2681
2468
  Tank[j].V0 = tankvolume(p, j, Tank[j].H0); // new init. volume
2469
+ vTmp = Tank[j].Vmax; // old max. volume
2682
2470
  Tank[j].Vmax = tankvolume(p, j, Tank[j].Hmax); // new max. volume
2683
- Tank[j].A = (curve->Y[n] - curve->Y[0]) / // nominal area
2471
+ Tank[j].V1max *= Tank[j].Vmax / vTmp; // new mix zone volume
2472
+ Tank[j].A = (curve->Y[n] - curve->Y[0]) / // nominal area
2684
2473
  (curve->X[n] - curve->X[0]);
2685
2474
  break;
2686
2475
 
2687
2476
  case EN_MINLEVEL:
2688
2477
  if (value < 0.0) return 209; // invalid water level
2689
- if (index <= nJuncs) return 263; // node not a tank
2478
+ if (index <= nJuncs) return 0; // node not a tank
2690
2479
  j = index - nJuncs; // tank index
2691
- if (Tank[j].A == 0.0) return 263; // tank is a reservoir
2480
+ if (Tank[j].A == 0.0) return 0; // tank is a reservoir
2692
2481
  hTmp = value / Ucf[ELEV] + Node[index].El; // convert level to head
2693
2482
  if (hTmp >= Tank[j].Hmax ||
2694
2483
  hTmp > Tank[j].H0) return 225; // invalid water levels
@@ -2707,9 +2496,9 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int property, double valu
2707
2496
 
2708
2497
  case EN_MAXLEVEL:
2709
2498
  if (value <= 0.0) return 209; // invalid water level
2710
- if (index <= nJuncs) return 263; // node not a tank
2499
+ if (index <= nJuncs) return 0; // node not a tank
2711
2500
  j = index - nJuncs; // tank index
2712
- if (Tank[j].A == 0.0) return 263; // tank is a reservoir
2501
+ if (Tank[j].A == 0.0) return 0; // tank is a reservoir
2713
2502
  hTmp = value / Ucf[ELEV] + Node[index].El; // convert level to head
2714
2503
  if (hTmp < Tank[j].Hmin ||
2715
2504
  hTmp < Tank[j].H0) return 225; // invalid water levels
@@ -2721,12 +2510,14 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int property, double valu
2721
2510
  if (value > curve->X[n]) return 225; // new level is off curve
2722
2511
  }
2723
2512
  Tank[j].Hmax = hTmp; // new max. head
2513
+ vTmp = Tank[j].Vmax; // old max. volume
2724
2514
  Tank[j].Vmax = tankvolume(p, j, hTmp); // new max. volume
2515
+ Tank[j].V1max *= Tank[j].Vmax / vTmp; // new mix zone volume
2725
2516
  break;
2726
2517
 
2727
2518
  case EN_MIXMODEL:
2728
2519
  j = ROUND(value);
2729
- if (index <= nJuncs) return 263;
2520
+ if (index <= nJuncs) return 0;
2730
2521
  if (j < MIX1 || j > LIFO) return 251;
2731
2522
  if (Tank[index - nJuncs].A > 0.0)
2732
2523
  {
@@ -2735,17 +2526,17 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int property, double valu
2735
2526
  break;
2736
2527
 
2737
2528
  case EN_MIXFRACTION:
2738
- if (index <= nJuncs) return 263;
2529
+ if (index <= nJuncs) return 0;
2739
2530
  if (value < 0.0 || value > 1.0) return 209;
2740
2531
  j = index - nJuncs;
2741
2532
  if (Tank[j].A > 0.0)
2742
2533
  {
2743
- Tank[j].V1frac = value;
2534
+ Tank[j].V1max = value * Tank[j].Vmax;
2744
2535
  }
2745
2536
  break;
2746
2537
 
2747
2538
  case EN_TANK_KBULK:
2748
- if (index <= nJuncs) return 263;
2539
+ if (index <= nJuncs) return 0;
2749
2540
  j = index - nJuncs;
2750
2541
  if (Tank[j].A > 0.0)
2751
2542
  {
@@ -2755,7 +2546,7 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int property, double valu
2755
2546
  break;
2756
2547
 
2757
2548
  case EN_CANOVERFLOW:
2758
- if (Node[index].Type != TANK) return 263;
2549
+ if (Node[index].Type != TANK) return 0;
2759
2550
  Tank[index - nJuncs].CanOverflow = (value != 0.0);
2760
2551
  break;
2761
2552
 
@@ -2766,7 +2557,7 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int property, double valu
2766
2557
  }
2767
2558
 
2768
2559
  int DLLEXPORT EN_setjuncdata(EN_Project p, int index, double elev,
2769
- double dmnd, const char *dmndpat)
2560
+ double dmnd, char *dmndpat)
2770
2561
  /*----------------------------------------------------------------
2771
2562
  ** Input: index = junction node index
2772
2563
  ** elev = junction elevation
@@ -2811,7 +2602,7 @@ int DLLEXPORT EN_setjuncdata(EN_Project p, int index, double elev,
2811
2602
  int DLLEXPORT EN_settankdata(EN_Project p, int index, double elev,
2812
2603
  double initlvl, double minlvl,
2813
2604
  double maxlvl, double diam,
2814
- double minvol, const char *volcurve)
2605
+ double minvol, char *volcurve)
2815
2606
  /*----------------------------------------------------------------
2816
2607
  ** Input: index = tank node index
2817
2608
  ** elev = tank bottom elevation
@@ -2830,16 +2621,16 @@ int DLLEXPORT EN_settankdata(EN_Project p, int index, double elev,
2830
2621
  Network *net = &p->network;
2831
2622
 
2832
2623
  int i, j, n, curveIndex = 0;
2624
+ double area, elevation = elev;
2833
2625
  double *Ucf = p->Ucf;
2834
- double area;
2835
2626
  Stank *Tank = net->Tank;
2836
2627
  Scurve *curve;
2837
2628
 
2838
2629
  // Check that tank exists
2839
2630
  if (!p->Openflag) return 102;
2840
- if (index <= net->Njuncs || index > net->Nnodes) return 263;
2631
+ if (index <= net->Njuncs || index > net->Nnodes) return 203;
2841
2632
  j = index - net->Njuncs;
2842
- if (Tank[j].A == 0) return 263; // Tank is a Reservoir
2633
+ if (Tank[j].A == 0) return 0; // Tank is a Reservoir
2843
2634
 
2844
2635
  // Check for valid parameter values
2845
2636
  if (initlvl < 0.0 || minlvl < 0.0 || maxlvl < 0.0) return 209;
@@ -2868,16 +2659,16 @@ int DLLEXPORT EN_settankdata(EN_Project p, int index, double elev,
2868
2659
  else area = PI * diam * diam / 4.0;
2869
2660
 
2870
2661
  // Assign parameters to tank object
2871
- net->Node[Tank[j].Node].El = elev / Ucf[ELEV];
2662
+ net->Node[Tank[j].Node].El = elevation;
2872
2663
  Tank[j].A = area / Ucf[ELEV] / Ucf[ELEV];
2873
- Tank[j].H0 = (elev + initlvl) / Ucf[ELEV];
2874
- Tank[j].Hmin = (elev + minlvl) / Ucf[ELEV];
2875
- Tank[j].Hmax = (elev + maxlvl) / Ucf[ELEV];
2664
+ Tank[j].H0 = elevation + initlvl / Ucf[ELEV];
2665
+ Tank[j].Hmin = elevation + minlvl / Ucf[ELEV];
2666
+ Tank[j].Hmax = elevation + maxlvl / Ucf[ELEV];
2876
2667
  Tank[j].Vcurve = curveIndex;
2877
2668
  if (curveIndex == 0)
2878
2669
  {
2879
2670
  if (minvol > 0.0) Tank[j].Vmin = minvol / Ucf[VOLUME];
2880
- else Tank[j].Vmin = Tank[j].A * (Tank[j].Hmin - elev / Ucf[ELEV]);
2671
+ else Tank[j].Vmin = Tank[j].A * Tank[j].Hmin;
2881
2672
  }
2882
2673
  else Tank[j].Vmin = tankvolume(p, j, Tank[j].Hmin);
2883
2674
  Tank[j].V0 = tankvolume(p, j, Tank[j].H0);
@@ -2987,7 +2778,7 @@ int DLLEXPORT EN_setdemandmodel(EN_Project p, int model, double pmin,
2987
2778
  }
2988
2779
 
2989
2780
  int DLLEXPORT EN_adddemand(EN_Project p, int nodeIndex, double baseDemand,
2990
- const char *demandPattern, const char *demandName)
2781
+ char *demandPattern, char *demandName)
2991
2782
  /*----------------------------------------------------------------
2992
2783
  ** Input: nodeIndex = node index
2993
2784
  ** baseDemand = baseline demand value
@@ -3074,7 +2865,7 @@ int DLLEXPORT EN_deletedemand(EN_Project p, int nodeIndex, int demandIndex)
3074
2865
  return 0;
3075
2866
  }
3076
2867
 
3077
- int DLLEXPORT EN_getdemandindex(EN_Project p, int nodeIndex, const char *demandName,
2868
+ int DLLEXPORT EN_getdemandindex(EN_Project p, int nodeIndex, char *demandName,
3078
2869
  int *demandIndex)
3079
2870
  /*----------------------------------------------------------------
3080
2871
  ** Input: nodeIndex = node index
@@ -3223,7 +3014,7 @@ int DLLEXPORT EN_getdemandname(EN_Project p, int nodeIndex, int demandIndex,
3223
3014
  }
3224
3015
 
3225
3016
  int DLLEXPORT EN_setdemandname(EN_Project p, int nodeIndex, int demandIndex,
3226
- const char *demandName)
3017
+ char *demandName)
3227
3018
  /*----------------------------------------------------------------
3228
3019
  ** Input: nodeIndex = node index
3229
3020
  ** demandIndex = demand category index
@@ -3313,8 +3104,8 @@ int DLLEXPORT EN_setdemandpattern(EN_Project p, int nodeIndex, int demandIndex,
3313
3104
 
3314
3105
  ********************************************************************/
3315
3106
 
3316
- int DLLEXPORT EN_addlink(EN_Project p, const char *id, int linkType,
3317
- const char *fromNode, const char *toNode, int *index)
3107
+ int DLLEXPORT EN_addlink(EN_Project p, char *id, int linkType,
3108
+ char *fromNode, char *toNode, int *index)
3318
3109
  /*----------------------------------------------------------------
3319
3110
  ** Input: id = link ID name
3320
3111
  ** type = link type (see EN_LinkType)
@@ -3346,7 +3137,7 @@ int DLLEXPORT EN_addlink(EN_Project p, const char *id, int linkType,
3346
3137
  if (EN_getlinkindex(p, id, &i) == 0) return 215;
3347
3138
 
3348
3139
  // Check for valid link type
3349
- if (linkType < CVPIPE || linkType > PCV) return 251;
3140
+ if (linkType < CVPIPE || linkType > GPV) return 251;
3350
3141
 
3351
3142
  // Lookup the link's from and to nodes
3352
3143
  n1 = hashtable_find(net->NodeHashTable, fromNode);
@@ -3360,7 +3151,7 @@ int DLLEXPORT EN_addlink(EN_Project p, const char *id, int linkType,
3360
3151
  if (errcode) return errcode;
3361
3152
  }
3362
3153
 
3363
- // Grow link-related arrays to accommodate the new link
3154
+ // Grow link-related arrays to accomodate the new link
3364
3155
  net->Nlinks++;
3365
3156
  p->parser.MaxLinks = net->Nlinks;
3366
3157
  n = net->Nlinks;
@@ -3379,7 +3170,7 @@ int DLLEXPORT EN_addlink(EN_Project p, const char *id, int linkType,
3379
3170
  if (linkType <= PIPE) net->Npipes++;
3380
3171
  else if (linkType == PUMP)
3381
3172
  {
3382
- // Grow pump array to accommodate the new link
3173
+ // Grow pump array to accomodate the new link
3383
3174
  net->Npumps++;
3384
3175
  size = (net->Npumps + 1) * sizeof(Spump);
3385
3176
  net->Pump = (Spump *)realloc(net->Pump, size);
@@ -3401,18 +3192,17 @@ int DLLEXPORT EN_addlink(EN_Project p, const char *id, int linkType,
3401
3192
  }
3402
3193
  else
3403
3194
  {
3404
- // Grow valve array to accommodate the new link
3195
+ // Grow valve array to accomodate the new link
3405
3196
  net->Nvalves++;
3406
3197
  size = (net->Nvalves + 1) * sizeof(Svalve);
3407
3198
  net->Valve = (Svalve *)realloc(net->Valve, size);
3408
3199
  net->Valve[net->Nvalves].Link = n;
3409
- net->Valve[net->Nvalves].Curve = 0;
3410
3200
  }
3411
3201
 
3412
3202
  link->Type = linkType;
3413
3203
  link->N1 = n1;
3414
3204
  link->N2 = n2;
3415
- link->InitStatus = OPEN;
3205
+ link->Status = OPEN;
3416
3206
 
3417
3207
  if (linkType == PUMP)
3418
3208
  {
@@ -3441,19 +3231,15 @@ int DLLEXPORT EN_addlink(EN_Project p, const char *id, int linkType,
3441
3231
  link->Kc = 0.0; // Valve setting.
3442
3232
  link->Km = 0.0; // Loss coeff
3443
3233
  link->Len = 0.0;
3444
- link->InitStatus = ACTIVE;
3234
+ link->Status = ACTIVE;
3445
3235
  }
3446
3236
  link->Kb = 0;
3447
3237
  link->Kw = 0;
3448
- link->LeakArea = 0;
3449
- link->LeakExpan = 0;
3450
- link->InitSetting = link->Kc;
3451
3238
  link->R = 0;
3452
3239
  link->Rc = 0;
3453
3240
  link->Rpt = 0;
3454
3241
  link->ResultIndex = 0;
3455
3242
  link->Comment = NULL;
3456
- link->Tag = NULL;
3457
3243
  link->Vertices = NULL;
3458
3244
 
3459
3245
  hashtable_insert(net->LinkHashTable, link->ID, n);
@@ -3506,7 +3292,6 @@ int DLLEXPORT EN_deletelink(EN_Project p, int index, int actionCode)
3506
3292
 
3507
3293
  // Remove link's comment and vertices
3508
3294
  free(link->Comment);
3509
- free(link->Tag);
3510
3295
  freelinkvertices(link);
3511
3296
 
3512
3297
  // Shift position of higher entries in Link array down one
@@ -3527,12 +3312,6 @@ int DLLEXPORT EN_deletelink(EN_Project p, int index, int actionCode)
3527
3312
  if (net->Valve[i].Link > index) net->Valve[i].Link -= 1;
3528
3313
  }
3529
3314
 
3530
- // Reduce the number of pipes count by one if it is a pipe.
3531
- if (linkType == PIPE)
3532
- {
3533
- net->Npipes--;
3534
- }
3535
-
3536
3315
  // Delete any pump associated with the deleted link
3537
3316
  if (linkType == PUMP)
3538
3317
  {
@@ -3575,7 +3354,7 @@ int DLLEXPORT EN_deletelink(EN_Project p, int index, int actionCode)
3575
3354
  return 0;
3576
3355
  }
3577
3356
 
3578
- int DLLEXPORT EN_getlinkindex(EN_Project p, const char *id, int *index)
3357
+ int DLLEXPORT EN_getlinkindex(EN_Project p, char *id, int *index)
3579
3358
  /*----------------------------------------------------------------
3580
3359
  ** Input: id = link ID name
3581
3360
  ** Output: index = link index
@@ -3607,7 +3386,7 @@ int DLLEXPORT EN_getlinkid(EN_Project p, int index, char *id)
3607
3386
  return 0;
3608
3387
  }
3609
3388
 
3610
- int DLLEXPORT EN_setlinkid(EN_Project p, int index, const char *newid)
3389
+ int DLLEXPORT EN_setlinkid(EN_Project p, int index, char *newid)
3611
3390
  /*----------------------------------------------------------------
3612
3391
  ** Input: index = link index
3613
3392
  ** id = link ID name
@@ -3677,7 +3456,7 @@ int DLLEXPORT EN_setlinktype(EN_Project p, int *index, int linkType, int actionC
3677
3456
  if (p->hydraul.OpenHflag || p->quality.OpenQflag) return 262;
3678
3457
 
3679
3458
  // Check for valid input parameters
3680
- if (linkType < 0 || linkType > PCV || actionCode < EN_UNCONDITIONAL ||
3459
+ if (linkType < 0 || linkType > GPV || actionCode < EN_UNCONDITIONAL ||
3681
3460
  actionCode > EN_CONDITIONAL)
3682
3461
  {
3683
3462
  return 251;
@@ -3701,7 +3480,7 @@ int DLLEXPORT EN_setlinktype(EN_Project p, int *index, int linkType, int actionC
3701
3480
  if (oldType <= PIPE && linkType <= PIPE)
3702
3481
  {
3703
3482
  net->Link[i].Type = linkType;
3704
- if (linkType == CVPIPE) net->Link[i].InitStatus = OPEN;
3483
+ if (linkType == CVPIPE) net->Link[i].Status = OPEN;
3705
3484
  return 0;
3706
3485
  }
3707
3486
 
@@ -3804,6 +3583,8 @@ int DLLEXPORT EN_getlinkvalue(EN_Project p, int index, int property, double *val
3804
3583
  Slink *Link = net->Link;
3805
3584
  Spump *Pump = net->Pump;
3806
3585
  double *Ucf = p->Ucf;
3586
+ double *LinkFlow = hyd->LinkFlow;
3587
+ double *LinkSetting = hyd->LinkSetting;
3807
3588
 
3808
3589
  // Check for valid arguments
3809
3590
  *value = 0.0;
@@ -3841,19 +3622,18 @@ int DLLEXPORT EN_getlinkvalue(EN_Project p, int index, int property, double *val
3841
3622
  break;
3842
3623
 
3843
3624
  case EN_INITSTATUS:
3844
- if (Link[index].InitStatus <= CLOSED) v = 0.0;
3625
+ if (Link[index].Status <= CLOSED) v = 0.0;
3845
3626
  else v = 1.0;
3846
- if (Link[index].Type > PUMP && Link[index].InitStatus > OPEN) v = 2.0;
3847
3627
  break;
3848
3628
 
3849
3629
  case EN_INITSETTING:
3850
- v = Link[index].InitSetting;
3630
+ if (Link[index].Type == PIPE || Link[index].Type == CVPIPE)
3631
+ {
3632
+ return EN_getlinkvalue(p, index, EN_ROUGHNESS, value);
3633
+ }
3634
+ v = Link[index].Kc;
3851
3635
  switch (Link[index].Type)
3852
3636
  {
3853
- case CVPIPE:
3854
- case PIPE:
3855
- if (hyd->Formflag == DW) v = v * (1000.0 * Ucf[ELEV]);
3856
- break;
3857
3637
  case PRV:
3858
3638
  case PSV:
3859
3639
  case PBV:
@@ -3876,7 +3656,7 @@ int DLLEXPORT EN_getlinkvalue(EN_Project p, int index, int property, double *val
3876
3656
 
3877
3657
  case EN_FLOW:
3878
3658
  if (hyd->LinkStatus[index] <= CLOSED) v = 0.0;
3879
- else v = hyd->LinkFlow[index] * Ucf[FLOW];
3659
+ else v = LinkFlow[index] * Ucf[FLOW];
3880
3660
  break;
3881
3661
 
3882
3662
  case EN_VELOCITY:
@@ -3884,7 +3664,7 @@ int DLLEXPORT EN_getlinkvalue(EN_Project p, int index, int property, double *val
3884
3664
  else if (hyd->LinkStatus[index] <= CLOSED) v = 0.0;
3885
3665
  else
3886
3666
  {
3887
- q = ABS(hyd->LinkFlow[index]);
3667
+ q = ABS(LinkFlow[index]);
3888
3668
  a = PI * SQR(Link[index].Diam) / 4.0;
3889
3669
  v = q / a * Ucf[VELOCITY];
3890
3670
  }
@@ -3903,8 +3683,6 @@ int DLLEXPORT EN_getlinkvalue(EN_Project p, int index, int property, double *val
3903
3683
  case EN_STATUS:
3904
3684
  if (hyd->LinkStatus[index] <= CLOSED) v = 0.0;
3905
3685
  else v = 1.0;
3906
- if (Link[index].Type > PUMP &&
3907
- hyd->LinkStatus[index] > OPEN) v = 2.0;
3908
3686
  break;
3909
3687
 
3910
3688
  case EN_SETTING:
@@ -3912,8 +3690,8 @@ int DLLEXPORT EN_getlinkvalue(EN_Project p, int index, int property, double *val
3912
3690
  {
3913
3691
  return EN_getlinkvalue(p, index, EN_ROUGHNESS, value);
3914
3692
  }
3915
- if (hyd->LinkSetting[index] == MISSING) v = 0.0;
3916
- else v = hyd->LinkSetting[index];
3693
+ if (LinkSetting[index] == MISSING) v = 0.0;
3694
+ else v = LinkSetting[index];
3917
3695
  switch (Link[index].Type)
3918
3696
  {
3919
3697
  case PRV:
@@ -4000,40 +3778,6 @@ int DLLEXPORT EN_getlinkvalue(EN_Project p, int index, int property, double *val
4000
3778
  v = (double)Pump[findpump(&p->network, index)].Epat;
4001
3779
  }
4002
3780
  break;
4003
-
4004
- case EN_PCV_CURVE:
4005
- if (Link[index].Type == PCV)
4006
- {
4007
- v = net->Valve[findvalve(&p->network, index)].Curve;
4008
- }
4009
- break;
4010
-
4011
- case EN_GPV_CURVE:
4012
- if (Link[index].Type == GPV)
4013
- {
4014
- v = Link[index].Kc;
4015
- }
4016
- break;
4017
-
4018
- case EN_LINK_INCONTROL:
4019
- v = (double)incontrols(p, LINK, index);
4020
- break;
4021
-
4022
- case EN_LEAK_AREA:
4023
- v = Link[index].LeakArea * Ucf[LENGTH];
4024
- break;
4025
-
4026
- case EN_LEAK_EXPAN:
4027
- v = Link[index].LeakExpan * Ucf[LENGTH];
4028
- break;
4029
-
4030
- case EN_LINK_LEAKAGE:
4031
- v = findlinkleakage(p, index) * Ucf[FLOW];
4032
- break;
4033
-
4034
- case EN_VALVE_TYPE:
4035
- if (Link[index].Type > PUMP) v = Link[index].Type;
4036
- break;
4037
3781
 
4038
3782
  default:
4039
3783
  return 251;
@@ -4042,24 +3786,6 @@ int DLLEXPORT EN_getlinkvalue(EN_Project p, int index, int property, double *val
4042
3786
  return 0;
4043
3787
  }
4044
3788
 
4045
- int DLLEXPORT EN_getlinkvalues(EN_Project p, int property, double *values)
4046
- /*----------------------------------------------------------------
4047
- ** Input: property = link property code (see EN_LinkProperty)
4048
- ** Output: values = array of link property values
4049
- ** Returns: error code
4050
- ** Purpose: retrieves property values for all links
4051
- **----------------------------------------------------------------
4052
- */
4053
- {
4054
- int errcode = 0, i = 0;
4055
- for(i = 1; i <= p->network.Nlinks; i++)
4056
- {
4057
- errcode = EN_getlinkvalue(p, i, property, &values[i-1]);
4058
- if(errcode != 0) { return errcode; }
4059
- }
4060
- return 0;
4061
- }
4062
-
4063
3789
  int DLLEXPORT EN_setlinkvalue(EN_Project p, int index, int property, double value)
4064
3790
  /*----------------------------------------------------------------
4065
3791
  ** Input: index = link index
@@ -4077,9 +3803,10 @@ int DLLEXPORT EN_setlinkvalue(EN_Project p, int index, int property, double valu
4077
3803
 
4078
3804
  Slink *Link = net->Link;
4079
3805
  double *Ucf = p->Ucf;
3806
+ double *LinkSetting = hyd->LinkSetting;
4080
3807
  char s;
4081
3808
  double r;
4082
- int pumpIndex, patIndex, curveIndex, valveType;
3809
+ int pumpIndex, patIndex, curveIndex;
4083
3810
 
4084
3811
  if (!p->Openflag) return 102;
4085
3812
  if (index <= 0 || index > net->Nlinks) return 204;
@@ -4112,15 +3839,14 @@ int DLLEXPORT EN_setlinkvalue(EN_Project p, int index, int property, double valu
4112
3839
  if (value <= 0.0) return 211;
4113
3840
  Link[index].Kc = value;
4114
3841
  if (hyd->Formflag == DW) Link[index].Kc /= (1000.0 * Ucf[ELEV]);
4115
- if (p->hydraul.OpenHflag) resistcoeff(p, index);
4116
- else Link[index].InitSetting = Link[index].Kc;
3842
+ resistcoeff(p, index);
4117
3843
  }
4118
3844
  break;
4119
3845
 
4120
3846
  case EN_MINORLOSS:
4121
3847
  if (Link[index].Type != PUMP)
4122
3848
  {
4123
- if (value < 0.0) return 211;
3849
+ if (value <= 0.0) return 211;
4124
3850
  Link[index].Km = 0.02517 * value / SQR(Link[index].Diam) /
4125
3851
  SQR(Link[index].Diam);
4126
3852
  }
@@ -4131,31 +3857,29 @@ int DLLEXPORT EN_setlinkvalue(EN_Project p, int index, int property, double valu
4131
3857
  // Cannot set status for a check valve
4132
3858
  if (Link[index].Type == CVPIPE) return 207;
4133
3859
  s = (char)ROUND(value);
4134
- if (s < 0 || s > 2) return 211;
4135
- s = s + CLOSED;
3860
+ if (s < 0 || s > 1) return 211;
4136
3861
  if (property == EN_INITSTATUS)
4137
3862
  {
4138
- Link[index].InitStatus = s;
3863
+ setlinkstatus(p, index, s, &Link[index].Status, &Link[index].Kc);
4139
3864
  }
4140
3865
  else
4141
3866
  {
4142
- setlinkstatus(p, index, s, &hyd->LinkStatus[index], &hyd->LinkSetting[index]);
3867
+ setlinkstatus(p, index, s, &hyd->LinkStatus[index], &LinkSetting[index]);
4143
3868
  }
4144
3869
  break;
4145
3870
 
4146
3871
  case EN_INITSETTING:
4147
3872
  case EN_SETTING:
3873
+ if (value < 0.0) return 211;
4148
3874
  if (Link[index].Type == PIPE || Link[index].Type == CVPIPE)
4149
3875
  {
4150
- EN_setlinkvalue(p, index, EN_ROUGHNESS, value);
4151
- if (property == EN_INITSETTING) Link[index].InitSetting = Link[index].Kc;
3876
+ return EN_setlinkvalue(p, index, EN_ROUGHNESS, value);
4152
3877
  }
4153
3878
  else
4154
3879
  {
4155
3880
  switch (Link[index].Type)
4156
3881
  {
4157
3882
  case PUMP:
4158
- if (value < 0.0) return 211;
4159
3883
  break;
4160
3884
  case PRV:
4161
3885
  case PSV:
@@ -4166,7 +3890,6 @@ int DLLEXPORT EN_setlinkvalue(EN_Project p, int index, int property, double valu
4166
3890
  value /= Ucf[FLOW];
4167
3891
  break;
4168
3892
  case TCV:
4169
- case PCV:
4170
3893
  break;
4171
3894
  case GPV:
4172
3895
  return 207; // Cannot modify setting for GPV
@@ -4175,13 +3898,12 @@ int DLLEXPORT EN_setlinkvalue(EN_Project p, int index, int property, double valu
4175
3898
  }
4176
3899
  if (property == EN_INITSETTING)
4177
3900
  {
4178
- Link[index].Kc = value;
4179
- Link[index].InitSetting = value;
3901
+ setlinksetting(p, index, value, &Link[index].Status, &Link[index].Kc);
4180
3902
  }
4181
3903
  else
4182
3904
  {
4183
3905
  setlinksetting(p, index, value, &hyd->LinkStatus[index],
4184
- &hyd->LinkSetting[index]);
3906
+ &LinkSetting[index]);
4185
3907
  }
4186
3908
  }
4187
3909
  break;
@@ -4220,6 +3942,11 @@ int DLLEXPORT EN_setlinkvalue(EN_Project p, int index, int property, double valu
4220
3942
  net->Pump[pumpIndex].Ptype = CONST_HP;
4221
3943
  net->Pump[pumpIndex].Hcurve = 0;
4222
3944
  net->Link[index].Km = value;
3945
+ updatepumpparams(p, pumpIndex);
3946
+ net->Pump[pumpIndex].R /= Ucf[POWER];
3947
+ net->Pump[pumpIndex].Q0 /= Ucf[FLOW];
3948
+ net->Pump[pumpIndex].Qmax /= Ucf[FLOW];
3949
+ net->Pump[pumpIndex].Hmax /= Ucf[HEAD];
4223
3950
  }
4224
3951
  break;
4225
3952
 
@@ -4258,43 +3985,6 @@ int DLLEXPORT EN_setlinkvalue(EN_Project p, int index, int property, double valu
4258
3985
  net->Pump[pumpIndex].Epat = patIndex;
4259
3986
  }
4260
3987
  break;
4261
-
4262
- case EN_PCV_CURVE:
4263
- if (Link[index].Type == PCV)
4264
- {
4265
- curveIndex = ROUND(value);
4266
- if (curveIndex < 0 || curveIndex > net->Ncurves) return 206;
4267
- net->Valve[findvalve(&p->network, index)].Curve = curveIndex;
4268
- }
4269
- break;
4270
-
4271
- case EN_GPV_CURVE:
4272
- if (Link[index].Type == GPV)
4273
- {
4274
- curveIndex = ROUND(value);
4275
- if (curveIndex < 0 || curveIndex > net->Ncurves) return 206;
4276
- Link[index].Kc = curveIndex;
4277
- if (hyd->OpenHflag == FALSE) Link[index].InitSetting = curveIndex;
4278
- }
4279
- break;
4280
-
4281
- case EN_LEAK_AREA: // leak area in sq mm per 100 pipe length units
4282
- if (value < 0.0) return 211;
4283
- Link[index].LeakArea = value / Ucf[LENGTH];
4284
- break;
4285
-
4286
- case EN_LEAK_EXPAN: // leak area expansion slope (sq mm per unit of head)
4287
- if (value < 0.0) return 211;
4288
- Link[index].LeakExpan = value / Ucf[LENGTH];
4289
- break;
4290
-
4291
- case EN_VALVE_TYPE:
4292
- if (hyd->OpenHflag || qual->OpenQflag) return 262; //Solver is running
4293
- if (Link[index].Type <= PUMP) return 264; //Link not a valve
4294
- valveType = ROUND(value);
4295
- if (valveType < PRV || valveType > PCV) return 213; //Invalid valve type
4296
- if (valveType == Link[index].Type) return 0; //No type change
4297
- return changevalvetype(p, index, valveType); //See project.c
4298
3988
 
4299
3989
  default:
4300
3990
  return 251;
@@ -4353,20 +4043,20 @@ int DLLEXPORT EN_getvertexcount(EN_Project p, int index, int *count)
4353
4043
  */
4354
4044
  {
4355
4045
  Network *net = &p->network;
4356
-
4046
+
4357
4047
  Slink *Link = net->Link;
4358
4048
  Pvertices vertices;
4359
-
4049
+
4360
4050
  // Check that link exists
4361
4051
  *count = 0;
4362
4052
  if (!p->Openflag) return 102;
4363
4053
  if (index <= 0 || index > net->Nlinks) return 204;
4364
-
4054
+
4365
4055
  // Set count to number of vertices
4366
4056
  vertices = Link[index].Vertices;
4367
4057
  if (vertices) *count = vertices->Npts;
4368
4058
  return 0;
4369
- }
4059
+ }
4370
4060
 
4371
4061
  int DLLEXPORT EN_getvertex(EN_Project p, int index, int vertex, double *x, double *y)
4372
4062
  /*----------------------------------------------------------------
@@ -4380,54 +4070,25 @@ int DLLEXPORT EN_getvertex(EN_Project p, int index, int vertex, double *x, doubl
4380
4070
  */
4381
4071
  {
4382
4072
  Network *net = &p->network;
4383
-
4073
+
4384
4074
  Slink *Link = net->Link;
4385
4075
  Pvertices vertices;
4386
-
4076
+
4387
4077
  // Check that link exists
4388
4078
  *x = MISSING;
4389
4079
  *y = MISSING;
4390
4080
  if (!p->Openflag) return 102;
4391
4081
  if (index <= 0 || index > net->Nlinks) return 204;
4392
-
4082
+
4393
4083
  // Check that vertex exists
4394
4084
  vertices = Link[index].Vertices;
4395
4085
  if (vertices == NULL) return 255;
4396
4086
  if (vertex <= 0 || vertex > vertices->Npts) return 255;
4397
4087
  *x = vertices->X[vertex - 1];
4398
- *y = vertices->Y[vertex - 1];
4399
- return 0;
4400
- }
4401
-
4402
- int DLLEXPORT EN_setvertex(EN_Project p, int index, int vertex, double x, double y)
4403
- /*----------------------------------------------------------------
4404
- ** Input: index = link index
4405
- ** vertex = index of a link vertex point
4406
- ** x = vertex point's X-coordinate
4407
- ** y = vertex point's Y-coordinate
4408
- ** Returns: error code
4409
- ** Purpose: sets the coordinates of a vertex point in a link
4410
- **----------------------------------------------------------------
4411
- */
4412
- {
4413
- Network *net = &p->network;
4414
-
4415
- Slink *Link = net->Link;
4416
- Pvertices vertices;
4417
-
4418
- // Check that link exists
4419
- if (!p->Openflag) return 102;
4420
- if (index <= 0 || index > net->Nlinks) return 204;
4421
-
4422
- // Check that vertex exists
4423
- vertices = Link[index].Vertices;
4424
- if (vertices == NULL) return 255;
4425
- if (vertex <= 0 || vertex > vertices->Npts) return 255;
4426
- vertices->X[vertex - 1] = x;
4427
- vertices->Y[vertex - 1] = y;
4088
+ *y = vertices->Y[vertex - 1];
4428
4089
  return 0;
4429
4090
  }
4430
-
4091
+
4431
4092
  int DLLEXPORT EN_setvertices(EN_Project p, int index, double *x, double *y, int count)
4432
4093
  /*----------------------------------------------------------------
4433
4094
  ** Input: index = link index
@@ -4440,11 +4101,11 @@ int DLLEXPORT EN_setvertices(EN_Project p, int index, double *x, double *y, int
4440
4101
  */
4441
4102
  {
4442
4103
  Network *net = &p->network;
4443
-
4104
+
4444
4105
  Slink *link;
4445
4106
  int i;
4446
4107
  int err = 0;
4447
-
4108
+
4448
4109
  // Check that link exists
4449
4110
  if (!p->Openflag) return 102;
4450
4111
  if (index <= 0 || index > net->Nlinks) return 204;
@@ -4452,7 +4113,7 @@ int DLLEXPORT EN_setvertices(EN_Project p, int index, double *x, double *y, int
4452
4113
 
4453
4114
  // Delete existing set of vertices
4454
4115
  freelinkvertices(link);
4455
-
4116
+
4456
4117
  // Add each new vertex to the link
4457
4118
  for (i = 0; i < count; i++)
4458
4119
  {
@@ -4461,7 +4122,7 @@ int DLLEXPORT EN_setvertices(EN_Project p, int index, double *x, double *y, int
4461
4122
  }
4462
4123
  if (err) freelinkvertices(link);
4463
4124
  return err;
4464
- }
4125
+ }
4465
4126
 
4466
4127
  /********************************************************************
4467
4128
 
@@ -4527,7 +4188,10 @@ int DLLEXPORT EN_setheadcurveindex(EN_Project p, int linkIndex, int curveIndex)
4527
4188
  {
4528
4189
  Network *net = &p->network;
4529
4190
 
4191
+ double *Ucf = p->Ucf;
4530
4192
  int pumpIndex;
4193
+ int oldCurveIndex;
4194
+ int newCurveType;
4531
4195
  int err = 0;
4532
4196
  Spump *pump;
4533
4197
 
@@ -4537,12 +4201,43 @@ int DLLEXPORT EN_setheadcurveindex(EN_Project p, int linkIndex, int curveIndex)
4537
4201
  if (PUMP != net->Link[linkIndex].Type) return 0;
4538
4202
  if (curveIndex < 0 || curveIndex > net->Ncurves) return 206;
4539
4203
 
4540
- // Assign the new curve to the pump
4204
+ // Save values that need to be restored in case new curve is invalid
4541
4205
  pumpIndex = findpump(net, linkIndex);
4542
- pump = &net->Pump[pumpIndex];
4206
+ pump = &p->network.Pump[pumpIndex];
4207
+ oldCurveIndex = pump->Hcurve;
4208
+ newCurveType = p->network.Curve[curveIndex].Type;
4209
+
4210
+ // Assign the new curve to the pump
4211
+ pump->Ptype = NOCURVE;
4543
4212
  pump->Hcurve = curveIndex;
4544
- net->Link[linkIndex].Km = 0.0;
4545
- return 0;
4213
+ if (curveIndex == 0) return 0;
4214
+
4215
+ // Update the pump's head curve parameters (which also changes
4216
+ // the new curve's Type to PUMP_CURVE)
4217
+ err = updatepumpparams(p, pumpIndex);
4218
+
4219
+ // If the parameter updating failed (new curve was not a valid pump curve)
4220
+ // restore the pump's original curve and its parameters
4221
+ if (err > 0)
4222
+ {
4223
+ p->network.Curve[curveIndex].Type = newCurveType;
4224
+ pump->Ptype = NOCURVE;
4225
+ pump->Hcurve = oldCurveIndex;
4226
+ if (oldCurveIndex == 0) return err;
4227
+ updatepumpparams(p, pumpIndex);
4228
+ }
4229
+
4230
+ // Convert the units of the updated pump parameters to feet and cfs
4231
+ if (pump->Ptype == POWER_FUNC)
4232
+ {
4233
+ pump->H0 /= Ucf[HEAD];
4234
+ pump->R *= (pow(Ucf[FLOW], pump->N) / Ucf[HEAD]);
4235
+ }
4236
+ pump->Q0 /= Ucf[FLOW];
4237
+ pump->Qmax /= Ucf[FLOW];
4238
+ pump->Hmax /= Ucf[HEAD];
4239
+
4240
+ return err;
4546
4241
  }
4547
4242
 
4548
4243
  /********************************************************************
@@ -4551,7 +4246,7 @@ int DLLEXPORT EN_setheadcurveindex(EN_Project p, int linkIndex, int curveIndex)
4551
4246
 
4552
4247
  ********************************************************************/
4553
4248
 
4554
- int DLLEXPORT EN_addpattern(EN_Project p, const char *id)
4249
+ int DLLEXPORT EN_addpattern(EN_Project p, char *id)
4555
4250
  /*----------------------------------------------------------------
4556
4251
  ** Input: id = time pattern ID name
4557
4252
  ** Output: none
@@ -4599,70 +4294,6 @@ int DLLEXPORT EN_addpattern(EN_Project p, const char *id)
4599
4294
  return 0;
4600
4295
  }
4601
4296
 
4602
- int DLLEXPORT EN_loadpatternfile(EN_Project p, const char *filename, const char *id)
4603
- /*----------------------------------------------------------------
4604
- ** Input: filename = name of the file containing pattern data
4605
- ** id = ID for the new pattern
4606
- ** Output: none
4607
- ** Returns: error code
4608
- ** Purpose: loads time patterns from a file into a project under a specific pattern ID
4609
- **----------------------------------------------------------------
4610
- */
4611
- {
4612
- FILE *file;
4613
- char line[MAXLINE+1];
4614
- char *tok;
4615
- int err = 0;
4616
- int i;
4617
- int len = 0;
4618
- double value;
4619
- double *values = NULL;
4620
- int CHUNK = 50;
4621
-
4622
- if (!p->Openflag) return 102;
4623
-
4624
- file = fopen(filename, "r");
4625
- if (file == NULL) return 302;
4626
-
4627
- // Add a new pattern or use an existing pattern.
4628
- err = EN_getpatternindex(p, id, &i);
4629
- if (err == 205) {
4630
- if ((err = EN_addpattern(p, id)) != 0) {
4631
- fclose(file);
4632
- return err;
4633
- }
4634
- i = p->network.Npats;
4635
- }
4636
-
4637
- // Read pattern values
4638
- while (fgets(line, sizeof(line), file) != NULL) {
4639
-
4640
- // Skip lines that don't contain valid numbers
4641
- tok = strtok(line, SEPSTR);
4642
- if (tok == NULL) continue;
4643
- if (!getfloat(tok, &value)) continue;
4644
-
4645
- // Resize multiplier array if it's full
4646
- if (len % CHUNK == 0) {
4647
- values = (double *) realloc(values, (len + CHUNK) * sizeof(double));
4648
-
4649
- // Abort if memory allocation error
4650
- if (values == NULL) {
4651
- fclose(file);
4652
- return 101;
4653
- }
4654
- }
4655
- values[len] = value;
4656
- len++;
4657
- }
4658
- fclose(file);
4659
-
4660
- // Transfer multipliers to pattern
4661
- err = EN_setpattern(p, i, values, len);
4662
- free(values);
4663
- return err;
4664
- }
4665
-
4666
4297
  int DLLEXPORT EN_deletepattern(EN_Project p, int index)
4667
4298
  /*----------------------------------------------------------------
4668
4299
  ** Input: index = index of the pattern to delete
@@ -4692,10 +4323,6 @@ int DLLEXPORT EN_deletepattern(EN_Project p, int index)
4692
4323
  if (hyd->Epat == index) hyd->Epat = 0;
4693
4324
  else if (hyd->Epat > index) hyd->Epat--;
4694
4325
 
4695
- // Modify global default demand pattern
4696
- if (hyd->DefPat == index) hyd->DefPat = 0;
4697
- else if (hyd->DefPat > index) hyd->DefPat--;
4698
-
4699
4326
  // Free the pattern's factor array
4700
4327
  FREE(net->Pattern[index].F);
4701
4328
  FREE(net->Pattern[index].Comment);
@@ -4707,7 +4334,7 @@ int DLLEXPORT EN_deletepattern(EN_Project p, int index)
4707
4334
  return 0;
4708
4335
  }
4709
4336
 
4710
- int DLLEXPORT EN_getpatternindex(EN_Project p, const char *id, int *index)
4337
+ int DLLEXPORT EN_getpatternindex(EN_Project p, char *id, int *index)
4711
4338
  /*----------------------------------------------------------------
4712
4339
  ** Input: id = time pattern name
4713
4340
  ** Output: index = time pattern index
@@ -4748,7 +4375,7 @@ int DLLEXPORT EN_getpatternid(EN_Project p, int index, char *id)
4748
4375
  return 0;
4749
4376
  }
4750
4377
 
4751
- int DLLEXPORT EN_setpatternid(EN_Project p, int index, const char *id)
4378
+ int DLLEXPORT EN_setpatternid(EN_Project p, int index, char *id)
4752
4379
  /*----------------------------------------------------------------
4753
4380
  ** Input: index = time pattern index
4754
4381
  ** id = time pattern ID name
@@ -4845,7 +4472,7 @@ int DLLEXPORT EN_getaveragepatternvalue(EN_Project p, int index, double *value)
4845
4472
 
4846
4473
  *value = 0.0;
4847
4474
  if (!p->Openflag) return 102;
4848
- if (index < 0 || index > net->Npats) return 205;
4475
+ if (index < 1 || index > net->Npats) return 205;
4849
4476
  for (i = 0; i < Pattern[index].Length; i++)
4850
4477
  {
4851
4478
  *value += (double)Pattern[index].F[i];
@@ -4892,7 +4519,7 @@ int DLLEXPORT EN_setpattern(EN_Project p, int index, double *values, int len)
4892
4519
 
4893
4520
  ********************************************************************/
4894
4521
 
4895
- int DLLEXPORT EN_addcurve(EN_Project p, const char *id)
4522
+ int DLLEXPORT EN_addcurve(EN_Project p, char *id)
4896
4523
  /*----------------------------------------------------------------
4897
4524
  ** Input: id = data curve ID name
4898
4525
  ** Output: none
@@ -4984,7 +4611,7 @@ int DLLEXPORT EN_deletecurve(EN_Project p, int index)
4984
4611
  return 0;
4985
4612
  }
4986
4613
 
4987
- int DLLEXPORT EN_getcurveindex(EN_Project p, const char *id, int *index)
4614
+ int DLLEXPORT EN_getcurveindex(EN_Project p, char *id, int *index)
4988
4615
  /*----------------------------------------------------------------
4989
4616
  ** Input: id = data curve name
4990
4617
  ** Output: index = data curve index
@@ -5016,7 +4643,7 @@ int DLLEXPORT EN_getcurveid(EN_Project p, int index, char *id)
5016
4643
  return 0;
5017
4644
  }
5018
4645
 
5019
- int DLLEXPORT EN_setcurveid(EN_Project p, int index, const char *id)
4646
+ int DLLEXPORT EN_setcurveid(EN_Project p, int index, char *id)
5020
4647
  /*----------------------------------------------------------------
5021
4648
  ** Input: index = data curve index
5022
4649
  ** id = data curve ID name
@@ -5072,23 +4699,6 @@ int DLLEXPORT EN_getcurvetype(EN_Project p, int index, int *type)
5072
4699
  return 0;
5073
4700
  }
5074
4701
 
5075
- int DLLEXPORT EN_setcurvetype(EN_Project p, int index, int type)
5076
- /*----------------------------------------------------------------
5077
- ** Input: index = data curve index
5078
- ** type = type of data curve (see EN_CurveType)
5079
- ** Returns: error code
5080
- ** Purpose: sets the type assigned to a data curve
5081
- **----------------------------------------------------------------
5082
- */
5083
- {
5084
- Network *net = &p->network;
5085
- if (!p->Openflag) return 102;
5086
- if (index < 1 || index > net->Ncurves) return 206;
5087
- if (type < 0 || type > EN_VALVE_CURVE) return 251;
5088
- net->Curve[index].Type = type;
5089
- return 0;
5090
- }
5091
-
5092
4702
  int DLLEXPORT EN_getcurvevalue(EN_Project p, int curveIndex, int pointIndex,
5093
4703
  double *x, double *y)
5094
4704
  /*----------------------------------------------------------------
@@ -5158,7 +4768,9 @@ int DLLEXPORT EN_setcurvevalue(EN_Project p, int curveIndex, int pointIndex,
5158
4768
  // Insert new point into curve
5159
4769
  curve->X[n] = x;
5160
4770
  curve->Y[n] = y;
5161
- return 0;
4771
+
4772
+ // Adjust parameters for pumps using curve as a head curve
4773
+ return adjustpumpparams(p, curveIndex);
5162
4774
  }
5163
4775
 
5164
4776
  int DLLEXPORT EN_getcurve(EN_Project p, int index, char *id, int *nPoints,
@@ -5230,7 +4842,9 @@ int DLLEXPORT EN_setcurve(EN_Project p, int index, double *xValues,
5230
4842
  curve->X[j] = xValues[j];
5231
4843
  curve->Y[j] = yValues[j];
5232
4844
  }
5233
- return 0;
4845
+
4846
+ // Adjust parameters for pumps using curve as a head curve
4847
+ return adjustpumpparams(p, index);
5234
4848
  }
5235
4849
 
5236
4850
  /********************************************************************
@@ -5256,30 +4870,84 @@ int DLLEXPORT EN_addcontrol(EN_Project p, int type, int linkIndex, double settin
5256
4870
  */
5257
4871
  {
5258
4872
  Network *net = &p->network;
4873
+ Parser *parser = &p->parser;
4874
+
4875
+ char status = ACTIVE;
4876
+ int n;
4877
+ long t = 0;
4878
+ double s = setting, lvl = level;
4879
+ double *Ucf = p->Ucf;
4880
+ Scontrol *control;
5259
4881
 
5260
- int err, n;
5261
- Scontrol ctrl;
5262
4882
 
5263
4883
  // Check that project exists
5264
4884
  if (!p->Openflag) return 102;
5265
4885
 
5266
4886
  // Check that controlled link exists
5267
4887
  if (linkIndex <= 0 || linkIndex > net->Nlinks) return 204;
5268
-
5269
- // Insert control properties into a temporary struct
5270
- err = setcontrol(p, type, linkIndex, setting, nodeIndex, level, &ctrl);
5271
- if (err > 0) return err;
4888
+
4889
+ // Cannot control check valve
4890
+ if (net->Link[linkIndex].Type == CVPIPE) return 207;
4891
+
4892
+ // Check for valid parameters
4893
+ if (type < 0 || type > EN_TIMEOFDAY) return 251;
4894
+ if (type == EN_LOWLEVEL || type == EN_HILEVEL)
4895
+ {
4896
+ if (nodeIndex < 1 || nodeIndex > net->Nnodes) return 203;
4897
+ }
4898
+ else nodeIndex = 0;
4899
+ if (s < 0.0 || lvl < 0.0) return 202;
4900
+
4901
+ // Adjust units of control parameters
4902
+ switch (net->Link[linkIndex].Type)
4903
+ {
4904
+ case PRV:
4905
+ case PSV:
4906
+ case PBV:
4907
+ s /= Ucf[PRESSURE];
4908
+ break;
4909
+ case FCV:
4910
+ s /= Ucf[FLOW];
4911
+ break;
4912
+ case GPV:
4913
+ if (s == 0.0) status = CLOSED;
4914
+ else if (s == 1.0) status = OPEN;
4915
+ else return 202;
4916
+ s = net->Link[linkIndex].Kc;
4917
+ break;
4918
+ case PIPE:
4919
+ case PUMP:
4920
+ status = OPEN;
4921
+ if (s == 0.0) status = CLOSED;
4922
+ default:
4923
+ break;
4924
+ }
4925
+
4926
+ if (type == LOWLEVEL || type == HILEVEL)
4927
+ {
4928
+ if (nodeIndex > net->Njuncs) lvl = net->Node[nodeIndex].El + level / Ucf[ELEV];
4929
+ else lvl = net->Node[nodeIndex].El + level / Ucf[PRESSURE];
4930
+ }
4931
+ if (type == TIMER) t = (long)ROUND(lvl);
4932
+ if (type == TIMEOFDAY) t = (long)ROUND(lvl) % SECperDAY;
5272
4933
 
5273
4934
  // Expand project's array of controls
5274
4935
  n = net->Ncontrols + 1;
5275
4936
  net->Control = (Scontrol *)realloc(net->Control, (n + 1) * sizeof(Scontrol));
5276
4937
 
5277
4938
  // Set properties of the new control
5278
- net->Control[n] = ctrl;
4939
+ control = &net->Control[n];
4940
+ control->Type = (char)type;
4941
+ control->Link = linkIndex;
4942
+ control->Node = nodeIndex;
4943
+ control->Status = status;
4944
+ control->Setting = s;
4945
+ control->Grade = lvl;
4946
+ control->Time = t;
5279
4947
 
5280
4948
  // Update number of controls
5281
4949
  net->Ncontrols = n;
5282
- p->parser.MaxControls = n;
4950
+ parser->MaxControls = n;
5283
4951
 
5284
4952
  // Replace the control's index
5285
4953
  *index = n;
@@ -5362,8 +5030,8 @@ int DLLEXPORT EN_getcontrol(EN_Project p, int index, int *type, int *linkIndex,
5362
5030
  break;
5363
5031
  }
5364
5032
  }
5365
- else if (control->Status == OPEN) s = SET_OPEN;
5366
- else s = SET_CLOSED;
5033
+ else if (control->Status == OPEN) s = 1.0;
5034
+ else s = 0.0;
5367
5035
 
5368
5036
  // Retrieve level value for a node level control
5369
5037
  *nodeIndex = control->Node;
@@ -5385,8 +5053,8 @@ int DLLEXPORT EN_getcontrol(EN_Project p, int index, int *type, int *linkIndex,
5385
5053
  {
5386
5054
  lvl = (double)control->Time;
5387
5055
  }
5388
- *setting = s;
5389
- *level = lvl;
5056
+ *setting = (double)s;
5057
+ *level = (double)lvl;
5390
5058
  return 0;
5391
5059
  }
5392
5060
 
@@ -5408,63 +5076,81 @@ int DLLEXPORT EN_setcontrol(EN_Project p, int index, int type, int linkIndex,
5408
5076
  {
5409
5077
  Network *net = &p->network;
5410
5078
 
5411
- int err;
5412
- Scontrol ctrl;
5079
+ char status = ACTIVE;
5080
+ long t = 0;
5081
+ double s = setting, lvl = level;
5082
+ double *Ucf = p->Ucf;
5083
+ Slink *link;
5084
+ Scontrol *control;
5413
5085
 
5414
5086
  // Check that project exists
5415
5087
  if (!p->Openflag) return 102;
5416
5088
 
5417
5089
  // Check that control exists
5418
5090
  if (index <= 0 || index > net->Ncontrols) return 241;
5091
+ control = &net->Control[index];
5419
5092
 
5420
5093
  // Check that controlled link exists (0 index de-activates the control)
5421
5094
  if (linkIndex == 0)
5422
5095
  {
5423
- net->Control[index].Link = 0;
5096
+ control->Link = 0;
5424
5097
  return 0;
5425
5098
  }
5426
5099
  if (linkIndex < 0 || linkIndex > net->Nlinks) return 204;
5427
5100
 
5428
- // Assign new set of properties to control
5429
- err = setcontrol(p, type, linkIndex, setting, nodeIndex, level, &ctrl);
5430
- if (err > 0) return err;
5431
- net->Control[index] = ctrl;
5432
- return 0;
5433
- }
5434
-
5435
-
5436
- int DLLEXPORT EN_getcontrolenabled(EN_Project p, int index, int *enabled)
5437
- {
5438
- Network *net = &p->network;
5439
- Scontrol *control;
5440
-
5441
- // Check for valid arguments
5442
- if (!p->Openflag)
5443
- return 102;
5444
- if (index <= 0 || index > net->Ncontrols)
5445
- return 241;
5446
-
5447
- control = &net->Control[index];
5448
- *enabled = control->isEnabled;
5449
- return 0;
5450
- }
5101
+ // Cannot control check valve
5102
+ if (net->Link[linkIndex].Type == CVPIPE) return 207;
5451
5103
 
5104
+ // Check for valid control properties
5105
+ if (type < 0 || type > EN_TIMEOFDAY) return 251;
5106
+ if (type == EN_LOWLEVEL || type == EN_HILEVEL)
5107
+ {
5108
+ if (nodeIndex < 1 || nodeIndex > net->Nnodes) return 203;
5109
+ }
5110
+ else nodeIndex = 0;
5111
+ if (s < 0.0 || lvl < 0.0) return 202;
5452
5112
 
5453
- int DLLEXPORT EN_setcontrolenabled(EN_Project p, int index, int enabled)
5454
- {
5455
- Network *net = &p->network;
5456
- Scontrol *control;
5457
-
5458
- // Check for valid arguments
5459
- if (enabled != TRUE && enabled != FALSE)
5460
- return 202; // illegal numeric value
5461
- if (!p->Openflag)
5462
- return 102;
5463
- if (index <= 0 || index > net->Ncontrols)
5464
- return 241;
5465
-
5466
- control = &net->Control[index];
5467
- control->isEnabled = enabled;
5113
+ // Adjust units of control's properties
5114
+ link = &net->Link[linkIndex];
5115
+ switch (link->Type)
5116
+ {
5117
+ case PRV:
5118
+ case PSV:
5119
+ case PBV:
5120
+ s /= Ucf[PRESSURE];
5121
+ break;
5122
+ case FCV:
5123
+ s /= Ucf[FLOW];
5124
+ break;
5125
+ case GPV:
5126
+ if (s == 0.0) status = CLOSED;
5127
+ else if (s == 1.0) status = OPEN;
5128
+ else return 202;
5129
+ s = link->Kc;
5130
+ break;
5131
+ case PIPE:
5132
+ case PUMP:
5133
+ status = OPEN;
5134
+ if (s == 0.0) status = CLOSED;
5135
+ default:
5136
+ break;
5137
+ }
5138
+ if (type == LOWLEVEL || type == HILEVEL)
5139
+ {
5140
+ if (nodeIndex > net->Njuncs) lvl = net->Node[nodeIndex].El + level / Ucf[ELEV];
5141
+ else lvl = net->Node[nodeIndex].El + level / Ucf[PRESSURE];
5142
+ }
5143
+ if (type == TIMER) t = (long)ROUND(lvl);
5144
+ if (type == TIMEOFDAY) t = (long)ROUND(lvl) % SECperDAY;
5145
+
5146
+ /* Reset control's parameters */
5147
+ control->Type = (char)type;
5148
+ control->Link = linkIndex;
5149
+ control->Node = nodeIndex;
5150
+ control->Status = status;
5151
+ control->Setting = s;
5152
+ control->Grade = lvl;
5153
+ control->Time = t;
5468
5154
  return 0;
5469
5155
  }
5470
5156
 
@@ -5718,7 +5404,7 @@ int DLLEXPORT EN_setpremisestatus(EN_Project p, int ruleIndex, int premiseIndex,
5718
5404
  ** Input: ruleIndex = rule index
5719
5405
  ** premiseIndex = premise index
5720
5406
  ** status = object status being tested against
5721
- ** (see EN_RuleStatus)
5407
+ ** (see EN_RuleStatus))
5722
5408
  ** Output: none
5723
5409
  ** Returns: error code
5724
5410
  ** Purpose: sets the status of an object being tested against
@@ -5770,7 +5456,7 @@ int DLLEXPORT EN_getthenaction(EN_Project p, int ruleIndex, int actionIndex,
5770
5456
  ** Input: ruleIndex = rule index
5771
5457
  ** actionIndex = index of a rule's THEN actions
5772
5458
  ** Output: linkIndex = index of link appearing in the action
5773
- ** status = status assigned to the link (see EN_RuleStatus)
5459
+ ** status = status assigned to the link (see EN_RuleStatus))
5774
5460
  ** setting = setting assigned to the link
5775
5461
  ** Returns: error code
5776
5462
  ** Purpose: retrieves the properties of a rule's THEN action
@@ -5798,7 +5484,7 @@ int DLLEXPORT EN_setthenaction(EN_Project p, int ruleIndex, int actionIndex,
5798
5484
  ** Input: ruleIndex = rule index
5799
5485
  ** actionIndex = index of a rule's THEN actions
5800
5486
  ** linkIndex = index of link appearing in the action
5801
- ** status = status assigned to the link (see EN_RuleStatus)
5487
+ ** status = status assigned to the link (see EN_RuleStatus))
5802
5488
  ** setting = setting assigned to the link
5803
5489
  ** Returns: error code
5804
5490
  ** Purpose: sets the properties of a rule's THEN action
@@ -5826,7 +5512,7 @@ int DLLEXPORT EN_getelseaction(EN_Project p, int ruleIndex, int actionIndex,
5826
5512
  ** Input: ruleIndex = rule index
5827
5513
  ** actionIndex = index of a rule's ELSE actions
5828
5514
  ** Output: linkIndex = index of link appearing in the action
5829
- ** status = status assigned to the link (see EN_RuleStatus)
5515
+ ** status = status assigned to the link (see EN_RuleStatus))
5830
5516
  ** setting = setting assigned to the link
5831
5517
  ** Returns: error code
5832
5518
  ** Purpose: retrieves the properties of a rule's ELSE action
@@ -5854,7 +5540,7 @@ int DLLEXPORT EN_setelseaction(EN_Project p, int ruleIndex, int actionIndex,
5854
5540
  ** Input: ruleIndex = rule index
5855
5541
  ** actionIndex = index of a rule's ELSE actions
5856
5542
  ** linkIndex = index of link appearing in the action
5857
- ** status = status assigned to the link (see EN_RuleStatus)
5543
+ ** status = status assigned to the link (see EN_RuleStatus))
5858
5544
  ** setting = setting assigned to the link
5859
5545
  ** Returns: error code
5860
5546
  ** Purpose: sets the properties of a rule's ELSE action
@@ -5890,41 +5576,3 @@ int DLLEXPORT EN_setrulepriority(EN_Project p, int index, double priority)
5890
5576
  p->network.Rule[index].priority = priority;
5891
5577
  return 0;
5892
5578
  }
5893
-
5894
-
5895
- int DLLEXPORT EN_getruleenabled(EN_Project p, int index, int *enabled)
5896
- {
5897
- Network *net = &p->network;
5898
- Srule *rule;
5899
-
5900
- // Check for valid arguments
5901
- if (!p->Openflag)
5902
- return 102;
5903
- if (index <= 0 || index > net->Nrules)
5904
- return 241;
5905
-
5906
- rule = &net->Rule[index];
5907
- *enabled = rule->isEnabled;
5908
- return 0;
5909
- }
5910
-
5911
-
5912
- int DLLEXPORT EN_setruleenabled(EN_Project p, int index, int enabled)
5913
- {
5914
- Network *net = &p->network;
5915
- Srule *rule;
5916
-
5917
- // Check for valid arguments
5918
- if (enabled != TRUE && enabled != FALSE)
5919
- return 202; // illegal numeric value
5920
- if (!p->Openflag)
5921
- return 102;
5922
- if (index <= 0 || index > net->Nrules)
5923
- return 241;
5924
-
5925
- rule = &net->Rule[index];
5926
- rule->isEnabled = enabled;
5927
- return 0;
5928
- }
5929
-
5930
-