epyt-flow 0.14.0__py3-none-any.whl → 0.14.1__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 (60) hide show
  1. epyt_flow/EPANET/EPANET/SRC_engines/AUTHORS +40 -8
  2. epyt_flow/EPANET/EPANET/SRC_engines/LICENSE +3 -3
  3. epyt_flow/EPANET/EPANET/SRC_engines/enumstxt.h +24 -7
  4. epyt_flow/EPANET/EPANET/SRC_engines/epanet.c +726 -374
  5. epyt_flow/EPANET/EPANET/SRC_engines/epanet2.c +128 -32
  6. epyt_flow/EPANET/EPANET/SRC_engines/errors.dat +7 -1
  7. epyt_flow/EPANET/EPANET/SRC_engines/flowbalance.c +186 -0
  8. epyt_flow/EPANET/EPANET/SRC_engines/funcs.h +40 -14
  9. epyt_flow/EPANET/EPANET/SRC_engines/hash.c +177 -177
  10. epyt_flow/EPANET/EPANET/SRC_engines/hash.h +28 -28
  11. epyt_flow/EPANET/EPANET/SRC_engines/hydcoeffs.c +192 -40
  12. epyt_flow/EPANET/EPANET/SRC_engines/hydraul.c +101 -46
  13. epyt_flow/EPANET/EPANET/SRC_engines/hydsolver.c +85 -24
  14. epyt_flow/EPANET/EPANET/SRC_engines/hydstatus.c +29 -63
  15. epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2.h +70 -37
  16. epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2_2.h +408 -234
  17. epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2_enums.h +87 -37
  18. epyt_flow/EPANET/EPANET/SRC_engines/inpfile.c +153 -79
  19. epyt_flow/EPANET/EPANET/SRC_engines/input1.c +59 -94
  20. epyt_flow/EPANET/EPANET/SRC_engines/input2.c +73 -202
  21. epyt_flow/EPANET/EPANET/SRC_engines/input3.c +446 -351
  22. epyt_flow/EPANET/EPANET/SRC_engines/leakage.c +527 -0
  23. epyt_flow/EPANET/EPANET/SRC_engines/mempool.c +8 -4
  24. epyt_flow/EPANET/EPANET/SRC_engines/mempool.h +23 -23
  25. epyt_flow/EPANET/EPANET/SRC_engines/output.c +5 -4
  26. epyt_flow/EPANET/EPANET/SRC_engines/project.c +407 -75
  27. epyt_flow/EPANET/EPANET/SRC_engines/quality.c +12 -2
  28. epyt_flow/EPANET/EPANET/SRC_engines/qualreact.c +70 -13
  29. epyt_flow/EPANET/EPANET/SRC_engines/qualroute.c +7 -5
  30. epyt_flow/EPANET/EPANET/SRC_engines/report.c +88 -20
  31. epyt_flow/EPANET/EPANET/SRC_engines/rules.c +144 -6
  32. epyt_flow/EPANET/EPANET/SRC_engines/smatrix.c +19 -19
  33. epyt_flow/EPANET/EPANET/SRC_engines/text.h +16 -5
  34. epyt_flow/EPANET/EPANET/SRC_engines/types.h +73 -19
  35. epyt_flow/EPANET/EPANET/SRC_engines/util/cstr_helper.c +59 -0
  36. epyt_flow/EPANET/EPANET/SRC_engines/util/cstr_helper.h +38 -0
  37. epyt_flow/EPANET/EPANET/SRC_engines/util/errormanager.c +92 -0
  38. epyt_flow/EPANET/EPANET/SRC_engines/util/errormanager.h +39 -0
  39. epyt_flow/EPANET/EPANET/SRC_engines/util/filemanager.c +212 -0
  40. epyt_flow/EPANET/EPANET/SRC_engines/util/filemanager.h +81 -0
  41. epyt_flow/EPANET/EPANET/SRC_engines/validate.c +408 -0
  42. epyt_flow/EPANET/compile_linux.sh +1 -1
  43. epyt_flow/EPANET/compile_macos.sh +1 -1
  44. epyt_flow/VERSION +1 -1
  45. epyt_flow/gym/scenario_control_env.py +26 -3
  46. epyt_flow/simulation/events/quality_events.py +6 -6
  47. epyt_flow/simulation/events/sensor_faults.py +24 -24
  48. epyt_flow/simulation/events/system_event.py +3 -3
  49. epyt_flow/simulation/scada/scada_data.py +1 -1
  50. epyt_flow/simulation/scenario_simulator.py +14 -11
  51. epyt_flow/topology.py +8 -1
  52. epyt_flow/uncertainty/model_uncertainty.py +292 -150
  53. {epyt_flow-0.14.0.dist-info → epyt_flow-0.14.1.dist-info}/METADATA +2 -2
  54. {epyt_flow-0.14.0.dist-info → epyt_flow-0.14.1.dist-info}/RECORD +57 -51
  55. epyt_flow/EPANET/EPANET/SRC_engines/Readme_SRC_Engines.txt +0 -18
  56. epyt_flow/EPANET/EPANET/SRC_engines/epanet2.def +0 -131
  57. epyt_flow/EPANET/EPANET/SRC_engines/main.c +0 -93
  58. {epyt_flow-0.14.0.dist-info → epyt_flow-0.14.1.dist-info}/WHEEL +0 -0
  59. {epyt_flow-0.14.0.dist-info → epyt_flow-0.14.1.dist-info}/licenses/LICENSE +0 -0
  60. {epyt_flow-0.14.0.dist-info → epyt_flow-0.14.1.dist-info}/top_level.txt +0 -0
@@ -1,13 +1,13 @@
1
1
  /*
2
2
  ******************************************************************************
3
3
  Project: OWA EPANET
4
- Version: 2.2
4
+ Version: 2.3
5
5
  Module: project.c
6
6
  Description: project data management routines
7
7
  Authors: see AUTHORS
8
8
  Copyright: see AUTHORS
9
9
  License: see LICENSE
10
- Last Updated: 11/15/2019
10
+ Last Updated: 04/23/2025
11
11
  ******************************************************************************
12
12
  */
13
13
 
@@ -24,6 +24,81 @@
24
24
  #include "types.h"
25
25
  #include "funcs.h"
26
26
 
27
+ int openproject(Project *pr, const char *inpFile, const char *rptFile,
28
+ const char *outFile, int allowerrors)
29
+ /*----------------------------------------------------------------
30
+ ** Input: inpFile = name of input file
31
+ ** rptFile = name of report file
32
+ ** outFile = name of binary output file
33
+ ** allowerrors = TRUE if project can be opened with errors
34
+ ** Output: none
35
+ ** Returns: error code
36
+ ** Purpose: opens an EPANET input file & reads in network data
37
+ **----------------------------------------------------------------
38
+ */
39
+ {
40
+ int errcode = 0;
41
+ int hyderrcode = 0;
42
+ int projectopened;
43
+
44
+ // Set system flags
45
+ pr->Openflag = FALSE;
46
+ pr->hydraul.OpenHflag = FALSE;
47
+ pr->quality.OpenQflag = FALSE;
48
+ pr->outfile.SaveHflag = FALSE;
49
+ pr->outfile.SaveQflag = FALSE;
50
+ pr->Warnflag = FALSE;
51
+ pr->report.Messageflag = TRUE;
52
+ pr->report.Rptflag = 1;
53
+
54
+ // Initialize data arrays to NULL
55
+ initpointers(pr);
56
+
57
+ // Open input & report files
58
+ ERRCODE(openfiles(pr, inpFile, rptFile, outFile));
59
+ if (errcode > 0)
60
+ {
61
+ errmsg(pr, errcode);
62
+ return errcode;
63
+ }
64
+
65
+ // Allocate memory for project's data arrays
66
+ ERRCODE(netsize(pr));
67
+ ERRCODE(allocdata(pr));
68
+
69
+ // Read input data
70
+ ERRCODE(getdata(pr));
71
+
72
+ // Close input file
73
+ if (pr->parser.InFile != NULL)
74
+ {
75
+ fclose(pr->parser.InFile);
76
+ pr->parser.InFile = NULL;
77
+ }
78
+
79
+ // Input file read with no fatal errors
80
+ if (allowerrors) projectopened = (errcode == 0 || errcode == 200);
81
+ else projectopened = (errcode == 0);
82
+ if (projectopened)
83
+ {
84
+ // If using previously saved hydraulics file then open it
85
+ if (pr->outfile.Hydflag == USE)
86
+ {
87
+ hyderrcode = openhydfile(pr);
88
+ if (hyderrcode > 0)
89
+ {
90
+ errmsg(pr, hyderrcode);
91
+ pr->outfile.Hydflag = SCRATCH;
92
+ }
93
+ }
94
+
95
+ // Write input summary to report file
96
+ if (pr->report.Summaryflag) writesummary(pr);
97
+ pr->Openflag = TRUE;
98
+ }
99
+ errmsg(pr, errcode);
100
+ return errcode;
101
+ }
27
102
 
28
103
  int openfiles(Project *pr, const char *f1, const char *f2, const char *f3)
29
104
  /*----------------------------------------------------------------
@@ -93,10 +168,9 @@ int openhydfile(Project *pr)
93
168
  INT4 version;
94
169
  int errcode = 0;
95
170
 
96
- // If HydFile currently open, then close it if its not a scratch file
171
+ // If HydFile currently open, then close it
97
172
  if (pr->outfile.HydFile != NULL)
98
173
  {
99
- if (pr->outfile.Hydflag == SCRATCH) return 0;
100
174
  fclose(pr->outfile.HydFile);
101
175
  pr->outfile.HydFile = NULL;
102
176
  }
@@ -253,6 +327,11 @@ void initpointers(Project *pr)
253
327
  pr->hydraul.P = NULL;
254
328
  pr->hydraul.Y = NULL;
255
329
  pr->hydraul.Xflow = NULL;
330
+ pr->hydraul.FullDemand = NULL;
331
+ pr->hydraul.DemandFlow = NULL;
332
+ pr->hydraul.EmitterFlow = NULL;
333
+ pr->hydraul.LeakageFlow = NULL;
334
+ pr->hydraul.Leakage = NULL;
256
335
 
257
336
  pr->quality.NodeQual = NULL;
258
337
  pr->quality.PipeRateCoeff = NULL;
@@ -279,6 +358,8 @@ void initpointers(Project *pr)
279
358
  pr->hydraul.smatrix.NZSUB = NULL;
280
359
  pr->hydraul.smatrix.LNZ = NULL;
281
360
 
361
+ pr->report.reportCallback = NULL;
362
+
282
363
  initrules(pr);
283
364
  }
284
365
 
@@ -313,10 +394,18 @@ int allocdata(Project *pr)
313
394
  pr->hydraul.NodeDemand = (double *)calloc(n, sizeof(double));
314
395
  pr->hydraul.NodeHead = (double *)calloc(n, sizeof(double));
315
396
  pr->quality.NodeQual = (double *)calloc(n, sizeof(double));
397
+ pr->hydraul.FullDemand = (double *)calloc(n, sizeof(double));
398
+ pr->hydraul.DemandFlow = (double *)calloc(n, sizeof(double));
399
+ pr->hydraul.EmitterFlow = (double *)calloc(n, sizeof(double));
400
+ pr->hydraul.LeakageFlow = (double *)calloc(n, sizeof(double));
316
401
  ERRCODE(MEMCHECK(pr->network.Node));
317
402
  ERRCODE(MEMCHECK(pr->hydraul.NodeDemand));
318
403
  ERRCODE(MEMCHECK(pr->hydraul.NodeHead));
319
404
  ERRCODE(MEMCHECK(pr->quality.NodeQual));
405
+ ERRCODE(MEMCHECK(pr->hydraul.FullDemand));
406
+ ERRCODE(MEMCHECK(pr->hydraul.DemandFlow));
407
+ ERRCODE(MEMCHECK(pr->hydraul.EmitterFlow));
408
+ ERRCODE(MEMCHECK(pr->hydraul.LeakageFlow));
320
409
  }
321
410
 
322
411
  // Allocate memory for network links
@@ -359,11 +448,13 @@ int allocdata(Project *pr)
359
448
  pr->network.Node[n].D = NULL; // node demand
360
449
  pr->network.Node[n].S = NULL; // node source
361
450
  pr->network.Node[n].Comment = NULL;
451
+ pr->network.Node[n].Tag = NULL;
362
452
  }
363
453
  for (n = 0; n <= pr->parser.MaxLinks; n++)
364
454
  {
365
455
  pr->network.Link[n].Vertices = NULL;
366
456
  pr->network.Link[n].Comment = NULL;
457
+ pr->network.Link[n].Tag = NULL;
367
458
  }
368
459
  }
369
460
 
@@ -388,6 +479,10 @@ void freedata(Project *pr)
388
479
  free(pr->hydraul.LinkFlow);
389
480
  free(pr->hydraul.LinkSetting);
390
481
  free(pr->hydraul.LinkStatus);
482
+ free(pr->hydraul.FullDemand);
483
+ free(pr->hydraul.DemandFlow);
484
+ free(pr->hydraul.EmitterFlow);
485
+ free(pr->hydraul.LeakageFlow);
391
486
  free(pr->quality.NodeQual);
392
487
 
393
488
  // Free memory used for nodal adjacency lists
@@ -402,6 +497,7 @@ void freedata(Project *pr)
402
497
  freedemands(&(pr->network.Node[j]));
403
498
  free(pr->network.Node[j].S);
404
499
  free(pr->network.Node[j].Comment);
500
+ free(pr->network.Node[j].Tag);
405
501
  }
406
502
  free(pr->network.Node);
407
503
  }
@@ -413,6 +509,7 @@ void freedata(Project *pr)
413
509
  {
414
510
  freelinkvertices(&pr->network.Link[j]);
415
511
  free(pr->network.Link[j].Comment);
512
+ free(pr->network.Link[j].Tag);
416
513
  }
417
514
  }
418
515
  free(pr->network.Link);
@@ -482,7 +579,7 @@ Pdemand finddemand(Pdemand d, int index)
482
579
  return d;
483
580
  }
484
581
 
485
- int adddemand(Snode *node, double dbase, int dpat, char *dname)
582
+ int adddemand(Snode *node, double dbase, int dpat, const char *dname)
486
583
  /*----------------------------------------------------------------
487
584
  ** Input: node = a network junction node
488
585
  ** dbase = base demand value
@@ -550,31 +647,41 @@ int addlinkvertex(Slink *link, double x, double y)
550
647
  */
551
648
  {
552
649
  static int CHUNKSIZE = 5;
553
- int n;
650
+ int n, newCapacity;
554
651
  Pvertices vertices;
555
- if (link->Vertices == NULL)
652
+ double *newX, *newY;
653
+
654
+ vertices = link->Vertices;
655
+ if (vertices == NULL)
556
656
  {
557
657
  vertices = (struct Svertices *) malloc(sizeof(struct Svertices));
558
658
  if (vertices == NULL) return 101;
559
659
  vertices->Npts = 0;
560
- vertices->Capacity = CHUNKSIZE;
561
- vertices->X = (double *) calloc(vertices->Capacity, sizeof(double));
562
- vertices->Y = (double *) calloc(vertices->Capacity, sizeof(double));
660
+ vertices->Capacity = 0;
661
+ vertices->X = NULL;
662
+ vertices->Y = NULL;
563
663
  link->Vertices = vertices;
564
664
  }
565
- vertices = link->Vertices;
566
665
  if (vertices->Npts >= vertices->Capacity)
567
666
  {
568
- vertices->Capacity += CHUNKSIZE;
569
- vertices->X = realloc(vertices->X, vertices->Capacity * sizeof(double));
570
- vertices->Y = realloc(vertices->Y, vertices->Capacity * sizeof(double));
667
+ newCapacity = vertices->Capacity + CHUNKSIZE;
668
+ newX = realloc(vertices->X, newCapacity * sizeof(double));
669
+ newY = realloc(vertices->Y, newCapacity * sizeof(double));
670
+ if (newX == NULL || newY == NULL)
671
+ {
672
+ free(newX);
673
+ free(newY);
674
+ return 101;
675
+ }
676
+ vertices->Capacity = newCapacity;
677
+ vertices->X = newX;
678
+ vertices->Y = newY;
571
679
  }
572
- if (vertices->X == NULL || vertices->Y == NULL) return 101;
573
680
  n = vertices->Npts;
574
681
  vertices->X[n] = x;
575
682
  vertices->Y[n] = y;
576
683
  vertices->Npts++;
577
- return 0;
684
+ return 0;
578
685
  }
579
686
 
580
687
  void freelinkvertices(Slink *link)
@@ -647,7 +754,6 @@ int buildadjlists(Network *net)
647
754
  return errcode;
648
755
  }
649
756
 
650
-
651
757
  void freeadjlists(Network *net)
652
758
  /*
653
759
  **--------------------------------------------------------------
@@ -734,6 +840,66 @@ int incontrols(Project *pr, int objType, int index)
734
840
  return 0;
735
841
  }
736
842
 
843
+ int changevalvetype(Project *pr, int index, int type)
844
+ /*
845
+ **--------------------------------------------------------------
846
+ ** Input: index = link index
847
+ ** type = new valve type
848
+ ** Output: returns an error code
849
+ ** Purpose: changes a valve's type
850
+ **--------------------------------------------------------------
851
+ */
852
+ {
853
+ Network *net = &pr->network;
854
+ Slink *link;
855
+ int errcode;
856
+ double setting;
857
+
858
+ // Check that new valve type has legal connections
859
+ link = &net->Link[index];
860
+ if (link->Type <= PUMP) return 264;
861
+ errcode = valvecheck(pr, index, type, link->N1, link->N2);
862
+ if (errcode) return errcode;
863
+
864
+ // Preserve new type's setting in solver units
865
+ setting = link->InitSetting;
866
+ switch (link->Type)
867
+ {
868
+ case FCV:
869
+ setting *= pr->Ucf[FLOW];
870
+ break;
871
+ case PRV:
872
+ case PSV:
873
+ case PBV:
874
+ setting *= pr->Ucf[PRESSURE];
875
+ break;
876
+ case GPV:
877
+ setting = 0.0;
878
+ break;
879
+ }
880
+ switch (type)
881
+ {
882
+ case FCV:
883
+ setting /= pr->Ucf[FLOW];
884
+ break;
885
+ case PRV:
886
+ case PSV:
887
+ case PBV:
888
+ setting /= pr->Ucf[PRESSURE];
889
+ break;
890
+ }
891
+
892
+ // Save setting
893
+ if (type == GPV) setting = 0.0;
894
+ if (type == PCV) setting = MIN(setting, 100.0);
895
+ link->Kc = setting;
896
+ link->InitSetting = setting;
897
+
898
+ // Change valve link's type
899
+ link->Type = type;
900
+ return 0;
901
+ }
902
+
737
903
  int valvecheck(Project *pr, int index, int type, int j1, int j2)
738
904
  /*
739
905
  **--------------------------------------------------------------
@@ -795,7 +961,36 @@ int valvecheck(Project *pr, int index, int type, int j1, int j2)
795
961
  return 0;
796
962
  }
797
963
 
798
- int findnode(Network *network, char *id)
964
+ int unlinked(Project *pr)
965
+ /*
966
+ **--------------------------------------------------------------
967
+ ** Input: none
968
+ ** Output: returns error code if any unlinked junctions found
969
+ ** Purpose: checks for unlinked junctions in network
970
+ **
971
+ ** NOTE: unlinked tanks have no effect on computations.
972
+ **--------------------------------------------------------------
973
+ */
974
+ {
975
+ Network *net = &pr->network;
976
+ int i, count = 0;
977
+ char errmsg[MAXMSG + 1] = "";
978
+
979
+ for (i = 1; i <= net->Njuncs; i++)
980
+ {
981
+ if (pr->network.Adjlist[i] == NULL)
982
+ {
983
+ count++;
984
+ sprintf(pr->Msg, "Error 234: %s %s", geterrmsg(234, errmsg), net->Node[i].ID);
985
+ writeline(pr, pr->Msg);
986
+ }
987
+ if (count >= 10) break;
988
+ }
989
+ if (count > 0) return 233;
990
+ return 0;
991
+ }
992
+
993
+ int findnode(Network *network, const char *id)
799
994
  /*----------------------------------------------------------------
800
995
  ** Input: id = node ID
801
996
  ** Output: none
@@ -807,7 +1002,7 @@ int findnode(Network *network, char *id)
807
1002
  return (hashtable_find(network->NodeHashTable, id));
808
1003
  }
809
1004
 
810
- int findlink(Network *network, char *id)
1005
+ int findlink(Network *network, const char *id)
811
1006
  /*----------------------------------------------------------------
812
1007
  ** Input: id = link ID
813
1008
  ** Output: none
@@ -823,7 +1018,7 @@ int findtank(Network *network, int index)
823
1018
  /*----------------------------------------------------------------
824
1019
  ** Input: index = node index
825
1020
  ** Output: none
826
- ** Returns: index of tank with given node id, or NOTFOUND if tank not found
1021
+ ** Returns: index of tank with given node index, or NOTFOUND if tank not found
827
1022
  ** Purpose: for use in the deletenode function
828
1023
  **----------------------------------------------------------------
829
1024
  */
@@ -840,7 +1035,7 @@ int findpump(Network *network, int index)
840
1035
  /*----------------------------------------------------------------
841
1036
  ** Input: index = link ID
842
1037
  ** Output: none
843
- ** Returns: index of pump with given link id, or NOTFOUND if pump not found
1038
+ ** Returns: index of pump with given link index, or NOTFOUND if pump not found
844
1039
  ** Purpose: for use in the deletelink function
845
1040
  **----------------------------------------------------------------
846
1041
  */
@@ -857,7 +1052,7 @@ int findvalve(Network *network, int index)
857
1052
  /*----------------------------------------------------------------
858
1053
  ** Input: index = link ID
859
1054
  ** Output: none
860
- ** Returns: index of valve with given link id, or NOTFOUND if valve not found
1055
+ ** Returns: index of valve with given link index, or NOTFOUND if valve not found
861
1056
  ** Purpose: for use in the deletelink function
862
1057
  **----------------------------------------------------------------
863
1058
  */
@@ -870,7 +1065,7 @@ int findvalve(Network *network, int index)
870
1065
  return NOTFOUND;
871
1066
  }
872
1067
 
873
- int findpattern(Network *network, char *id)
1068
+ int findpattern(Network *network, const char *id)
874
1069
  /*----------------------------------------------------------------
875
1070
  ** Input: id = time pattern ID
876
1071
  ** Output: none
@@ -889,7 +1084,7 @@ int findpattern(Network *network, char *id)
889
1084
  return -1;
890
1085
  }
891
1086
 
892
- int findcurve(Network *network, char *id)
1087
+ int findcurve(Network *network, const char *id)
893
1088
  /*----------------------------------------------------------------
894
1089
  ** Input: id = data curve ID
895
1090
  ** Output: none
@@ -912,8 +1107,8 @@ void adjustpattern(int *pat, int index)
912
1107
  **----------------------------------------------------------------
913
1108
  */
914
1109
  {
915
- if (*pat == index) *pat = 0;
916
- else if (*pat > index) (*pat)--;
1110
+ if (*pat == index) *pat = 0;
1111
+ else if (*pat > index) (*pat)--;
917
1112
  }
918
1113
 
919
1114
  void adjustpatterns(Network *network, int index)
@@ -973,7 +1168,7 @@ void adjustcurves(Network *network, int index)
973
1168
  **----------------------------------------------------------------
974
1169
  */
975
1170
  {
976
- int j, k, setting;
1171
+ int j, k, curve;
977
1172
 
978
1173
  // Adjust tank volume curves
979
1174
  for (j = 1; j <= network->Ntanks; j++)
@@ -988,60 +1183,29 @@ void adjustcurves(Network *network, int index)
988
1183
  adjustcurve(&network->Pump[j].Ecurve, index);
989
1184
  }
990
1185
 
991
- // Adjust GPV curves
1186
+ // Adjust PCV & GPV curves
992
1187
  for (j = 1; j <= network->Nvalves; j++)
993
1188
  {
994
1189
  k = network->Valve[j].Link;
995
- if (network->Link[k].Type == GPV)
996
- {
997
- setting = INT(network->Link[k].Kc);
998
- adjustcurve(&setting, index);
999
- network->Link[k].Kc = setting;
1000
- }
1001
- }
1002
- }
1003
-
1004
- int adjustpumpparams(Project *pr, int curveIndex)
1005
- /*----------------------------------------------------------------
1006
- ** Input: curveIndex = index of a data curve
1007
- ** Output: returns an error code
1008
- ** Purpose: updates head curve parameters for pumps using a
1009
- ** curve whose data have been modified.
1010
- **----------------------------------------------------------------
1011
- */
1012
- {
1013
- Network *network = &pr->network;
1014
-
1015
- double *Ucf = pr->Ucf;
1016
- int j, err = 0;
1017
- Spump *pump;
1018
-
1019
- // Check each pump
1020
- for (j = 1; j <= network->Npumps; j++)
1021
- {
1022
- // Pump uses curve as head curve
1023
- pump = &network->Pump[j];
1024
- if ( curveIndex == pump->Hcurve)
1190
+ if (network->Link[k].Type == PCV)
1025
1191
  {
1026
- // Update its head curve parameters
1027
- pump->Ptype = NOCURVE;
1028
- err = updatepumpparams(pr, curveIndex);
1029
- if (err > 0) break;
1030
-
1031
- // Convert parameters to internal units
1032
- if (pump->Ptype == POWER_FUNC)
1192
+ if ((curve = network->Valve[j].Curve) > 0)
1033
1193
  {
1034
- pump->H0 /= Ucf[HEAD];
1035
- pump->R *= (pow(Ucf[FLOW], pump->N) / Ucf[HEAD]);
1194
+ adjustcurve(&curve, index);
1195
+ network->Valve[j].Curve = curve;
1196
+ if (curve == 0)
1197
+ network->Link[k].Kc = 0.0;
1036
1198
  }
1037
- pump->Q0 /= Ucf[FLOW];
1038
- pump->Qmax /= Ucf[FLOW];
1039
- pump->Hmax /= Ucf[HEAD];
1199
+ }
1200
+ if (network->Link[k].Type == GPV)
1201
+ {
1202
+ curve = INT(network->Link[k].Kc);
1203
+ adjustcurve(&curve, index);
1204
+ network->Link[k].Kc = curve;
1040
1205
  }
1041
1206
  }
1042
- return err;
1043
1207
  }
1044
-
1208
+
1045
1209
 
1046
1210
  int resizecurve(Scurve *curve, int size)
1047
1211
  /*----------------------------------------------------------------
@@ -1072,6 +1236,112 @@ int resizecurve(Scurve *curve, int size)
1072
1236
  return 0;
1073
1237
  }
1074
1238
 
1239
+
1240
+ int setcontrol(EN_Project p, int type, int linkIndex, double setting,
1241
+ int nodeIndex, double level, Scontrol *control)
1242
+ /*----------------------------------------------------------------
1243
+ ** Input: type = type of control (see EN_ControlType)
1244
+ ** linkIndex = index of link being controlled
1245
+ ** setting = link control setting (e.g., pump speed)
1246
+ ** nodeIndex = index of node controlling a link (for level controls)
1247
+ ** level = control activation level (pressure for junction nodes,
1248
+ ** water level for tank nodes or time value for time-based
1249
+ ** control)
1250
+ ** Output: control = control struct whose properties are being set
1251
+ ** Returns: error code
1252
+ ** Purpose: assigns properties to a control struct.
1253
+ **----------------------------------------------------------------
1254
+ */
1255
+ {
1256
+ Network *net = &p->network;
1257
+ Parser *parser = &p->parser;
1258
+
1259
+ long t = 0;
1260
+ double lvl = 0.0, s = MISSING;
1261
+ double *Ucf = p->Ucf;
1262
+ LinkType linktype;
1263
+ StatusType status = ACTIVE;
1264
+
1265
+ // Cannot control check valve
1266
+ linktype = net->Link[linkIndex].Type;
1267
+ if (linktype == CVPIPE) return 207;
1268
+
1269
+ // Check for valid control type and node index
1270
+ if (type < 0 || type > TIMEOFDAY) return 251;
1271
+ if (type == LOWLEVEL || type == HILEVEL)
1272
+ {
1273
+ if (nodeIndex < 1 || nodeIndex > net->Nnodes) return 203;
1274
+ }
1275
+ else nodeIndex = 0;
1276
+
1277
+ // Check if control setting is a status level
1278
+ if (setting == SET_OPEN)
1279
+ {
1280
+ status = OPEN;
1281
+ if (linktype == PUMP) s = 1.0;
1282
+ if (linktype == GPV) s = net->Link[linkIndex].Kc;
1283
+ }
1284
+ else if (setting == SET_CLOSED)
1285
+ {
1286
+ status = CLOSED;
1287
+ if (linktype == PUMP) s = 0.0;
1288
+ if (linktype == GPV) s = net->Link[linkIndex].Kc;
1289
+ }
1290
+
1291
+ // Convert units of control setting
1292
+ else
1293
+ {
1294
+ s = setting;
1295
+ switch (linktype)
1296
+ {
1297
+ case PIPE:
1298
+ case PUMP:
1299
+ if (s < 0.0) return 202;
1300
+ else if (s == 0.0) status = CLOSED;
1301
+ else status = OPEN;
1302
+ break;
1303
+ case PRV:
1304
+ case PSV:
1305
+ case PBV:
1306
+ s /= Ucf[PRESSURE];
1307
+ break;
1308
+ case FCV:
1309
+ s /= Ucf[FLOW];
1310
+ break;
1311
+ case GPV:
1312
+ if (s == 0.0) status = CLOSED;
1313
+ else if (s == 1.0) status = OPEN;
1314
+ else return 202;
1315
+ s = net->Link[linkIndex].Kc;
1316
+ break;
1317
+ }
1318
+ }
1319
+
1320
+ // Determine if control level is a pressure, tank level or time value
1321
+ if (type == LOWLEVEL || type == HILEVEL)
1322
+ {
1323
+ if (nodeIndex > net->Njuncs) lvl = net->Node[nodeIndex].El + level / Ucf[ELEV];
1324
+ else lvl = net->Node[nodeIndex].El + level / Ucf[PRESSURE];
1325
+ }
1326
+ else if (type == TIMER || type == TIMEOFDAY)
1327
+ {
1328
+ t = (long)level;
1329
+ if (t < 0) return 202;
1330
+ }
1331
+
1332
+ // Assign values to control struct
1333
+ control->Link = linkIndex;
1334
+ control->Node = nodeIndex;
1335
+ control->Type = type;
1336
+ control->Status = status;
1337
+ control->Setting = s;
1338
+ control->Time = t;
1339
+ control->Grade = lvl;
1340
+ control->isEnabled = TRUE;
1341
+ return 0;
1342
+ }
1343
+
1344
+
1075
1345
  int getcomment(Network *network, int object, int index, char *comment)
1076
1346
  //----------------------------------------------------------------
1077
1347
  // Input: object = a type of network object
@@ -1154,6 +1424,67 @@ int setcomment(Network *network, int object, int index, const char *newcomment)
1154
1424
  }
1155
1425
  }
1156
1426
 
1427
+ int gettag(Network *network, int object, int index, char *tag)
1428
+ //----------------------------------------------------------------
1429
+ // Input: object = a type of network object
1430
+ // index = index of the specified object
1431
+ // tag = the object's tag string
1432
+ // Output: error code
1433
+ // Purpose: gets the tag string assigned to an object.
1434
+ //----------------------------------------------------------------
1435
+ {
1436
+ char *currenttag;
1437
+
1438
+ // Get pointer to specified object's tag
1439
+ switch (object)
1440
+ {
1441
+ case NODE:
1442
+ if (index < 1 || index > network->Nnodes) return 251;
1443
+ currenttag = network->Node[index].Tag;
1444
+ break;
1445
+ case LINK:
1446
+ if (index < 1 || index > network->Nlinks) return 251;
1447
+ currenttag = network->Link[index].Tag;
1448
+ break;
1449
+ default:
1450
+ strcpy(tag, "");
1451
+ return 251;
1452
+ }
1453
+ // Copy the object's tag to the returned string
1454
+ if (currenttag) strcpy(tag, currenttag);
1455
+ else tag[0] = '\0';
1456
+ return 0;
1457
+ }
1458
+
1459
+ int settag(Network *network, int object, int index, const char *newtag)
1460
+ //----------------------------------------------------------------
1461
+ // Input: object = a type of network object
1462
+ // index = index of the specified object
1463
+ // newtag = new tag string
1464
+ // Output: error code
1465
+ // Purpose: sets the tag string of an object.
1466
+ //----------------------------------------------------------------
1467
+ {
1468
+ char *tag;
1469
+
1470
+ switch (object)
1471
+ {
1472
+ case NODE:
1473
+ if (index < 1 || index > network->Nnodes) return 251;
1474
+ tag = network->Node[index].Tag;
1475
+ network->Node[index].Tag = xstrcpy(&tag, newtag, MAXMSG);
1476
+ return 0;
1477
+
1478
+ case LINK:
1479
+ if (index < 1 || index > network->Nlinks) return 251;
1480
+ tag = network->Link[index].Tag;
1481
+ network->Link[index].Tag = xstrcpy(&tag, newtag, MAXMSG);
1482
+ return 0;
1483
+
1484
+ default: return 251;
1485
+ }
1486
+ }
1487
+
1157
1488
  int namevalid(const char *name)
1158
1489
  //----------------------------------------------------------------
1159
1490
  // Input: name = name used to ID an object
@@ -1219,10 +1550,10 @@ char *xstrcpy(char **s1, const char *s2, const size_t n)
1219
1550
  // s1 points to a valid memory location or is NULL. E.g.,
1220
1551
  // the following code will likely cause a segment fault:
1221
1552
  // char *s;
1222
- // s = xstrcpy(s, "Some text");
1553
+ // s = xstrcpy(&s, "Some text");
1223
1554
  // while this would work correctly:
1224
1555
  // char *s = NULL;
1225
- // s = xstrcpy(s, "Some text");
1556
+ // s = xstrcpy(&s, "Some text");
1226
1557
  //----------------------------------------------------------------
1227
1558
  {
1228
1559
  size_t n1 = 0, n2 = 0;
@@ -1244,7 +1575,7 @@ char *xstrcpy(char **s1, const char *s2, const size_t n)
1244
1575
  if (n2 > n1) *s1 = realloc(*s1, (n2 + 1) * sizeof(char));
1245
1576
 
1246
1577
  // Copy the source string into the destination string
1247
- strncpy(*s1, s2, n2+1);
1578
+ if (*s1) strncpy(*s1, s2, n2+1);
1248
1579
  return *s1;
1249
1580
  }
1250
1581
 
@@ -1283,6 +1614,7 @@ double interp(int n, double x[], double y[], double xx)
1283
1614
  int k, m;
1284
1615
  double dx, dy;
1285
1616
 
1617
+ if (n == 0) return 0.0;
1286
1618
  m = n - 1; // Highest data index
1287
1619
  if (xx <= x[0]) return (y[0]); // xx off low end of curve
1288
1620
  for (k = 1; k <= m; k++) // Bracket xx on curve