From 880bdfffba8cdc1c892ceb0a713f98f98d4617ce Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Fri, 12 Apr 2019 18:00:36 -0400 Subject: [PATCH 01/36] Work in progress compiles with warnings, definitely not working --- CMakeLists.txt | 4 +- src/demand.c | 72 +++++++++++++++++++++++++++++++++ src/demand.h | 42 ++++++++++++++++++++ src/types.h | 106 +++++++++++++++++++++++++------------------------ 4 files changed, 171 insertions(+), 53 deletions(-) create mode 100644 src/demand.c create mode 100644 src/demand.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 93fbda1..6892dcc 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,8 +83,8 @@ ENDIF (MSVC) # configure file groups -file(GLOB EPANET_SOURCES RELATIVE ${PROJECT_SOURCE_DIR} src/*.c) -file(GLOB EPANET_LIB_ALL RELATIVE ${PROJECT_SOURCE_DIR} src/*) +file(GLOB EPANET_SOURCES RELATIVE ${PROJECT_SOURCE_DIR} src/*.c src/util/list.c) +file(GLOB EPANET_LIB_ALL RELATIVE ${PROJECT_SOURCE_DIR} src/* src/util/list.*) # exclude epanet python API from the default build list(REMOVE_ITEM EPANET_LIB_ALL "src/epanet_py.c") source_group("Library" FILES ${EPANET_LIB_ALL}) diff --git a/src/demand.c b/src/demand.c new file mode 100644 index 0000000..dc91221 --- /dev/null +++ b/src/demand.c @@ -0,0 +1,72 @@ +/* + ****************************************************************************** + Project: OWA EPANET + Version: 2.2 + Module: demand.c + Description: demand pattern list + Authors: see AUTHORS + Copyright: see AUTHORS + License: see LICENSE + Last Updated: 04/12/2019 + ****************************************************************************** +*/ + +#include +#include + +#include "demand.h" + + +typedef struct demand_data_s +{ + double base_demand; + int pattern_index; + char *category_name; +} demand_data_t; + + +demand_data_t *create_demand_data(double base_demand, int pat_index, char *cat_name) +{ + demand_data_t *demand_data = (demand_data_t *)malloc(sizeof(demand_data_t)); + + demand_data->base_demand = base_demand; + demand_data->pattern_index = pat_index; + + if (cat_name) + demand_data->category_name = strdup(cat_name); + else + demand_data->category_name = NULL; + + return demand_data; +} + +void delete_demand_data(void *data) +{ + demand_data_t *demand_data = *(demand_data_t **)data; + + if (demand_data->category_name) + free(demand_data->category_name); + + free(demand_data); +} + +demand_data_t *get_demand_data(list_node_t *lnode) +{ + return *(demand_data_t **)get_data(lnode); +} + + +double get_base_demand(demand_data_t *data) +{ + return data->base_demand; +} + +int get_pattern_index(demand_data_t *data) +{ + return data->pattern_index; +} + +char *get_category_name(demand_data_t *data) +{ + return data->category_name; +} diff --git a/src/demand.h b/src/demand.h new file mode 100644 index 0000000..e593ed2 --- /dev/null +++ b/src/demand.h @@ -0,0 +1,42 @@ +/* + ****************************************************************************** + Project: OWA EPANET + Version: 2.2 + Module: demand.h + Description: demand pattern list + Authors: see AUTHORS + Copyright: see AUTHORS + License: see LICENSE + Last Updated: 04/12/2019 + ****************************************************************************** +*/ + +#ifndef DEMAND_H +#define DEMAND_H + + +#include "util/list.h" + + +// Forward declarations +typedef struct demand_data_s demand_data_t; + +// demand list gets declared in types.h typedef struct Snode +extern list_t *p_demand_list; + + +demand_data_t *create_demand_data(double base_demand, int pat_index, char *cat_name); + +void delete_demand_data(void *data); + +demand_data_t *get_demand_data(list_node_t *lnode); + + +double get_base_demand(demand_data_t *data); + +int get_pattern_index(demand_data_t *data); + +char *get_category_name(demand_data_t *data); + + +#endif /* DEMAND_H */ diff --git a/src/types.h b/src/types.h index 476afac..01b25af 100755 --- a/src/types.h +++ b/src/types.h @@ -14,15 +14,18 @@ #ifndef TYPES_H #define TYPES_H -#include "hash.h" #include + +#include "hash.h" +#include "util/list.h" + /* ------------------------------------------- Definition of 4-byte integers & reals ------------------------------------------- */ -typedef float REAL4; +typedef float REAL4; typedef int INT4; /* @@ -64,7 +67,7 @@ typedef int INT4; Flow units conversion factors ---------------------------------------------- */ -#define GPMperCFS 448.831 +#define GPMperCFS 448.831 #define AFDperCFS 1.9837 #define MGDperCFS 0.64632 #define IMGDperCFS 0.5382 @@ -91,9 +94,9 @@ typedef int INT4; /* --------------------------------------------------------------------- - Conversion macros to be used in place of functions + Conversion macros to be used in place of functions --------------------------------------------------------------------- -*/ +*/ #define INT(x) ((int)(x)) // integer portion of x #define FRAC(x) ((x)-(int)(x)) // fractional part of x #define ABS(x) (((x)<0) ? -(x) : (x)) // absolute value of x @@ -109,10 +112,10 @@ typedef int INT4; /* ------------------------------------------------------ Macro to evaluate function x with error checking - (Fatal errors are numbered higher than 100) + (Fatal errors are numbered higher than 100) ------------------------------------------------------ */ -#define ERRCODE(x) (errcode = ((errcode>100) ? (errcode) : (x))) +#define ERRCODE(x) (errcode = ((errcode>100) ? (errcode) : (x))) /* ---------------------------------------------- @@ -187,7 +190,7 @@ typedef enum { HILEVEL, // act when grade above set level TIMER, // act when set time reached TIMEOFDAY // act when time of day occurs -} ControlType; +} ControlType; typedef enum { XHEAD, // pump cannot deliver head (closed) @@ -206,12 +209,12 @@ typedef enum { HW, // Hazen-Williams DW, // Darcy-Weisbach CM // Chezy-Manning -} HeadLossType; +} HeadLossType; typedef enum { US, // US SI // SI (metric) -} UnitsType; +} UnitsType; typedef enum { CFS, // cubic feet per second @@ -224,7 +227,7 @@ typedef enum { MLD, // megaliters per day CMH, // cubic meters per hour CMD // cubic meters per day -} FlowUnitsType; +} FlowUnitsType; typedef enum { PSI, // pounds per square inch @@ -236,14 +239,14 @@ typedef enum { LOW, // lower limit HI, // upper limit PREC // precision -} RangeType; +} RangeType; typedef enum { MIX1, // complete mix model MIX2, // 2-compartment model FIFO, // first in, first out model LIFO // last in, first out model -} MixType; +} MixType; typedef enum { SERIES, // point time series @@ -259,7 +262,7 @@ typedef enum { HEAD, // nodal hydraulic head PRESSURE, // nodal pressure QUALITY, // nodal water quality - + LENGTH, // link length DIAM, // link diameter FLOW, // link flow rate @@ -270,7 +273,7 @@ typedef enum { SETTING, // pump/valve setting REACTRATE, // avg. reaction rate in link FRICTION, // link friction factor - + POWER, // pump power output TIME, // simulation time VOLUME, // tank volume @@ -293,7 +296,7 @@ typedef enum { ENERHDR, // energy usage header NODEHDR, // node results header LINKHDR // link results header -} HdrType; +} HdrType; typedef enum { NEGATIVE = -1, // flow in reverse of pre-assigned direction @@ -302,13 +305,13 @@ typedef enum { } FlowDirection; typedef enum { - DDA, // demand driven analysis + DDA, // demand driven analysis PDA // pressure driven analysis } DemandModelType; /* ------------------------------------------------------ - Fundamental Data Structures + Fundamental Data Structures ------------------------------------------------------ */ @@ -370,7 +373,8 @@ typedef struct // Node Object double X; // x-coordinate double Y; // y-coordinate double El; // elevation - Pdemand D; // demand pointer +// Pdemand D; // demand pointer + list_t *D; // pointer to demand list Psource S; // source pointer double C0; // initial quality double Ke; // emitter coeff. @@ -383,7 +387,7 @@ typedef struct // Link Object { char ID[MAXID+1]; // link ID int N1; // start node index - int N2; // end node index + int N2; // end node index double Diam; // diameter double Len; // length double Kc; // roughness @@ -510,7 +514,7 @@ typedef struct s_ActionItem // Action List Item { int ruleIndex; // index of rule action belongs to Saction *action; // an action clause - struct s_ActionItem *next; // next action on the list + struct s_ActionItem *next; // next action on the list } SactionList; typedef struct // Mass Balance Components @@ -532,15 +536,15 @@ typedef struct // Mass Balance Components // Input File Parser Wrapper typedef struct { FILE *InFile; // Input file handle - + char DefPatID[MAXID + 1], // Default demand pattern ID InpFname[MAXFNAME + 1], // Input file name *Tok[MAXTOKS], // Array of token strings Comment[MAXMSG + 1], // Comment text LineComment[MAXMSG + 1]; // Full line comment - - int + + int MaxNodes, // Node count from input file */ MaxLinks, // Link count " " " MaxJuncs, // Junction count " " " @@ -559,7 +563,7 @@ typedef struct { Flowflag, // Flow units flag Pressflag, // Pressure units flag DefPat; // Default demand pattern - + Spattern *PrevPat; // Previous pattern processed Scurve *PrevCurve; // Previous curve processed double *X; // Temporary array for curve data @@ -590,7 +594,7 @@ typedef struct { typedef struct { FILE *RptFile; // Report file handle - + int Nperiods, // Number of reporting periods PageSize, // Lines/page in output report/ @@ -607,13 +611,13 @@ typedef struct { long LineNum, // Current line number PageNum; // Current page number - + char Atime[13], // Clock time (hrs:min:sec) Rpt1Fname[MAXFNAME+1], // Primary report file name Rpt2Fname[MAXFNAME+1], // Secondary report file name DateStamp[26]; // Current date & time - + SField Field[MAXVAR]; // Output reporting fields } Report; @@ -624,19 +628,19 @@ typedef struct { char HydFname[MAXFNAME+1], // Hydraulics file name OutFname[MAXFNAME+1]; // Binary output file name - + int Outflag, // Output file flag Hydflag, // Hydraulics flag SaveHflag, // Hydraulic results saved flag SaveQflag, // Quality results saved flag Saveflag; // General purpose save flag - - long + + long HydOffset, // Hydraulics file byte offset OutOffset1, // 1st output file byte offset OutOffset2; // 2nd output file byte offset - + FILE *OutFile, // Output file handle *HydFile, // Hydraulics file handle @@ -665,7 +669,7 @@ typedef struct { *Aij, // Non-zero, off-diagonal matrix coeffs. *F, // Right hand side vector *temp; // Array used by linear eqn. solver - + int Ncoeffs, // Number of non-zero matrix coeffs *Order, // Node-to-row of re-ordered matrix @@ -683,7 +687,7 @@ typedef struct { // Hydraulics Solver Wrapper typedef struct { - double + double *NodeHead, // Node hydraulic heads *NodeDemand, // Node demand + emitter flows *DemandFlow, // Demand outflows @@ -711,13 +715,13 @@ typedef struct { Dcost, // Energy demand charge/kw/day Emax, // Peak energy usage RelativeError, // Total flow change / total flow - MaxHeadError, // Max. error for link head loss + MaxHeadError, // Max. error for link head loss MaxFlowChange, // Max. change in link flow RelaxFactor, // Relaxation factor for flow updating *P, // Inverse of head loss derivatives *Y, // Flow correction factors *Xflow; // Inflow - outflow at each node - + int Epat, // Energy cost time pattern DemandModel, // Fixed or pressure dependent @@ -730,10 +734,10 @@ typedef struct { OpenHflag, // Hydraulic system opened flag Haltflag; // Flag to halt simulation - StatusType + StatusType *LinkStatus, // Link status *OldStatus; // Previous link/tank status - + Smatrix smatrix; // Sparse matrix storage } Hydraul; @@ -747,7 +751,7 @@ typedef struct { int Qualflag, // Water quality analysis flag OpenQflag, // Quality system opened flag - Reactflag, // Reaction indicator + Reactflag, // Reaction indicator OutOfMemory, // Out of memory indicator TraceNode, // Source node for flow tracing *SortedNodes; // Topologically sorted node indexes @@ -768,17 +772,17 @@ typedef struct { Bucf, // Bulk reaction units conversion factor Tucf, // Tank reaction units conversion factor BulkOrder, // Bulk flow reaction order - WallOrder, // Pipe wall reaction order - TankOrder, // Tank reaction order - Kbulk, // Global bulk reaction coeff. - Kwall, // Global wall reaction coeff. + WallOrder, // Pipe wall reaction order + TankOrder, // Tank reaction order + Kbulk, // Global bulk reaction coeff. + Kwall, // Global wall reaction coeff. Climit, // Limiting potential quality SourceQual, // External source quality *NodeQual, // Reported node quality state *PipeRateCoeff; // Pipe reaction rate coeffs. struct Mempool - *SegPool; // Memory pool for water quality segments + *SegPool; // Memory pool for water quality segments Pseg FreeSeg, // Pointer to unused segment @@ -808,7 +812,7 @@ typedef struct { Nrules, // Number of control rules Npats, // Number of time patterns Ncurves; // Number of data curves - + Snode *Node; // Node array Slink *Link; // Link array Stank *Tank; // Tank array @@ -836,13 +840,13 @@ typedef struct Project { Rules rules; // Rule-based controls wrapper Hydraul hydraul; // Hydraulics solver wrapper Quality quality; // Water quality solver wrapper - + double Ucf[MAXVAR]; // Unit conversion factors - + int Openflag, // Project open flag Warnflag; // Warning flag - + char Msg[MAXMSG+1], // General-purpose string: errors, messages Title[MAXTITLE][TITLELEN+1], // Project title @@ -850,9 +854,9 @@ typedef struct Project { TmpHydFname[MAXFNAME+1], // Temporary hydraulics file name TmpOutFname[MAXFNAME+1], // Temporary output file name TmpStatFname[MAXFNAME+1]; // Temporary statistic file name - - void (* viewprog) (char *); // Pointer to progress viewing function - + + void (* viewprog) (char *); // Pointer to progress viewing function + } Project, *EN_Project; #endif From f80e74bc5c197157529896775e4238294b2dceab Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Fri, 12 Apr 2019 18:07:32 -0400 Subject: [PATCH 02/36] Update demand.h --- src/demand.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/demand.h b/src/demand.h index e593ed2..73b81c2 100644 --- a/src/demand.h +++ b/src/demand.h @@ -21,8 +21,7 @@ // Forward declarations typedef struct demand_data_s demand_data_t; -// demand list gets declared in types.h typedef struct Snode -extern list_t *p_demand_list; +// demand list gets declared in types.h struct Snode demand_data_t *create_demand_data(double base_demand, int pat_index, char *cat_name); From c659c708173c6e47baf82949920f256706dc370a Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Mon, 15 Apr 2019 13:35:37 -0400 Subject: [PATCH 03/36] Work in progress Implementing demand_list --- src/demand.c | 19 +++++++ src/demand.h | 7 +++ src/input1.c | 44 ++++++++++------ src/input3.c | 135 +++++++++++++++++++++++++++++++----------------- src/util/list.c | 12 +++-- 5 files changed, 150 insertions(+), 67 deletions(-) diff --git a/src/demand.c b/src/demand.c index dc91221..5cba1d9 100644 --- a/src/demand.c +++ b/src/demand.c @@ -50,17 +50,36 @@ void delete_demand_data(void *data) free(demand_data); } +size_t get_demand_data_size(void) +{ + return sizeof(demand_data_t *); +} + demand_data_t *get_demand_data(list_node_t *lnode) { return *(demand_data_t **)get_data(lnode); } +bool convert_units(list_node_t *lnode, double unit_conversion) +{ + demand_data_t *demand_data = get_demand_data(lnode); + double base_demand = get_base_demand(demand_data); + + set_base_demand(demand_data, base_demand/unit_conversion); +} + + double get_base_demand(demand_data_t *data) { return data->base_demand; } +void set_base_demand(demand_data_t *data, double base_demand) +{ + data->base_demand = base_demand; +} + int get_pattern_index(demand_data_t *data) { return data->pattern_index; diff --git a/src/demand.h b/src/demand.h index 73b81c2..bdfd8a2 100644 --- a/src/demand.h +++ b/src/demand.h @@ -28,11 +28,18 @@ demand_data_t *create_demand_data(double base_demand, int pat_index, char *cat_n void delete_demand_data(void *data); +size_t get_demand_data_size(void); + demand_data_t *get_demand_data(list_node_t *lnode); +bool convert_units(list_node_t *lnode, double unit_conversion); + + double get_base_demand(demand_data_t *data); +void set_base_demand(demand_data_t *data, double base_demand); + int get_pattern_index(demand_data_t *data); char *get_category_name(demand_data_t *data); diff --git a/src/input1.c b/src/input1.c index 219caaf..2d80d5b 100644 --- a/src/input1.c +++ b/src/input1.c @@ -23,6 +23,8 @@ Last Updated: 04/03/2019 #include +#include "demand.h" + #include "types.h" #include "funcs.h" #include "hash.h" @@ -220,9 +222,9 @@ void adjustdata(Project *pr) int i; double ucf; // Unit conversion factor - Pdemand demand; // Pointer to demand record + //Pdemand demand; // Pointer to demand record Slink *link; - Snode *node; + //Snode *node; Stank *tank; // Use 1 hr pattern & report time step if none specified @@ -330,16 +332,19 @@ void adjustdata(Project *pr) if (tank->Kb == MISSING) tank->Kb = qual->Kbulk; } - // Use default pattern if none assigned to a demand - parser->DefPat = findpattern(net, parser->DefPatID); - if (parser->DefPat > 0) for (i = 1; i <= net->Nnodes; i++) - { - node = &net->Node[i]; - for (demand = node->D; demand != NULL; demand = demand->next) - { - if (demand->Pat == 0) demand->Pat = parser->DefPat; - } - } + // It is expensive to iterate over every demand at every node. + // cheaper to apply default pattern when creating the demand data. + +// // Use default pattern if none assigned to a demand +// parser->DefPat = findpattern(net, parser->DefPatID); +// if (parser->DefPat > 0) for (i = 1; i <= net->Nnodes; i++) +// { +// node = &net->Node[i]; +// for (demand = node->D; demand != NULL; demand = demand->next) +// { +// if (demand->Pat == 0) demand->Pat = parser->DefPat; +// } +// } // Remove QUALITY as a reporting variable if no WQ analysis if (qual->Qualflag == NONE) rpt->Field[QUALITY].Enabled = FALSE; @@ -542,7 +547,7 @@ void convertunits(Project *pr) int i, j, k; double ucf; // Unit conversion factor - Pdemand demand; // Pointer to demand record + //Pdemand demand; // Pointer to demand record Snode *node; Stank *tank; Slink *link; @@ -562,11 +567,16 @@ void convertunits(Project *pr) for (i = 1; i <= net->Njuncs; i++) { node = &net->Node[i]; - for (demand = node->D; demand != NULL; demand = demand->next) - { - demand->Base /= pr->Ucf[DEMAND]; - } + list_t *dlist = node->D; + for (list_node_t *lnode = first_list(dlist); done_list(lnode); lnode = next_list(lnode)) + convert_units(lnode, pr->Ucf[DEMAND]); + + // for (demand = node->D; demand != NULL; demand = demand->next) + // { + // demand->Base /= pr->Ucf[DEMAND]; + // } } + hyd->Pmin /= pr->Ucf[PRESSURE]; hyd->Preq /= pr->Ucf[PRESSURE]; diff --git a/src/input3.c b/src/input3.c index 61324a3..617f464 100644 --- a/src/input3.c +++ b/src/input3.c @@ -23,6 +23,7 @@ Last Updated: 04/03/2019 #include +#include "demand.h" #include "types.h" #include "funcs.h" #include "hash.h" @@ -80,12 +81,15 @@ int juncdata(Project *pr) Parser *parser = &pr->parser; Hydraul *hyd = &pr->hydraul; - int p = 0; // time pattern index - int n; // number of tokens - int njuncs; // number of network junction nodes - double el, // elevation - y = 0.0; // base demand - Pdemand demand; // demand record + int p = 0; // time pattern index + int n; // number of tokens + int njuncs; // number of network junction nodes + double el, // elevation + y = 0.0; // base demand + + list_t *demand_list = NULL; // demand list + + Snode *node; // Add new junction to data base @@ -118,14 +122,26 @@ int juncdata(Project *pr) node->Type = JUNCTION; node->Comment = xstrcpy(&node->Comment, parser->Comment, MAXMSG); - // create a demand record, even if no demand is specified here. - demand = (struct Sdemand *) malloc(sizeof(struct Sdemand)); - if (demand == NULL) return 101; - demand->Base = y; - demand->Pat = p; - demand->Name = NULL; - demand->next = NULL; - node->D = demand; + // create demand data only if a demand has been specified + if (y != 0.0) { + demand_data_t *demand_data; + + demand_list = create_list(get_demand_data_size(), delete_demand_data); + if (demand_list == NULL) return 101; + + // apply the default demand pattern and append the data + if (p == 0) p = findpattern(net, parser->DefPatID); + demand_data = create_demand_data(y, p, NULL); + if (demand_data == NULL) return 101; + + append_list(demand_list, &demand_data); + } + //demand->Base = y; + //demand->Pat = p; + //demand->Name = NULL; + //demand->next = NULL; + node->D = demand_list; + hyd->NodeDemand[njuncs] = y; return 0; } @@ -709,8 +725,12 @@ int demanddata(Project *pr) int j, n, p = 0; double y; - Pdemand demand; - Pdemand cur_demand; + + list_t *demand_list = NULL; + demand_data_t *demand_data = NULL; + + //Pdemand demand; + //Pdemand cur_demand; // Extract data from tokens n = parser->Ntokens; @@ -734,38 +754,59 @@ int demanddata(Project *pr) if (p == 0) return setError(parser, 2, 205); } - // Replace any demand entered in [JUNCTIONS] section - demand = net->Node[j].D; - if (hyd->NodeDemand[j] != MISSING) - { - // First category encountered will overwrite "dummy" demand category - // with what is specified in this section - demand->Base = y; - demand->Pat = p; - if (parser->Comment[0]) - { - demand->Name = xstrcpy(&demand->Name, parser->Comment, MAXID); - } - hyd->NodeDemand[j] = MISSING; // marker - next iteration will append a new category. - } + + // if no demands were specified in [JUNCTIONS] create the list here + demand_list = net->Node[j].D; + if (demand_list == NULL) { + demand_list = create_list(get_demand_data_size(), delete_demand_data); + if (demand_list == NULL) return 101; + net->Node[j].D = demand_list; + } + + // else delete the demand data in [JUNCTIONS] section + else if (size_list(demand_list) == 1) { + list_node_t *lnode = head_list(demand_list, true); + delete_node(demand_list, lnode); + } - // Otherwise add new demand to junction - else - { - cur_demand = net->Node[j].D; - while (cur_demand->next != NULL) cur_demand = cur_demand->next; - demand = (struct Sdemand *)malloc(sizeof(struct Sdemand)); - if (demand == NULL) return 101; - demand->Base = y; - demand->Pat = p; - demand->Name = NULL; - if (parser->Comment[0]) - { - demand->Name = xstrcpy(&demand->Name, parser->Comment, MAXID); - } - demand->next = NULL; - cur_demand->next = demand; - } + // apply the default demand pattern and append the data + if (p == 0) p = findpattern(net, parser->DefPatID); + demand_data = create_demand_data(y, p, parser->Comment); + if (demand_data == NULL) return 101; + + append_list(demand_list, &demand_data); + + + // //if (hyd->NodeDemand[j] != MISSING) + // { + // // First category encountered will overwrite "dummy" demand category + // // with what is specified in this section + // demand->Base = y; + // demand->Pat = p; + // if (parser->Comment[0]) + // { + // demand->Name = xstrcpy(&demand->Name, parser->Comment, MAXID); + // } + // hyd->NodeDemand[j] = MISSING; // marker - next iteration will append a new category. + // } + // + // // Otherwise add new demand to junction + // else + // { + // cur_demand = net->Node[j].D; + // while (cur_demand->next != NULL) cur_demand = cur_demand->next; + // demand = (struct Sdemand *)malloc(sizeof(struct Sdemand)); + // if (demand == NULL) return 101; + // demand->Base = y; + // demand->Pat = p; + // demand->Name = NULL; + // if (parser->Comment[0]) + // { + // demand->Name = xstrcpy(&demand->Name, parser->Comment, MAXID); + // } + // demand->next = NULL; + // cur_demand->next = demand; + // } return 0; } diff --git a/src/util/list.c b/src/util/list.c index d3e41d8..fc2237e 100644 --- a/src/util/list.c +++ b/src/util/list.c @@ -162,7 +162,10 @@ void delete_node(list_t *list, list_node_t *lnode) // list_node_t *first_list(list_t *list) { - return list->head; + if (list) + return list->head; + else + return NULL; } bool done_list(list_node_t *lnode) @@ -171,6 +174,9 @@ bool done_list(list_node_t *lnode) } list_node_t *next_list(list_node_t *lnode) -{ - return lnode->next; +{ + if (lnode) + return lnode->next; + else + return NULL; } From 109276e379d5d26ccc1db4511df9ca818f45f635 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Wed, 17 Apr 2019 17:24:34 -0400 Subject: [PATCH 04/36] Work in progress Implementing generic demand pattern lists. Compiles but does not run. --- src/demand.c | 30 ++++-- src/demand.h | 16 +-- src/epanet.c | 222 ++++++++++++++++++++++++--------------- src/hydraul.c | 13 ++- src/inpfile.c | 28 +++-- src/project.c | 37 +++++-- src/util/list.c | 65 ++++++------ src/util/list.h | 27 ++++- tests/util/test_list.cpp | 11 +- 9 files changed, 277 insertions(+), 172 deletions(-) diff --git a/src/demand.c b/src/demand.c index 5cba1d9..4215a05 100644 --- a/src/demand.c +++ b/src/demand.c @@ -3,7 +3,7 @@ Project: OWA EPANET Version: 2.2 Module: demand.c - Description: demand pattern list + Description: data for demand pattern list Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE @@ -25,12 +25,12 @@ typedef struct demand_data_s } demand_data_t; -demand_data_t *create_demand_data(double base_demand, int pat_index, char *cat_name) +demand_data_t *create_demand_data(double base_demand, int pattern_index, char *category_name) { demand_data_t *demand_data = (demand_data_t *)malloc(sizeof(demand_data_t)); demand_data->base_demand = base_demand; - demand_data->pattern_index = pat_index; + demand_data->pattern_index = pattern_index; if (cat_name) demand_data->category_name = strdup(cat_name); @@ -72,20 +72,30 @@ bool convert_units(list_node_t *lnode, double unit_conversion) double get_base_demand(demand_data_t *data) { - return data->base_demand; + return get_demand_data(lnode)->base_demand; } -void set_base_demand(demand_data_t *data, double base_demand) +void set_base_demand(list_node_t *lnode, double base_demand) { - data->base_demand = base_demand; + get_demand_data(lnode)->base_demand = base_demand; } -int get_pattern_index(demand_data_t *data) +int get_pattern_index(list_node_t *lnode) { - return data->pattern_index; + return get_demand_data(lnode)->pattern_index; } -char *get_category_name(demand_data_t *data) +void set_pattern_index(list_node_t *lnode, int pattern_index) { - return data->category_name; + get_demand_data(lnode)->pattern_index = pattern_index; +} + +char *get_category_name(list_node_t *lnode) +{ + return get_demand_data(lnode)->category_name; +} + +void set_category_name(list_node_t *lnode, char *category_name) +{ + get_demand_data(lnode)->category_name = strdup(category_name); } diff --git a/src/demand.h b/src/demand.h index bdfd8a2..775ed4a 100644 --- a/src/demand.h +++ b/src/demand.h @@ -3,7 +3,7 @@ Project: OWA EPANET Version: 2.2 Module: demand.h - Description: demand pattern list + Description: data for demand pattern list Authors: see AUTHORS Copyright: see AUTHORS License: see LICENSE @@ -30,19 +30,21 @@ void delete_demand_data(void *data); size_t get_demand_data_size(void); -demand_data_t *get_demand_data(list_node_t *lnode); - bool convert_units(list_node_t *lnode, double unit_conversion); -double get_base_demand(demand_data_t *data); +double get_base_demand(list_node_t *lnode); +void set_base_demand(list_node_t *lnode, double base_demand); -void set_base_demand(demand_data_t *data, double base_demand); +int get_pattern_index(list_node_t *lnode); +void set_pattern_index(list_node_t *lnode, int pattern_index); -int get_pattern_index(demand_data_t *data); +char *get_category_name(list_node_t *lnode); +void set_category_name(list_node_t *lnode, char *category_name); -char *get_category_name(demand_data_t *data); +// Make this private? +demand_data_t *get_demand_data(list_node_t *lnode); #endif /* DEMAND_H */ diff --git a/src/epanet.c b/src/epanet.c index 6a9c546..4d06e4b 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -31,6 +31,7 @@ #include "enumstxt.h" #include "util/cstr_helper.h" +#include "demand.h" #ifdef _WIN32 #define snprintf _snprintf @@ -1724,7 +1725,7 @@ int DLLEXPORT EN_addnode(EN_Project p, char *id, int nodeType) int i, nIdx; int index; int size; - struct Sdemand *demand; +// struct Sdemand *demand; Stank *tank; Snode *node; Scontrol *control; @@ -1757,12 +1758,12 @@ int DLLEXPORT EN_addnode(EN_Project p, char *id, int nodeType) nIdx = net->Njuncs; node = &net->Node[nIdx]; - demand = (struct Sdemand *)malloc(sizeof(struct Sdemand)); - demand->Base = 0.0; - demand->Pat = 0; - demand->Name = NULL; - demand->next = NULL; - node->D = demand; + //demand = (struct Sdemand *)malloc(sizeof(struct Sdemand)); + //demand->Base = 0.0; + //demand->Pat = 0; + //demand->Name = NULL; + //demand->next = NULL; + node->D = NULL; // shift rest of Node array for (index = net->Nnodes; index >= net->Njuncs; index--) @@ -1862,7 +1863,7 @@ int DLLEXPORT EN_deletenode(EN_Project p, int index, int actionCode) int i, nodeType, tankindex; Snode *node; - Pdemand demand, nextdemand; + list_t *demand; // Cannot modify network structure while solvers are active if (!p->Openflag) return 102; @@ -1896,13 +1897,14 @@ int DLLEXPORT EN_deletenode(EN_Project p, int index, int actionCode) // Free memory allocated to node's demands, WQ source & comment demand = node->D; - while (demand != NULL) - { - nextdemand = demand->next; - free(demand->Name); - free(demand); - demand = nextdemand; - } + delete_list(demand); +// while (demand != NULL) + // { + // nextdemand = demand->next; + // free(demand->Name); + // free(demand); + // demand = nextdemand; + // } free(node->S); free(node->Comment); @@ -2072,7 +2074,7 @@ int DLLEXPORT EN_getnodevalue(EN_Project p, int index, int property, double *val Quality *qual = &p->quality; double v = 0.0; - Pdemand demand; + //Pdemand demand; Psource source; Snode *Node = net->Node; @@ -2102,10 +2104,14 @@ int DLLEXPORT EN_getnodevalue(EN_Project p, int index, int property, double *val // NOTE: primary demand category is last on demand list if (index <= nJuncs) { - for (demand = Node[index].D; demand != NULL; demand = demand->next) - { - v = (demand->Base); - } + list_t *demand = Node[index].D; + if (demand) + v = get_base_demand(tail_list(demand)); + + //for (demand = Node[index].D; demand != NULL; demand = demand->next) + //{ + // v = (demand->Base); + //} } v *= Ucf[FLOW]; break; @@ -2115,10 +2121,13 @@ int DLLEXPORT EN_getnodevalue(EN_Project p, int index, int property, double *val // NOTE: primary demand category is last on demand list if (index <= nJuncs) { - for (demand = Node[index].D; demand != NULL; demand = demand->next) - { - v = (double)(demand->Pat); - } + list_t *demand = Node[index].D; + if (demand) + v = get_pattern_index(tail_list(demand)); + //for (demand = Node[index].D; demand != NULL; demand = demand->next) + //{ + // v = (double)(demand->Pat); + //} } else v = (double)(Tank[index - nJuncs].Pat); break; @@ -2273,7 +2282,7 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int property, double valu double *Ucf = p->Ucf; int i, j, n; - Pdemand demand; +// Pdemand demand; Psource source; double hTmp; @@ -2299,10 +2308,13 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int property, double valu // NOTE: primary demand category is last on demand list if (index <= nJuncs) { - for (demand = Node[index].D; demand != NULL; demand = demand->next) - { - if (demand->next == NULL) demand->Base = value / Ucf[FLOW]; - } + list_t *demand = Node[index].D; + if (demand) + set_base_demand(tail_list(demand), value / Ucf[FLOW]); +// for (demand = Node[index].D; demand != NULL; demand = demand->next) +// { +// if (demand->next == NULL) demand->Base = value / Ucf[FLOW]; +// } } break; @@ -2312,10 +2324,13 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int property, double valu if (j < 0 || j > nPats) return 205; if (index <= nJuncs) { - for (demand = Node[index].D; demand != NULL; demand = demand->next) - { - if (demand->next == NULL) demand->Pat = j; - } + list_t *demand = Node[index].D; + if (demand) + set_pattern_index(tail_list(demand), j); + //for (demand = Node[index].D; demand != NULL; demand = demand->next) + //{ + // if (demand->next == NULL) demand->Pat = j; + //} } else Tank[index - nJuncs].Pat = j; break; @@ -2512,7 +2527,7 @@ int DLLEXPORT EN_setjuncdata(EN_Project p, int index, double elev, int i, patIndex = 0; Snode *Node = net->Node; - Pdemand demand; + //Pdemand demand; // Check that junction exists if (!p->Openflag) return 102; @@ -2534,14 +2549,25 @@ int DLLEXPORT EN_setjuncdata(EN_Project p, int index, double elev, // Assign values to junction's parameters Node[index].El = elev / p->Ucf[ELEV]; - for (demand = Node[index].D; demand != NULL; demand = demand->next) - { - if (demand->next == NULL) - { - demand->Base = dmnd / p->Ucf[FLOW]; - demand->Pat = patIndex; - } - } + + list_t *demand_list = Node[index].D; + if (!demand_list) { + demand_list = create_list(get_demand_data_size(), delete_demand_data); + if (!demand_list) return 101; + } + demand_data_t *demand_data = create_demand_data(dmnd / p->Ucf[FLOW], patIndex, NULL); + if (!demand_data) return 101; + + append_list(demand_list, &demand_data); + + //for (demand = Node[index].D; demand != NULL; demand = demand->next) + //{ + // if (demand->next == NULL) + // { + // demand->Base = dmnd / p->Ucf[FLOW]; + // demand->Pat = patIndex; + // } + //} return 0; } @@ -2722,16 +2748,20 @@ int DLLEXPORT EN_getnumdemands(EN_Project p, int nodeIndex, int *numDemands) **---------------------------------------------------------------- */ { - Pdemand d; - int n = 0; + //Pdemand d; + //int n = 0; // Check for valid arguments if (!p->Openflag) return 102; if (nodeIndex <= 0 || nodeIndex > p->network.Nnodes) return 203; // Count the number of demand categories - for (d = p->network.Node[nodeIndex].D; d != NULL; d = d->next) n++; - *numDemands = n; + list_t *demand_list = p->network.Node[nodeIndex].D; + if (!demand_list) + *numDemands = 0; + else + *numDemands = size_list(demand_list); + return 0; } @@ -2746,8 +2776,8 @@ int DLLEXPORT EN_getbasedemand(EN_Project p, int nodeIndex, int demandIndex, **---------------------------------------------------------------- */ { - Pdemand d; - int n = 1; + //Pdemand d; + //int n; //= 1; // Check for valid arguments if (!p->Openflag) return 102; @@ -2756,10 +2786,13 @@ int DLLEXPORT EN_getbasedemand(EN_Project p, int nodeIndex, int demandIndex, // Retrieve demand for specified category if (nodeIndex <= p->network.Njuncs) { - for (d = p->network.Node[nodeIndex].D; n < demandIndex && d->next != NULL; - d = d->next) n++; - if (n != demandIndex) return 253; - *baseDemand = (double)(d->Base * p->Ucf[FLOW]); + // Locate demand category record and assign demandName to it + list_t *dlist = p->network.Node[nodeIndex].D; + list_node_t *lnode = get_nth_list(dlist, demandIndex); + if (!lnode) + return 253; + else + *baseDemand = get_base_demand(lnode) * p->Ucf[FLOW]; } else *baseDemand = (double)(0.0); return 0; @@ -2777,9 +2810,6 @@ int DLLEXPORT EN_setbasedemand(EN_Project p, int nodeIndex, int demandIndex, **---------------------------------------------------------------- */ { - Pdemand d; - int n = 1; - // Check for valid arguments if (!p->Openflag) return 102; if (nodeIndex <= 0 || nodeIndex > p->network.Nnodes) return 203; @@ -2787,10 +2817,13 @@ int DLLEXPORT EN_setbasedemand(EN_Project p, int nodeIndex, int demandIndex, // Set baseline demand for specified category if (nodeIndex <= p->network.Njuncs) { - for (d = p->network.Node[nodeIndex].D; n < demandIndex && d->next != NULL; - d = d->next) n++; - if (n != demandIndex) return 253; - d->Base = baseDemand / p->Ucf[FLOW]; + // Locate demand category record and assign demandName to it + list_t *dlist = p->network.Node[nodeIndex].D; + list_node_t *lnode = get_nth_list(dlist, demandIndex); + if (!lnode) + return 253; + else + set_base_demand(lnode, baseDemand / p->Ucf[FLOW]); } return 0; } @@ -2806,8 +2839,8 @@ int DLLEXPORT EN_getdemandname(EN_Project p, int nodeIndex, int demandIndex, **---------------------------------------------------------------- */ { - Pdemand d; - int n = 1; + //Pdemand d; + //int n = 1; strcpy(demandName, ""); @@ -2816,12 +2849,19 @@ int DLLEXPORT EN_getdemandname(EN_Project p, int nodeIndex, int demandIndex, if (nodeIndex <= 0 || nodeIndex > p->network.Njuncs) return 203; // Locate demand category record and retrieve its name - for (d = p->network.Node[nodeIndex].D; - n < demandIndex && d->next != NULL; d = d->next) n++; - if (n != demandIndex) return 253; + list_t *dlist = p->network.Node[nodeIndex].D; + list_node_t *lnode = get_nth_list(dlist, demandIndex); + if (!lnode) + return 253; + else + demandName = get_category_name(lnode); - if (d->Name) strcpy(demandName, d->Name); - else demandName[0] = '\0'; + //for (d = p->network.Node[nodeIndex].D; + // n < demandIndex && d->next != NULL; d = d->next) n++; + //if (n != demandIndex) return 253; + + //if (d->Name) strcpy(demandName, d->Name); + //else demandName[0] = '\0'; return 0; } @@ -2837,8 +2877,8 @@ int DLLEXPORT EN_setdemandname(EN_Project p, int nodeIndex, int demandIndex, **---------------------------------------------------------------- */ { - Pdemand d; - int n = 1; + //Pdemand d; + //int n = 1; // Check for valid arguments if (!p->Openflag) return 102; @@ -2848,10 +2888,13 @@ int DLLEXPORT EN_setdemandname(EN_Project p, int nodeIndex, int demandIndex, if (strlen(demandName) > MAXID) return 250; // Locate demand category record and assign demandName to it - for (d = p->network.Node[nodeIndex].D; - n < demandIndex && d->next != NULL; d = d->next) n++; - if (n != demandIndex) return 253; - d->Name = xstrcpy(&d->Name, demandName, MAXID); + list_t *dlist = p->network.Node[nodeIndex].D; + list_node_t *lnode = get_nth_list(dlist, demandIndex); + if (!lnode) + return 253; + else + set_category_name(lnode, demandName); + return 0; } @@ -2867,16 +2910,21 @@ int DLLEXPORT EN_getdemandpattern(EN_Project p, int nodeIndex, int demandIndex, **---------------------------------------------------------------- */ { - Pdemand d; - int n = 1; + //Pdemand d; + //int n = 1; // Check for valid arguments if (!p->Openflag) return 102; if (nodeIndex <= 0 || nodeIndex > p->network.Nnodes) return 203; - for (d = p->network.Node[nodeIndex].D; - n < demandIndex && d->next != NULL; d = d->next) n++; - if (n != demandIndex) return 253; - *patIndex = d->Pat; + + // Locate demand category record and assign demandName to it + list_t *dlist = p->network.Node[nodeIndex].D; + list_node_t *lnode = get_nth_list(dlist, demandIndex); + if (!lnode) + return 253; + else + *patIndex = get_pattern_index(lnode); + return 0; } @@ -2894,8 +2942,8 @@ int DLLEXPORT EN_setdemandpattern(EN_Project p, int nodeIndex, int demandIndex, { Network *net = &p->network; - Pdemand d; - int n = 1; + //Pdemand d; + //int n = 1; // Check for valid arguments if (!p->Openflag) return 102; @@ -2903,12 +2951,14 @@ int DLLEXPORT EN_setdemandpattern(EN_Project p, int nodeIndex, int demandIndex, if (patIndex <= 0 || patIndex > net->Npats) return 205; // Locate demand category record and assign time pattern to it - if (nodeIndex <= net->Njuncs) - { - for (d = net->Node[nodeIndex].D; - n < demandIndex && d->next != NULL; d = d->next) n++; - if (n != demandIndex) return 253; - d->Pat = patIndex; + if (nodeIndex <= net->Njuncs) { + + list_t *dlist = p->network.Node[nodeIndex].D; + list_node_t *lnode = get_nth_list(dlist, demandIndex); + if (!lnode) + return 253; + else + set_pattern_index(lnode, patIndex); } return 0; } diff --git a/src/hydraul.c b/src/hydraul.c index 1e3532e..ac3357a 100755 --- a/src/hydraul.c +++ b/src/hydraul.c @@ -27,6 +27,9 @@ #include "funcs.h" #include "text.h" +#include "demand.h" + + const double QZERO = 1.e-6; // Equivalent to zero flow in cfs // Imported functions @@ -553,7 +556,7 @@ void demands(Project *pr) int i ,j, n; long k, p; double djunc, sum; - Pdemand demand; +// Pdemand demand; // Determine total elapsed number of pattern periods p = (time->Htime + time->Pstart) / time->Pstep; @@ -563,12 +566,14 @@ void demands(Project *pr) for (i = 1; i <= net->Njuncs; i++) { sum = 0.0; - for (demand = net->Node[i].D; demand != NULL; demand = demand->next) + list_t *dlist = net->Node[i].D; + list_node_t *lnode; + for (lnode = first_list(dlist); done_list(lnode); lnode = next_list(lnode)) { // pattern period (k) = (elapsed periods) modulus (periods per pattern) - j = demand->Pat; + j = get_pattern_index(lnode); k = p % (long) net->Pattern[j].Length; - djunc = (demand->Base) * net->Pattern[j].F[k] * hyd->Dmult; + djunc = (get_base_demand(lnode)) * net->Pattern[j].F[k] * hyd->Dmult; if (djunc > 0.0) hyd->Dsystem += djunc; sum += djunc; } diff --git a/src/inpfile.c b/src/inpfile.c index 946f364..53aee71 100644 --- a/src/inpfile.c +++ b/src/inpfile.c @@ -28,6 +28,8 @@ Last Updated: 04/03/2019 #include "hash.h" #include "text.h" +#include "demand.h" + // Defined in enumstxt.h in EPANET.C extern char *LinkTxt[]; extern char *FormTxt[]; @@ -137,7 +139,7 @@ int saveinpfile(Project *pr, const char *fname) int i, j, n; double d, kc, ke, km, ucf; char s[MAXLINE + 1], s1[MAXLINE + 1], s2[MAXLINE + 1]; - Pdemand demand; + //Pdemand demand; Psource source; FILE *f; Slink *link; @@ -329,17 +331,23 @@ int saveinpfile(Project *pr, const char *fname) fprintf(f, "\n\n"); fprintf(f, s_DEMANDS); ucf = pr->Ucf[DEMAND]; - for (i = 1; i <= net->Njuncs; i++) + + list_t *dlist; + list_node_t *lnode; + + for (i = 1; i <= net->Njuncs; i++) { node = &net->Node[i]; - for (demand = node->D; demand != NULL; demand = demand->next) - { - sprintf(s, " %-31s %14.6f", node->ID, ucf * demand->Base); - if ((j = demand->Pat) > 0) sprintf(s1, " %-31s", net->Pattern[j].ID); - else strcpy(s1, " "); - fprintf(f, "\n%s %-31s", s, s1); - if (demand->Name) fprintf(f, " ;%s", demand->Name); - } + if (dlist = node->D) { + for (lnode = first_list(dlist); done_list(lnode); lnode = next_list(lnode)) { + + sprintf(s, " %-31s %14.6f", node->ID, ucf * get_base_demand(lnode)); + if ((j = get_pattern_index(lnode)) > 0) sprintf(s1, " %-31s", net->Pattern[j].ID); + else strcpy(s1, " "); + fprintf(f, "\n%s %-31s", s, s1); + if (get_category_name(lnode)) fprintf(f, " ;%s", get_category_name(lnode)); + } + } } // Write [EMITTERS] section diff --git a/src/project.c b/src/project.c index f340e8a..9324bea 100644 --- a/src/project.c +++ b/src/project.c @@ -29,6 +29,8 @@ #include "types.h" #include "funcs.h" +#include "demand.h" + int openfiles(Project *pr, const char *f1, const char *f2, const char *f3) /*---------------------------------------------------------------- ** Input: f1 = pointer to name of input file @@ -385,7 +387,7 @@ void freedata(Project *pr) */ { int j; - Pdemand demand, nextdemand; + //Pdemand demand, nextdemand; // Free memory for computed results free(pr->hydraul.NodeDemand); @@ -404,14 +406,15 @@ void freedata(Project *pr) for (j = 1; j <= pr->parser.MaxNodes; j++) { // Free memory used for demand category list - demand = pr->network.Node[j].D; - while (demand != NULL) + list_t *demand = pr->network.Node[j].D; + delete_list(demand); + /*while (demand != NULL) { nextdemand = demand->next; free(demand->Name); free(demand); demand = nextdemand; - } + }*/ // Free memory used for WQ source data free(pr->network.Node[j].S); free(pr->network.Node[j].Comment); @@ -788,10 +791,20 @@ void adjustpattern(int *pat, int index) **---------------------------------------------------------------- */ { - if (*pat == index) *pat = 0; - else if (*pat > index) (*pat)--; + if (*pat == index) *pat = 0; + else if (*pat > index) (*pat)--; } + +void _adjustpattern(list_node_t *lnode, int index) +{ + int pat = get_pattern_index(lnode); + + if (pat == index) set_pattern_index(lnode, 0); + else if (pat > index) set_pattern_index(lnode, pat--); +} + + void adjustpatterns(Network *network, int index) /*---------------------------------------------------------------- ** Input: index = index of time pattern being deleted @@ -801,17 +814,19 @@ void adjustpatterns(Network *network, int index) */ { int j; - Pdemand demand; + //Pdemand demand; Psource source; // Adjust patterns used by junctions for (j = 1; j <= network->Njuncs; j++) { // Adjust demand patterns - for (demand = network->Node[j].D; demand != NULL; demand = demand->next) - { - adjustpattern(&demand->Pat, index); - } + list_t *dlist = network->Node[j].D; + list_node_t *lnode; + + for (lnode = first_list(dlist); done_list(lnode); lnode = next_list(lnode)) + _adjustpattern(lnode, index); + // Adjust WQ source patterns source = network->Node[j].S; if (source) adjustpattern(&source->Pat, index); diff --git a/src/util/list.c b/src/util/list.c index fc2237e..c74e2c2 100644 --- a/src/util/list.c +++ b/src/util/list.c @@ -108,8 +108,9 @@ void for_each_list(list_t *list, listIterator iterator) list_node_t *node = list->head; bool result = true; - while(node != NULL && result) { - result = iterator(node); + + while(node != NULL && result) { + result = (iterator); node = node->next; } } @@ -120,14 +121,17 @@ list_node_t *head_list(list_t *list, bool removeFromList) // { assert(list->head != NULL); - - list_node_t *node = list->head; - if(removeFromList) { - // Disconnecting head node - list->head = node->next; - list->logicalLength--; + + if (list) { + list_node_t *node = list->head; + if (removeFromList) { + // Disconnecting head node + list->head = node->next; + list->logicalLength--; + } + return node; } - return node; + return NULL; } list_node_t *tail_list(list_t *list) @@ -136,6 +140,18 @@ list_node_t *tail_list(list_t *list) return list->tail; } +list_node_t *get_nth_list(list_t *list, int index) +{ + int n; + list_node_t *lnode; + + for (n = 1, lnode = first_list(list); n < index && done_list(lnode); n++, lnode = next_list(lnode)); + if (n != index) + return NULL; + else + return lnode; +} + int size_list(list_t *list) { return list->logicalLength; @@ -146,6 +162,11 @@ void *get_data(list_node_t *lnode) return lnode->data; } +list_node_t *get_next(list_node_t *lnode) +{ + return lnode->next; +} + void delete_node(list_t *list, list_node_t *lnode) { if (list->freeFn) @@ -154,29 +175,3 @@ void delete_node(list_t *list, list_node_t *lnode) free(lnode->data); free(lnode); } - -// -// Iterator first/done/next operations provide containment for list abstraction -// http://www.cs.yale.edu/homes/aspnes/pinewiki/C(2f)Iterators.html -// Accessed on April 11, 2019 -// -list_node_t *first_list(list_t *list) -{ - if (list) - return list->head; - else - return NULL; -} - -bool done_list(list_node_t *lnode) -{ - return lnode != NULL; -} - -list_node_t *next_list(list_node_t *lnode) -{ - if (lnode) - return lnode->next; - else - return NULL; -} diff --git a/src/util/list.h b/src/util/list.h index 090fa4a..e2e9185 100644 --- a/src/util/list.h +++ b/src/util/list.h @@ -19,6 +19,7 @@ #include + #if defined(__cplusplus) extern "C" { #endif @@ -28,8 +29,8 @@ extern "C" { typedef struct list_node_s list_node_t; typedef struct list_s list_t; -typedef void(*freeFunction)(void *); -typedef bool(*listIterator)(list_node_t *); +typedef void (*freeFunction) (void *); +typedef bool (*listIterator) (list_node_t *); /** @@ -65,6 +66,11 @@ int size_list(list_t *list); */ void *get_data(list_node_t *lnode); +/** +@brief Returns next list node. +*/ +list_node_t *get_next(list_node_t *lnode); + /** @brief Frees memory associated with a list node. */ @@ -87,21 +93,32 @@ list_node_t *head_list(list_t *list, bool removeFromList); */ list_node_t *tail_list(list_t *list); +/** +@brief Returns nth node of the list or NULL. +*/ +list_node_t *get_nth_list(list_t *list, int index); + + +// +// Iterator first/done/next operations +// http://www.cs.yale.edu/homes/aspnes/pinewiki/C(2f)Iterators.html +// Accessed on April 11, 2019 +// /** @brief Returns list head node. */ -list_node_t *first_list(list_t *list); +static inline list_node_t *first_list(list_t *list) { return head_list(list, false); } /** @brief Returns true if end of list false otherwise. */ -bool done_list(list_node_t *lnode); +static inline bool done_list(list_node_t *lnode) { return lnode != NULL; } /** @brief Returns next node in the list. */ -list_node_t *next_list(list_node_t *lnode); +static inline list_node_t *next_list(list_node_t *lnode) { return get_next(lnode); } #if defined(__cplusplus) diff --git a/tests/util/test_list.cpp b/tests/util/test_list.cpp index 7844e6e..787c1ed 100644 --- a/tests/util/test_list.cpp +++ b/tests/util/test_list.cpp @@ -63,8 +63,9 @@ BOOST_AUTO_TEST_CASE(test_int_list){ append_list(list, &i); } BOOST_CHECK(size_list(list) == 10); - - for_each_list(list, iterate_int); + + listIterator iterator = (listIterator)iterate_int; + for_each_list(list, iterator); delete_list(list); } @@ -111,7 +112,8 @@ BOOST_FIXTURE_TEST_CASE(test_string_list, FixtureStrings) { BOOST_CHECK(size_list(list) == 5); - for_each_list(list, iterate_string); + listIterator iterator = (listIterator)iterate_string; + for_each_list(list, iterator); } @@ -196,7 +198,8 @@ BOOST_AUTO_TEST_CASE(test_struct_list){ BOOST_CHECK(size_list(list) == 3); - for_each_list(list, iterate_test_data); + listIterator iterator = (listIterator)iterate_test_data; + for_each_list(list, iterator); list_node_t *lnode; From 3cc9c95d3f037a891c556b816e33e9921f734f5d Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Wed, 17 Apr 2019 17:25:09 -0400 Subject: [PATCH 05/36] Update demand.c Work in progress --- src/demand.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/demand.c b/src/demand.c index 4215a05..a93b9e4 100644 --- a/src/demand.c +++ b/src/demand.c @@ -32,10 +32,10 @@ demand_data_t *create_demand_data(double base_demand, int pattern_index, char *c demand_data->base_demand = base_demand; demand_data->pattern_index = pattern_index; - if (cat_name) - demand_data->category_name = strdup(cat_name); + if (category_name) + demand_data->category_name = strdup(category_name); else - demand_data->category_name = NULL; + demand_data->category_name[0] = '\0'; return demand_data; } @@ -63,14 +63,14 @@ demand_data_t *get_demand_data(list_node_t *lnode) bool convert_units(list_node_t *lnode, double unit_conversion) { - demand_data_t *demand_data = get_demand_data(lnode); - double base_demand = get_base_demand(demand_data); + double base_demand = get_base_demand(lnode); - set_base_demand(demand_data, base_demand/unit_conversion); + set_base_demand(lnode, base_demand/unit_conversion); + return true; } -double get_base_demand(demand_data_t *data) +double get_base_demand(list_node_t *lnode) { return get_demand_data(lnode)->base_demand; } From 584233e5e88bb625aa80a68e3c0fa13bfb82d3d2 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Thu, 18 Apr 2019 09:54:56 -0400 Subject: [PATCH 06/36] Create test_demand_data.cpp --- tests/test_demand_data.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 tests/test_demand_data.cpp diff --git a/tests/test_demand_data.cpp b/tests/test_demand_data.cpp new file mode 100644 index 0000000..0700476 --- /dev/null +++ b/tests/test_demand_data.cpp @@ -0,0 +1,25 @@ +/* + ****************************************************************************** + Project: OWA EPANET + Version: 2.2 + Module: /test_demand_data.cpp + Description: tests demand data list node struct + Authors: see AUTHORS + Copyright: see AUTHORS + License: see LICENSE + Last Updated: 04/18/2019 + ****************************************************************************** +*/ + +#define BOOST_TEST_MODULE demand_data +#include + +#include "demand.h" + + +BOOST_AUTO_TEST_SUITE(test_filemanager) + + + + +BOOST_AUTO_TEST_SUITE_END() From 45812666544dfbcf64a514a8474167233cf19079 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Thu, 18 Apr 2019 13:46:18 -0400 Subject: [PATCH 07/36] test demand data passing --- src/demand.c | 15 ++++- src/demand.h | 12 +++- tests/CMakeLists.txt | 9 +++ tests/test_demand_data.cpp | 115 ++++++++++++++++++++++++++++++++++++- 4 files changed, 146 insertions(+), 5 deletions(-) diff --git a/src/demand.c b/src/demand.c index a93b9e4..b97ee86 100644 --- a/src/demand.c +++ b/src/demand.c @@ -11,7 +11,14 @@ ****************************************************************************** */ -#include +#ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #include +#else + #include +#endif + #include #include "demand.h" @@ -35,13 +42,14 @@ demand_data_t *create_demand_data(double base_demand, int pattern_index, char *c if (category_name) demand_data->category_name = strdup(category_name); else - demand_data->category_name[0] = '\0'; + demand_data->category_name = NULL; return demand_data; } void delete_demand_data(void *data) { + // TODO: This cast is a problem! demand_data_t *demand_data = *(demand_data_t **)data; if (demand_data->category_name) @@ -92,10 +100,11 @@ void set_pattern_index(list_node_t *lnode, int pattern_index) char *get_category_name(list_node_t *lnode) { - return get_demand_data(lnode)->category_name; + return strdup(get_demand_data(lnode)->category_name); } void set_category_name(list_node_t *lnode, char *category_name) { + free(get_demand_data(lnode)->category_name); get_demand_data(lnode)->category_name = strdup(category_name); } diff --git a/src/demand.h b/src/demand.h index 775ed4a..9ae0e58 100644 --- a/src/demand.h +++ b/src/demand.h @@ -18,6 +18,11 @@ #include "util/list.h" +#ifdef __cplusplus +extern "C" { +#endif + + // Forward declarations typedef struct demand_data_s demand_data_t; @@ -43,8 +48,13 @@ void set_pattern_index(list_node_t *lnode, int pattern_index); char *get_category_name(list_node_t *lnode); void set_category_name(list_node_t *lnode, char *category_name); -// Make this private? +// Make this private? demand_data_t *get_demand_data(list_node_t *lnode); +#ifdef __cplusplus +} +#endif + + #endif /* DEMAND_H */ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0a5f91e..dd9668e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -23,6 +23,15 @@ add_test(NAME test_net_builder WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data) +add_executable(test_demand_data test_demand_data.cpp + ../src/demand.c + ../src/util/list.c) +target_include_directories(test_demand_data PUBLIC ../src/ ../src/util/) +target_link_libraries(test_demand_data ${Boost_LIBRARIES}) +add_test(NAME test_demand_data + COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_demand_data + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data) + set(toolkit_test_srcs test_toolkit.cpp diff --git a/tests/test_demand_data.cpp b/tests/test_demand_data.cpp index 0700476..b78964a 100644 --- a/tests/test_demand_data.cpp +++ b/tests/test_demand_data.cpp @@ -17,9 +17,122 @@ #include "demand.h" -BOOST_AUTO_TEST_SUITE(test_filemanager) +boost::test_tools::predicate_result check_string(std::string test, std::string ref) +{ + if (ref.compare(test) == 0) + return true; + else + return false; +} +BOOST_AUTO_TEST_SUITE(test_demand_data) + + +BOOST_AUTO_TEST_CASE (test_create_destroy) +{ + void *data = NULL; + + data = create_demand_data(100.0, 1, NULL); + BOOST_CHECK(data != NULL); + + delete_demand_data(&data); + + data = NULL; + + data = create_demand_data(100.0, 1, "CUB_SCOUT_BASE_CAMP"); + BOOST_CHECK(data != NULL); + + delete_demand_data(&data); +} + +BOOST_AUTO_TEST_CASE(test_get_size) +{ + size_t size = get_demand_data_size(); + BOOST_CHECK(size == 8); +} + + +struct Fixture { + Fixture() { + _data = NULL; + dlist = NULL; + + dlist = create_list(get_demand_data_size(), delete_demand_data); + _data = create_demand_data(100.0, 1, "CUB_SCOUT_BASE_CAMP"); + + append_list(dlist, &_data); + + } + ~Fixture() { + delete_list(dlist); + } + void *_data; + list_t *dlist; +}; + +BOOST_FIXTURE_TEST_CASE(test_demand_list, Fixture) +{ + list_node_t *lnode = head_list(dlist, false); + BOOST_CHECK(lnode != NULL); +} + +BOOST_FIXTURE_TEST_CASE(test_demand_getset, Fixture) +{ + list_node_t *lnode = head_list(dlist, false); + double demand; + + demand = get_base_demand(lnode); + BOOST_CHECK(demand == 100.0); + + set_base_demand(lnode, 200.0); + + demand = get_base_demand(lnode); + BOOST_CHECK(demand == 200.0); +} + +BOOST_FIXTURE_TEST_CASE(test_pattern_getset, Fixture) +{ + list_node_t *lnode = head_list(dlist, false); + int index; + + index = get_pattern_index(lnode); + BOOST_CHECK(index == 1); + + set_pattern_index(lnode, 2); + + index = get_pattern_index(lnode); + BOOST_CHECK(index == 2); +} + +BOOST_FIXTURE_TEST_CASE(test_category_getset, Fixture) +{ + list_node_t *lnode = head_list(dlist, false); + char *name; + + name = get_category_name(lnode); + BOOST_CHECK(check_string(name, "CUB_SCOUT_BASE_CAMP")); + + free(name); + + set_category_name(lnode, "CUB_SCOUT_COMMAND"); + + name = get_category_name(lnode); + BOOST_CHECK(check_string(name, "CUB_SCOUT_COMMAND")); + + free(name); +} + +BOOST_FIXTURE_TEST_CASE(test_convert_demand, Fixture) +{ + list_node_t *lnode = head_list(dlist, false); + BOOST_CHECK(lnode != NULL); + + // 100.0 GPM == 6.31 LPS + convert_units(lnode, 15.850); + double demand = get_base_demand(lnode); + BOOST_TEST(demand == 6.31, boost::test_tools::tolerance(0.01)); +} BOOST_AUTO_TEST_SUITE_END() From bf519fdd94e45c45181bd6fbae4045ffd15341a5 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Thu, 18 Apr 2019 14:24:30 -0400 Subject: [PATCH 08/36] Work in progress Fixing problems when demand lists are null --- src/epanet.c | 3 ++- src/hydraul.c | 22 ++++++++++++---------- src/input1.c | 7 ++++--- src/project.c | 12 ++++++------ 4 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/epanet.c b/src/epanet.c index 4d06e4b..8af09ee 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -1897,7 +1897,8 @@ int DLLEXPORT EN_deletenode(EN_Project p, int index, int actionCode) // Free memory allocated to node's demands, WQ source & comment demand = node->D; - delete_list(demand); + if (demand) + delete_list(demand); // while (demand != NULL) // { // nextdemand = demand->next; diff --git a/src/hydraul.c b/src/hydraul.c index ac3357a..515be11 100755 --- a/src/hydraul.c +++ b/src/hydraul.c @@ -567,16 +567,18 @@ void demands(Project *pr) { sum = 0.0; list_t *dlist = net->Node[i].D; - list_node_t *lnode; - for (lnode = first_list(dlist); done_list(lnode); lnode = next_list(lnode)) - { - // pattern period (k) = (elapsed periods) modulus (periods per pattern) - j = get_pattern_index(lnode); - k = p % (long) net->Pattern[j].Length; - djunc = (get_base_demand(lnode)) * net->Pattern[j].F[k] * hyd->Dmult; - if (djunc > 0.0) hyd->Dsystem += djunc; - sum += djunc; - } + + if (dlist) { + for (list_node_t *lnode = first_list(dlist); done_list(lnode); lnode = next_list(lnode)) + { + // pattern period (k) = (elapsed periods) modulus (periods per pattern) + j = get_pattern_index(lnode); + k = p % (long)net->Pattern[j].Length; + djunc = (get_base_demand(lnode)) * net->Pattern[j].F[k] * hyd->Dmult; + if (djunc > 0.0) hyd->Dsystem += djunc; + sum += djunc; + } + } hyd->NodeDemand[i] = sum; // Initialize pressure dependent demand diff --git a/src/input1.c b/src/input1.c index 2d80d5b..aafa576 100644 --- a/src/input1.c +++ b/src/input1.c @@ -568,9 +568,10 @@ void convertunits(Project *pr) { node = &net->Node[i]; list_t *dlist = node->D; - for (list_node_t *lnode = first_list(dlist); done_list(lnode); lnode = next_list(lnode)) - convert_units(lnode, pr->Ucf[DEMAND]); - + if (dlist) { + for (list_node_t *lnode = first_list(dlist); done_list(lnode); lnode = next_list(lnode)) + convert_units(lnode, pr->Ucf[DEMAND]); + } // for (demand = node->D; demand != NULL; demand = demand->next) // { // demand->Base /= pr->Ucf[DEMAND]; diff --git a/src/project.c b/src/project.c index 9324bea..ea62e59 100644 --- a/src/project.c +++ b/src/project.c @@ -407,7 +407,8 @@ void freedata(Project *pr) { // Free memory used for demand category list list_t *demand = pr->network.Node[j].D; - delete_list(demand); + if(demand) + delete_list(demand); /*while (demand != NULL) { nextdemand = demand->next; @@ -822,11 +823,10 @@ void adjustpatterns(Network *network, int index) { // Adjust demand patterns list_t *dlist = network->Node[j].D; - list_node_t *lnode; - - for (lnode = first_list(dlist); done_list(lnode); lnode = next_list(lnode)) - _adjustpattern(lnode, index); - + if (dlist) { + for (list_node_t *lnode = first_list(dlist); done_list(lnode); lnode = next_list(lnode)) + _adjustpattern(lnode, index); + } // Adjust WQ source patterns source = network->Node[j].S; if (source) adjustpattern(&source->Pat, index); From 901a802f2189aed5cec0ef364960ff1661fb2260 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Thu, 18 Apr 2019 16:16:02 -0400 Subject: [PATCH 09/36] Passing open and close test --- src/input3.c | 2 +- src/types.h | 16 ++++++++-------- tests/CMakeLists.txt | 2 +- tests/test_demand_data.cpp | 27 +++++++++++++++++++++++++-- 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/src/input3.c b/src/input3.c index 617f464..161f2ab 100644 --- a/src/input3.c +++ b/src/input3.c @@ -132,7 +132,7 @@ int juncdata(Project *pr) // apply the default demand pattern and append the data if (p == 0) p = findpattern(net, parser->DefPatID); demand_data = create_demand_data(y, p, NULL); - if (demand_data == NULL) return 101; + if (demand_data == NULL) return 101; append_list(demand_list, &demand_data); } diff --git a/src/types.h b/src/types.h index 01b25af..b848238 100755 --- a/src/types.h +++ b/src/types.h @@ -339,14 +339,14 @@ typedef struct // Curve Object double *Y; // y-values } Scurve; -struct Sdemand // Demand List Item -{ - double Base; // baseline demand - int Pat; // pattern index - char *Name; // demand category name - struct Sdemand *next; // next demand list item -}; -typedef struct Sdemand *Pdemand; // Pointer to demand list +//struct Sdemand // Demand List Item +//{ +// double Base; // baseline demand +// int Pat; // pattern index +// char *Name; // demand category name +// struct Sdemand *next; // next demand list item +//}; +//typedef struct Sdemand *Pdemand; // Pointer to demand list typedef struct // Energy Usage Object { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index dd9668e..62f6f00 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -27,7 +27,7 @@ add_executable(test_demand_data test_demand_data.cpp ../src/demand.c ../src/util/list.c) target_include_directories(test_demand_data PUBLIC ../src/ ../src/util/) -target_link_libraries(test_demand_data ${Boost_LIBRARIES}) +target_link_libraries(test_demand_data ${Boost_LIBRARIES} epanet2) add_test(NAME test_demand_data COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_demand_data WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data) diff --git a/tests/test_demand_data.cpp b/tests/test_demand_data.cpp index b78964a..7b61ac4 100644 --- a/tests/test_demand_data.cpp +++ b/tests/test_demand_data.cpp @@ -15,6 +15,13 @@ #include #include "demand.h" +#include "epanet2_2.h" + + +#define DATA_PATH_NET1 "./net1.inp" +#define DATA_PATH_TMP "./tmp.inp" +#define DATA_PATH_RPT "./test.rpt" +#define DATA_PATH_OUT "./test.out" boost::test_tools::predicate_result check_string(std::string test, std::string ref) @@ -62,12 +69,11 @@ struct Fixture { _data = create_demand_data(100.0, 1, "CUB_SCOUT_BASE_CAMP"); append_list(dlist, &_data); - } ~Fixture() { delete_list(dlist); } - void *_data; + demand_data_t *_data; list_t *dlist; }; @@ -134,5 +140,22 @@ BOOST_FIXTURE_TEST_CASE(test_convert_demand, Fixture) BOOST_TEST(demand == 6.31, boost::test_tools::tolerance(0.01)); } +BOOST_AUTO_TEST_CASE(test_openclose) +{ + int error; + + EN_Project ph = NULL; + + EN_createproject(&ph); + + error = EN_open(ph, DATA_PATH_NET1, DATA_PATH_RPT, DATA_PATH_OUT); + BOOST_REQUIRE(error == 0); + + error = EN_close(ph); + BOOST_REQUIRE(error == 0); + + EN_deleteproject(&ph); +} + BOOST_AUTO_TEST_SUITE_END() From 76b6254f3394ad4775e64d09c39a88edd7b9347c Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Thu, 18 Apr 2019 17:07:50 -0400 Subject: [PATCH 10/36] get/set demand name are passing --- src/epanet.c | 19 +++++++++------ tests/test_demand_data.cpp | 48 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 7 deletions(-) diff --git a/src/epanet.c b/src/epanet.c index 8af09ee..0ab9ffc 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -2758,10 +2758,10 @@ int DLLEXPORT EN_getnumdemands(EN_Project p, int nodeIndex, int *numDemands) // Count the number of demand categories list_t *demand_list = p->network.Node[nodeIndex].D; - if (!demand_list) - *numDemands = 0; - else - *numDemands = size_list(demand_list); + if (demand_list) + *numDemands = size_list(demand_list); + else + *numDemands = 0; return 0; } @@ -2842,6 +2842,7 @@ int DLLEXPORT EN_getdemandname(EN_Project p, int nodeIndex, int demandIndex, { //Pdemand d; //int n = 1; + char *temp = NULL; strcpy(demandName, ""); @@ -2855,14 +2856,18 @@ int DLLEXPORT EN_getdemandname(EN_Project p, int nodeIndex, int demandIndex, if (!lnode) return 253; else - demandName = get_category_name(lnode); + temp = get_category_name(lnode); //for (d = p->network.Node[nodeIndex].D; // n < demandIndex && d->next != NULL; d = d->next) n++; //if (n != demandIndex) return 253; - //if (d->Name) strcpy(demandName, d->Name); - //else demandName[0] = '\0'; + if (temp) { + strcpy(demandName, temp); + //else demandName[0] = '\0'; + free(temp); + } + return 0; } diff --git a/tests/test_demand_data.cpp b/tests/test_demand_data.cpp index 7b61ac4..c9a7124 100644 --- a/tests/test_demand_data.cpp +++ b/tests/test_demand_data.cpp @@ -158,4 +158,52 @@ BOOST_AUTO_TEST_CASE(test_openclose) } +#define DATA_PATH_NET1 "./net1.inp" +#define DATA_PATH_TMP "./tmp.inp" +#define DATA_PATH_RPT "./test.rpt" +#define DATA_PATH_OUT "./test.out" + +struct FixtureOpenClose { + FixtureOpenClose() { + error = 0; + ph = NULL; + + EN_createproject(&ph); + error = EN_open(ph, DATA_PATH_NET1, DATA_PATH_RPT, DATA_PATH_OUT); + } + + ~FixtureOpenClose() { + error = EN_close(ph); + EN_deleteproject(&ph); + } + + int error; + EN_Project ph; +}; + + +BOOST_FIXTURE_TEST_CASE(test_demandname_getset, FixtureOpenClose) +{ + int Nindex, ndem; + + error = EN_getnodeindex(ph, (char *)"12", &Nindex); + BOOST_REQUIRE(error == 0); + error = EN_getnumdemands(ph, Nindex, &ndem); + BOOST_REQUIRE(error == 0); + BOOST_CHECK(ndem == 1); + + char demname[31]; + + error = EN_getdemandname(ph, Nindex, ndem, demname); + BOOST_REQUIRE(error == 0); + BOOST_CHECK(check_string(demname, "\0")); + + error = EN_setdemandname(ph, Nindex, ndem, (char *)"Demand category name"); + BOOST_REQUIRE(error == 0); + + error = EN_getdemandname(ph, Nindex, ndem, demname); + BOOST_REQUIRE(error == 0); + BOOST_CHECK(check_string(demname, "Demand category name")); +} + BOOST_AUTO_TEST_SUITE_END() From 55a28de9e003f0564b3611e83aeeac966915a9d4 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Thu, 18 Apr 2019 17:34:02 -0400 Subject: [PATCH 11/36] Work in progress --- tests/test_demand_data.cpp | 40 +++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/tests/test_demand_data.cpp b/tests/test_demand_data.cpp index c9a7124..6428cc0 100644 --- a/tests/test_demand_data.cpp +++ b/tests/test_demand_data.cpp @@ -181,7 +181,6 @@ struct FixtureOpenClose { EN_Project ph; }; - BOOST_FIXTURE_TEST_CASE(test_demandname_getset, FixtureOpenClose) { int Nindex, ndem; @@ -206,4 +205,43 @@ BOOST_FIXTURE_TEST_CASE(test_demandname_getset, FixtureOpenClose) BOOST_CHECK(check_string(demname, "Demand category name")); } +BOOST_FIXTURE_TEST_CASE(test_demandpattern_get, FixtureOpenClose) +{ + int n, patIdx; + + error = EN_getdemandpattern(ph, 3, 1, &patIdx); + BOOST_REQUIRE(error == 0); + + error = EN_getpatternlen(ph, patIdx, &n); + BOOST_REQUIRE(error == 0); + + BOOST_CHECK(n == 12); +} + +BOOST_FIXTURE_TEST_CASE(test_demandpattern_getset, FixtureOpenClose) +{ + int n, patIdx; + + double f3[] = { 3.1, 3.2, 3.3, 3.4 }; + + // Create pattern + error = EN_addpattern(ph, (char *)"Pat3"); + BOOST_REQUIRE(error == 0); + + error = EN_setpattern(ph, 3, f3, 4); + BOOST_REQUIRE(error == 0); + + // Assign Pat3 to 3rd junction + error = EN_setdemandpattern(ph, 3, 1, 3); + BOOST_REQUIRE(error == 0); + + + error = EN_getdemandpattern(ph, 3, 1, &patIdx); + BOOST_REQUIRE(error == 0); + + error = EN_getpatternlen(ph, patIdx, &n); + BOOST_REQUIRE(error == 0); + BOOST_CHECK(n == 4); +} + BOOST_AUTO_TEST_SUITE_END() From 7537be1ec94172d0460c9797464953564c364458 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Fri, 19 Apr 2019 18:01:06 -0400 Subject: [PATCH 12/36] Work in progress Working on demand lists --- src/demand.c | 18 ++++ src/demand.h | 3 + src/epanet.c | 56 +++++++---- src/input3.c | 15 +-- src/util/list.c | 2 +- tests/test_demand_data.cpp | 187 ++++++++++++++++++++++++++++--------- tests/test_pattern.cpp | 51 +++++++++- 7 files changed, 254 insertions(+), 78 deletions(-) diff --git a/src/demand.c b/src/demand.c index b97ee86..7b8a0b1 100644 --- a/src/demand.c +++ b/src/demand.c @@ -32,6 +32,24 @@ typedef struct demand_data_s } demand_data_t; + +list_t *create_demand_list(double base_demand, int pattern_index, char *category_name) +{ + list_t *demand_list; + demand_data_t *demand_data; + + demand_list = create_list(get_demand_data_size(), delete_demand_data); + if (!demand_list) return NULL; + + demand_data = create_demand_data(base_demand, pattern_index, category_name); + if (!demand_data) return NULL; + + append_list(demand_list, &demand_data); + + return demand_list; +} + + demand_data_t *create_demand_data(double base_demand, int pattern_index, char *category_name) { demand_data_t *demand_data = (demand_data_t *)malloc(sizeof(demand_data_t)); diff --git a/src/demand.h b/src/demand.h index 9ae0e58..fcc7826 100644 --- a/src/demand.h +++ b/src/demand.h @@ -29,6 +29,9 @@ typedef struct demand_data_s demand_data_t; // demand list gets declared in types.h struct Snode +list_t *create_demand_list(double base_demand, int pattern_index, char *category_name); + + demand_data_t *create_demand_data(double base_demand, int pat_index, char *cat_name); void delete_demand_data(void *data); diff --git a/src/epanet.c b/src/epanet.c index 0ab9ffc..407a5ff 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -2818,13 +2818,22 @@ int DLLEXPORT EN_setbasedemand(EN_Project p, int nodeIndex, int demandIndex, // Set baseline demand for specified category if (nodeIndex <= p->network.Njuncs) { - // Locate demand category record and assign demandName to it list_t *dlist = p->network.Node[nodeIndex].D; - list_node_t *lnode = get_nth_list(dlist, demandIndex); - if (!lnode) - return 253; - else - set_base_demand(lnode, baseDemand / p->Ucf[FLOW]); + // If demand list is null create one and set demand + if (!dlist) { + dlist = create_demand_list(baseDemand / p->Ucf[FLOW], 0, NULL); + if (!dlist) return 101; + + p->network.Node[nodeIndex].D = dlist; + } + // else find the demand entry and set demand + else { + list_node_t *lnode = get_nth_list(dlist, demandIndex); + if (!lnode) + return 253; + else + set_base_demand(lnode, baseDemand / p->Ucf[FLOW]); + } } return 0; } @@ -2895,12 +2904,19 @@ int DLLEXPORT EN_setdemandname(EN_Project p, int nodeIndex, int demandIndex, // Locate demand category record and assign demandName to it list_t *dlist = p->network.Node[nodeIndex].D; - list_node_t *lnode = get_nth_list(dlist, demandIndex); - if (!lnode) - return 253; - else - set_category_name(lnode, demandName); + if (!dlist) { + dlist = create_demand_list(0, 0, demandName); + if (!dlist) return 101; + p->network.Node[nodeIndex].D = dlist; + } + else { + list_node_t *lnode = get_nth_list(dlist, demandIndex); + if (!lnode) + return 253; + else + set_category_name(lnode, demandName); + } return 0; } @@ -2960,11 +2976,19 @@ int DLLEXPORT EN_setdemandpattern(EN_Project p, int nodeIndex, int demandIndex, if (nodeIndex <= net->Njuncs) { list_t *dlist = p->network.Node[nodeIndex].D; - list_node_t *lnode = get_nth_list(dlist, demandIndex); - if (!lnode) - return 253; - else - set_pattern_index(lnode, patIndex); + if (!dlist) { + dlist = create_demand_list(0, patIndex, NULL); + if (!dlist) return 101; + + p->network.Node[nodeIndex].D = dlist; + } + else { + list_node_t *lnode = get_nth_list(dlist, demandIndex); + if (!lnode) + return 253; + else + set_pattern_index(lnode, patIndex); + } } return 0; } diff --git a/src/input3.c b/src/input3.c index 161f2ab..9837bd4 100644 --- a/src/input3.c +++ b/src/input3.c @@ -124,22 +124,11 @@ int juncdata(Project *pr) // create demand data only if a demand has been specified if (y != 0.0) { - demand_data_t *demand_data; - - demand_list = create_list(get_demand_data_size(), delete_demand_data); - if (demand_list == NULL) return 101; - // apply the default demand pattern and append the data if (p == 0) p = findpattern(net, parser->DefPatID); - demand_data = create_demand_data(y, p, NULL); - if (demand_data == NULL) return 101; - - append_list(demand_list, &demand_data); + demand_list = create_demand_list(y, p, NULL); + if (!demand_list) return 101; } - //demand->Base = y; - //demand->Pat = p; - //demand->Name = NULL; - //demand->next = NULL; node->D = demand_list; hyd->NodeDemand[njuncs] = y; diff --git a/src/util/list.c b/src/util/list.c index c74e2c2..0b568d9 100644 --- a/src/util/list.c +++ b/src/util/list.c @@ -120,7 +120,7 @@ list_node_t *head_list(list_t *list, bool removeFromList) // Warning: When node is removed caller is responsible for freeing it. // { - assert(list->head != NULL); +// assert(list->head != NULL); if (list) { list_node_t *node = list->head; diff --git a/tests/test_demand_data.cpp b/tests/test_demand_data.cpp index 6428cc0..8d7252c 100644 --- a/tests/test_demand_data.cpp +++ b/tests/test_demand_data.cpp @@ -36,6 +36,17 @@ boost::test_tools::predicate_result check_string(std::string test, std::string r BOOST_AUTO_TEST_SUITE(test_demand_data) +BOOST_AUTO_TEST_CASE(test_create_destroy_demand_list) +{ + list_t *dlist; + + dlist = create_demand_list(100.0, 1, "CUB_SCOUT_DAY_CAMP"); + BOOST_CHECK(dlist != NULL); + + delete_list(dlist); +} + + BOOST_AUTO_TEST_CASE (test_create_destroy) { void *data = NULL; @@ -140,7 +151,7 @@ BOOST_FIXTURE_TEST_CASE(test_convert_demand, Fixture) BOOST_TEST(demand == 6.31, boost::test_tools::tolerance(0.01)); } -BOOST_AUTO_TEST_CASE(test_openclose) +BOOST_AUTO_TEST_CASE(test_initclose) { int error; @@ -148,7 +159,7 @@ BOOST_AUTO_TEST_CASE(test_openclose) EN_createproject(&ph); - error = EN_open(ph, DATA_PATH_NET1, DATA_PATH_RPT, DATA_PATH_OUT); + error = EN_init(ph, DATA_PATH_RPT, DATA_PATH_OUT, EN_GPM, EN_HW); BOOST_REQUIRE(error == 0); error = EN_close(ph); @@ -163,85 +174,173 @@ BOOST_AUTO_TEST_CASE(test_openclose) #define DATA_PATH_RPT "./test.rpt" #define DATA_PATH_OUT "./test.out" -struct FixtureOpenClose { - FixtureOpenClose() { + +struct FixtureSingleNode { + FixtureSingleNode() { error = 0; ph = NULL; EN_createproject(&ph); - error = EN_open(ph, DATA_PATH_NET1, DATA_PATH_RPT, DATA_PATH_OUT); + EN_init(ph, DATA_PATH_RPT, DATA_PATH_OUT, EN_GPM, EN_HW); + + EN_addnode(ph, (char *)"N2", EN_JUNCTION); + EN_getnodeindex(ph, (char *)"N2", &node_idx); } - ~FixtureOpenClose() { - error = EN_close(ph); + ~FixtureSingleNode() { + EN_close(ph); EN_deleteproject(&ph); } - - int error; + int error, node_idx; EN_Project ph; }; -BOOST_FIXTURE_TEST_CASE(test_demandname_getset, FixtureOpenClose) -{ - int Nindex, ndem; - error = EN_getnodeindex(ph, (char *)"12", &Nindex); +BOOST_FIXTURE_TEST_CASE(test_single_node, FixtureSingleNode) +{ + int demand_idx, pattern_idx, n; + double demand; + + error = EN_getnumdemands(ph, node_idx, &n); BOOST_REQUIRE(error == 0); - error = EN_getnumdemands(ph, Nindex, &ndem); - BOOST_REQUIRE(error == 0); - BOOST_CHECK(ndem == 1); + BOOST_CHECK(n == 0); + + demand_idx = 1; + error = EN_getbasedemand(ph, node_idx, demand_idx, &demand); + BOOST_REQUIRE(error == 253); + + error = EN_getdemandpattern(ph, node_idx, demand_idx, &pattern_idx); + BOOST_REQUIRE(error == 253); char demname[31]; - - error = EN_getdemandname(ph, Nindex, ndem, demname); - BOOST_REQUIRE(error == 0); + error = EN_getdemandname(ph, node_idx, demand_idx, demname); + BOOST_REQUIRE(error == 253); BOOST_CHECK(check_string(demname, "\0")); - error = EN_setdemandname(ph, Nindex, ndem, (char *)"Demand category name"); + error = EN_setbasedemand(ph, node_idx, demand_idx, 100.0); BOOST_REQUIRE(error == 0); - error = EN_getdemandname(ph, Nindex, ndem, demname); + // only one demand category + pattern_idx = 1; + error = EN_setdemandpattern(ph, node_idx, demand_idx, pattern_idx); + BOOST_REQUIRE(error == 205); + + // create pattern + error = EN_addpattern(ph, (char *)"Pat2"); BOOST_REQUIRE(error == 0); - BOOST_CHECK(check_string(demname, "Demand category name")); + error = EN_getpatternindex(ph, (char *)"Pat2", &pattern_idx); + BOOST_REQUIRE(error == 0); + + error = EN_setdemandpattern(ph, node_idx, demand_idx, pattern_idx); + BOOST_REQUIRE(error == 0); + + error = EN_setdemandname(ph, node_idx, demand_idx, (char *)"CUB_SCOUT_MESS_HALL"); + BOOST_REQUIRE(error == 0); + } -BOOST_FIXTURE_TEST_CASE(test_demandpattern_get, FixtureOpenClose) + +BOOST_FIXTURE_TEST_CASE(test_pattern_edits, FixtureSingleNode) { - int n, patIdx; + int n, pat_idx; - error = EN_getdemandpattern(ph, 3, 1, &patIdx); + // Add 2 new patterns + error = EN_addpattern(ph, (char *)"Pat2"); BOOST_REQUIRE(error == 0); - - error = EN_getpatternlen(ph, patIdx, &n); - BOOST_REQUIRE(error == 0); - - BOOST_CHECK(n == 12); -} - -BOOST_FIXTURE_TEST_CASE(test_demandpattern_getset, FixtureOpenClose) -{ - int n, patIdx; - - double f3[] = { 3.1, 3.2, 3.3, 3.4 }; - - // Create pattern error = EN_addpattern(ph, (char *)"Pat3"); BOOST_REQUIRE(error == 0); + double f2[] = { 2.1, 2.2 }; + double f3[] = { 3.1, 3.2, 3.3, 3.4 }; + error = EN_setpattern(ph, 2, f2, 2); + BOOST_REQUIRE(error == 0); error = EN_setpattern(ph, 3, f3, 4); BOOST_REQUIRE(error == 0); - + // Assign Pat3 to 3rd junction error = EN_setdemandpattern(ph, 3, 1, 3); BOOST_REQUIRE(error == 0); - - error = EN_getdemandpattern(ph, 3, 1, &patIdx); + // Delete Pat2 + error = EN_deletepattern(ph, 2); BOOST_REQUIRE(error == 0); - - error = EN_getpatternlen(ph, patIdx, &n); + + //Check that there are now 2 patterns + error = EN_getcount(ph, EN_PATCOUNT, &n); + BOOST_REQUIRE(error == 0); + BOOST_CHECK(n == 2); + + // Check that Pat3 with 4 factors is still assigned to 3rd junction + error = EN_getdemandpattern(ph, 3, 1, &pat_idx); + BOOST_REQUIRE(error == 0); + error = EN_getpatternlen(ph, pat_idx, &n); BOOST_REQUIRE(error == 0); BOOST_CHECK(n == 4); } + +//BOOST_FIXTURE_TEST_CASE(test_demandpattern_getset, FixtureOpenClose) +//{ +// int n, patIdx, pat2Idx, pat3Idx, defPatIdx = 1; +// +// // Rename the default pattern +// error = EN_setpatternid(ph, defPatIdx, (char *)"Pat1"); +// BOOST_REQUIRE(error == 0); +// error = EN_getpatternindex(ph, (char *)"Pat1", &patIdx); +// BOOST_REQUIRE(error == 0); +// BOOST_CHECK(defPatIdx == patIdx); +// +// // Add 2 new patterns +// error = EN_addpattern(ph, (char *)"Pat2"); +// BOOST_REQUIRE(error == 0); +// error = EN_getpatternindex(ph, (char *)"Pat2", &pat2Idx); +// BOOST_REQUIRE(error == 0); +// +// error = EN_addpattern(ph, (char *)"Pat3"); +// BOOST_REQUIRE(error == 0); +// error = EN_getpatternindex(ph, (char *)"Pat3", &pat3Idx); +// BOOST_REQUIRE(error == 0); +// +// double f2[] = {2.1, 2.2}; +// double f3[] = {3.1, 3.2, 3.3, 3.4}; +// error = EN_setpattern(ph, pat2Idx, f2, 2); +// BOOST_REQUIRE(error == 0); +// error = EN_setpattern(ph, pat3Idx, f3, 4); +// BOOST_REQUIRE(error == 0); +// +// // Assign Pat3 to 3rd junction +// error = EN_setdemandpattern(ph, 3, 1, pat3Idx); +// BOOST_REQUIRE(error == 0); +// +// // Delete Pat2 and check for 2 patterns +// //error = EN_deletepattern(ph, pat2Idx); +// //BOOST_REQUIRE(error == 0); +// //error = EN_getcount(ph, EN_PATCOUNT, &n); +// //BOOST_REQUIRE(error == 0); +// //BOOST_CHECK(n == 2); +// +// // Check that Pat3 with 4 factors is still assigned to 3rd junction +// error = EN_getdemandpattern(ph, 3, 1, &patIdx); +// BOOST_REQUIRE(error == 0); +// error = EN_getpatternlen(ph, patIdx, &n); +// BOOST_REQUIRE(error == 0); +// BOOST_CHECK(n == 4); +// +// // Delete the default pattern +// //error = EN_deletepattern(ph, defPatIdx); +// //BOOST_REQUIRE(error == 0); +// +// // Check that junction 4 has no pattern +// error = EN_getdemandpattern(ph, 4, 1, &patIdx); +// BOOST_REQUIRE(error == 0); +// BOOST_CHECK(patIdx == 0); +// +// // And that junction 3 still uses Pat3 +// error = EN_getdemandpattern(ph, 3, 1, &pat3Idx); +// BOOST_REQUIRE(error == 0); +// error = EN_getpatternindex(ph, (char *)"Pat3", &patIdx); +// BOOST_REQUIRE(error == 0); +// BOOST_CHECK(pat3Idx == patIdx); +//} + BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/test_pattern.cpp b/tests/test_pattern.cpp index ef2eb71..01af33d 100644 --- a/tests/test_pattern.cpp +++ b/tests/test_pattern.cpp @@ -18,7 +18,51 @@ BOOST_AUTO_TEST_SUITE (pattern) -BOOST_AUTO_TEST_CASE(add_set_pattern) +BOOST_FIXTURE_TEST_CASE(test_set_get_default_pattern, FixtureOpenClose) +{ + // Assign the default pattern index + int defPatIdx = 1; + int patIdx; + + // Rename the default pattern + error = EN_setpatternid(ph, defPatIdx, (char *)"Pat1"); + BOOST_REQUIRE(error == 0); + + error = EN_getpatternindex(ph, (char *)"Pat1", &patIdx); + BOOST_REQUIRE(error == 0); + + BOOST_CHECK(defPatIdx == patIdx); +} + +BOOST_FIXTURE_TEST_CASE(test_add_delete, FixtureOpenClose) +{ + double f2[] = { 2.1, 2.2 }; + double f3[] = { 3.1, 3.2, 3.3, 3.4 }; + + // Add 2 new patterns + error = EN_addpattern(ph, (char *)"Pat2"); + BOOST_REQUIRE(error == 0); + error = EN_addpattern(ph, (char *)"Pat3"); + BOOST_REQUIRE(error == 0); + + error = EN_setpattern(ph, 2, f2, 2); + BOOST_REQUIRE(error == 0); + error = EN_setpattern(ph, 3, f3, 4); + BOOST_REQUIRE(error == 0); + + // Delete Pat2 + error = EN_deletepattern(ph, 2); + BOOST_REQUIRE(error == 0); + + // Check that there are now 2 patterns + int n; + error = EN_getcount(ph, EN_PATCOUNT, &n); + BOOST_REQUIRE(error == 0); + BOOST_CHECK(n == 2); +} + + +BOOST_AUTO_TEST_CASE(test_add_set) { std::string path_inp(DATA_PATH_NET1); std::string path_rpt(DATA_PATH_RPT); @@ -34,7 +78,7 @@ BOOST_AUTO_TEST_CASE(add_set_pattern) BOOST_REQUIRE(error == 0); // Assign the default pattern index - int defPatIdx = 1; + int n, defPatIdx = 1; int patIdx; // Rename the default pattern @@ -56,8 +100,7 @@ BOOST_AUTO_TEST_CASE(add_set_pattern) // Delete Pat2 EN_deletepattern(ph, 2); - // Check that there are now 2 patterns - int n; + //Check that there are now 2 patterns EN_getcount(ph, EN_PATCOUNT, &n); BOOST_REQUIRE(n == 2); From e9650d2d6db1c02d6f3b0f6fff1af821a51aaed2 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Fri, 19 Apr 2019 21:21:58 -0400 Subject: [PATCH 13/36] Work in progress Fixing memory leaks Unit tests passing --- src/demand.c | 1 + src/inpfile.c | 6 +- src/project.c | 8 +-- tests/test_demand.cpp | 7 ++- tests/test_demand_data.cpp | 112 ++++++++++--------------------------- 5 files changed, 45 insertions(+), 89 deletions(-) diff --git a/src/demand.c b/src/demand.c index 7b8a0b1..48a7980 100644 --- a/src/demand.c +++ b/src/demand.c @@ -117,6 +117,7 @@ void set_pattern_index(list_node_t *lnode, int pattern_index) } char *get_category_name(list_node_t *lnode) +// Be advised: caller must free memory returned { return strdup(get_demand_data(lnode)->category_name); } diff --git a/src/inpfile.c b/src/inpfile.c index 53aee71..6df3d2c 100644 --- a/src/inpfile.c +++ b/src/inpfile.c @@ -334,6 +334,7 @@ int saveinpfile(Project *pr, const char *fname) list_t *dlist; list_node_t *lnode; + char *temp = NULL; for (i = 1; i <= net->Njuncs; i++) { @@ -345,7 +346,10 @@ int saveinpfile(Project *pr, const char *fname) if ((j = get_pattern_index(lnode)) > 0) sprintf(s1, " %-31s", net->Pattern[j].ID); else strcpy(s1, " "); fprintf(f, "\n%s %-31s", s, s1); - if (get_category_name(lnode)) fprintf(f, " ;%s", get_category_name(lnode)); + if (temp = get_category_name(lnode)) { + fprintf(f, " ;%s", temp); + free(temp); + } } } } diff --git a/src/project.c b/src/project.c index ea62e59..b394bd2 100644 --- a/src/project.c +++ b/src/project.c @@ -797,12 +797,12 @@ void adjustpattern(int *pat, int index) } -void _adjustpattern(list_node_t *lnode, int index) +void _adjustpattern(list_node_t *lnode, int del_idx) { - int pat = get_pattern_index(lnode); + int pat_idx = get_pattern_index(lnode); - if (pat == index) set_pattern_index(lnode, 0); - else if (pat > index) set_pattern_index(lnode, pat--); + if (pat_idx == del_idx) set_pattern_index(lnode, 0); + else if (pat_idx > del_idx) set_pattern_index(lnode, --pat_idx); } diff --git a/tests/test_demand.cpp b/tests/test_demand.cpp index 9a02ff7..1ef0cf3 100644 --- a/tests/test_demand.cpp +++ b/tests/test_demand.cpp @@ -18,6 +18,7 @@ BOOST_AUTO_TEST_SUITE (test_demand) + BOOST_AUTO_TEST_CASE(test_categories_save) { int error = 0; @@ -38,7 +39,7 @@ BOOST_AUTO_TEST_CASE(test_categories_save) error = EN_getdemandname(ph, Nindex, ndem, demname); BOOST_REQUIRE(error == 0); - error = EN_setdemandname(ph, Nindex, ndem, (char *)"Demand category name"); + error = EN_setdemandname(ph, Nindex, ndem, (char *)"CUB_SCOUT_MOTOR_POOL"); BOOST_REQUIRE(error == 0); error = EN_saveinpfile(ph, "net1_dem_cat.inp"); BOOST_REQUIRE(error == 0); @@ -49,6 +50,7 @@ BOOST_AUTO_TEST_CASE(test_categories_save) BOOST_REQUIRE(error == 0); } + BOOST_AUTO_TEST_CASE(test_categories_reopen, * boost::unit_test::depends_on("test_demand/test_categories_save")) { int error = 0; @@ -72,7 +74,7 @@ BOOST_AUTO_TEST_CASE(test_categories_reopen, * boost::unit_test::depends_on("tes error = EN_getdemandname(ph, Nindex, ndem, demname); BOOST_REQUIRE(error == 0); - BOOST_CHECK(check_string(demname, "Demand category name")); + BOOST_CHECK(check_string(demname, "CUB_SCOUT_MOTOR_POOL")); error = EN_close(ph); BOOST_REQUIRE(error == 0); @@ -80,4 +82,5 @@ BOOST_AUTO_TEST_CASE(test_categories_reopen, * boost::unit_test::depends_on("tes BOOST_REQUIRE(error == 0); } + BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/test_demand_data.cpp b/tests/test_demand_data.cpp index 8d7252c..80b6cb0 100644 --- a/tests/test_demand_data.cpp +++ b/tests/test_demand_data.cpp @@ -125,12 +125,13 @@ BOOST_FIXTURE_TEST_CASE(test_pattern_getset, Fixture) BOOST_FIXTURE_TEST_CASE(test_category_getset, Fixture) { list_node_t *lnode = head_list(dlist, false); - char *name; + char *name = NULL; name = get_category_name(lnode); BOOST_CHECK(check_string(name, "CUB_SCOUT_BASE_CAMP")); free(name); + name = NULL; set_category_name(lnode, "CUB_SCOUT_COMMAND"); @@ -183,15 +184,15 @@ struct FixtureSingleNode { EN_createproject(&ph); EN_init(ph, DATA_PATH_RPT, DATA_PATH_OUT, EN_GPM, EN_HW); - EN_addnode(ph, (char *)"N2", EN_JUNCTION); - EN_getnodeindex(ph, (char *)"N2", &node_idx); + EN_addnode(ph, (char *)"CUB_SCOUT_QUONSET_HUT", EN_JUNCTION); + EN_getnodeindex(ph, (char *)"CUB_SCOUT_QUONSET_HUT", &node_qhut); } ~FixtureSingleNode() { EN_close(ph); EN_deleteproject(&ph); } - int error, node_idx; + int error, node_qhut; EN_Project ph; }; @@ -201,28 +202,28 @@ BOOST_FIXTURE_TEST_CASE(test_single_node, FixtureSingleNode) int demand_idx, pattern_idx, n; double demand; - error = EN_getnumdemands(ph, node_idx, &n); + error = EN_getnumdemands(ph, node_qhut, &n); BOOST_REQUIRE(error == 0); BOOST_CHECK(n == 0); demand_idx = 1; - error = EN_getbasedemand(ph, node_idx, demand_idx, &demand); + error = EN_getbasedemand(ph, node_qhut, demand_idx, &demand); BOOST_REQUIRE(error == 253); - error = EN_getdemandpattern(ph, node_idx, demand_idx, &pattern_idx); + error = EN_getdemandpattern(ph, node_qhut, demand_idx, &pattern_idx); BOOST_REQUIRE(error == 253); char demname[31]; - error = EN_getdemandname(ph, node_idx, demand_idx, demname); + error = EN_getdemandname(ph, node_qhut, demand_idx, demname); BOOST_REQUIRE(error == 253); BOOST_CHECK(check_string(demname, "\0")); - error = EN_setbasedemand(ph, node_idx, demand_idx, 100.0); + error = EN_setbasedemand(ph, node_qhut, demand_idx, 100.0); BOOST_REQUIRE(error == 0); // only one demand category pattern_idx = 1; - error = EN_setdemandpattern(ph, node_idx, demand_idx, pattern_idx); + error = EN_setdemandpattern(ph, node_qhut, demand_idx, pattern_idx); BOOST_REQUIRE(error == 205); // create pattern @@ -231,10 +232,10 @@ BOOST_FIXTURE_TEST_CASE(test_single_node, FixtureSingleNode) error = EN_getpatternindex(ph, (char *)"Pat2", &pattern_idx); BOOST_REQUIRE(error == 0); - error = EN_setdemandpattern(ph, node_idx, demand_idx, pattern_idx); + error = EN_setdemandpattern(ph, node_qhut, demand_idx, pattern_idx); BOOST_REQUIRE(error == 0); - error = EN_setdemandname(ph, node_idx, demand_idx, (char *)"CUB_SCOUT_MESS_HALL"); + error = EN_setdemandname(ph, node_qhut, demand_idx, (char *)"CUB_SCOUT_MESS_HALL"); BOOST_REQUIRE(error == 0); } @@ -242,27 +243,37 @@ BOOST_FIXTURE_TEST_CASE(test_single_node, FixtureSingleNode) BOOST_FIXTURE_TEST_CASE(test_pattern_edits, FixtureSingleNode) { - int n, pat_idx; + int n, node_cpoint, pat2_idx, pat3_idx; + + EN_addnode(ph, (char *)"CUB_SCOUT_CHECKPOINT", EN_JUNCTION); + EN_getnodeindex(ph, (char *)"CUB_SCOUT_CHECKPOINT", &node_cpoint); // Add 2 new patterns + error = EN_addpattern(ph, (char *)"DefPat"); + BOOST_REQUIRE(error == 0); error = EN_addpattern(ph, (char *)"Pat2"); BOOST_REQUIRE(error == 0); + error = EN_getpatternindex(ph, "Pat2", &pat2_idx); + BOOST_REQUIRE(error == 0); + error = EN_addpattern(ph, (char *)"Pat3"); BOOST_REQUIRE(error == 0); + error = EN_getpatternindex(ph, "Pat3", &pat3_idx); + BOOST_REQUIRE(error == 0); double f2[] = { 2.1, 2.2 }; double f3[] = { 3.1, 3.2, 3.3, 3.4 }; - error = EN_setpattern(ph, 2, f2, 2); + error = EN_setpattern(ph, pat2_idx, f2, 2); BOOST_REQUIRE(error == 0); - error = EN_setpattern(ph, 3, f3, 4); + error = EN_setpattern(ph, pat3_idx, f3, 4); BOOST_REQUIRE(error == 0); // Assign Pat3 to 3rd junction - error = EN_setdemandpattern(ph, 3, 1, 3); + error = EN_setdemandpattern(ph, node_cpoint, 1, pat3_idx); BOOST_REQUIRE(error == 0); // Delete Pat2 - error = EN_deletepattern(ph, 2); + error = EN_deletepattern(ph, pat2_idx); BOOST_REQUIRE(error == 0); //Check that there are now 2 patterns @@ -271,76 +282,13 @@ BOOST_FIXTURE_TEST_CASE(test_pattern_edits, FixtureSingleNode) BOOST_CHECK(n == 2); // Check that Pat3 with 4 factors is still assigned to 3rd junction - error = EN_getdemandpattern(ph, 3, 1, &pat_idx); + error = EN_getdemandpattern(ph, node_cpoint, 1, &pat3_idx); BOOST_REQUIRE(error == 0); - error = EN_getpatternlen(ph, pat_idx, &n); + error = EN_getpatternlen(ph, pat3_idx, &n); BOOST_REQUIRE(error == 0); BOOST_CHECK(n == 4); } -//BOOST_FIXTURE_TEST_CASE(test_demandpattern_getset, FixtureOpenClose) -//{ -// int n, patIdx, pat2Idx, pat3Idx, defPatIdx = 1; -// -// // Rename the default pattern -// error = EN_setpatternid(ph, defPatIdx, (char *)"Pat1"); -// BOOST_REQUIRE(error == 0); -// error = EN_getpatternindex(ph, (char *)"Pat1", &patIdx); -// BOOST_REQUIRE(error == 0); -// BOOST_CHECK(defPatIdx == patIdx); -// -// // Add 2 new patterns -// error = EN_addpattern(ph, (char *)"Pat2"); -// BOOST_REQUIRE(error == 0); -// error = EN_getpatternindex(ph, (char *)"Pat2", &pat2Idx); -// BOOST_REQUIRE(error == 0); -// -// error = EN_addpattern(ph, (char *)"Pat3"); -// BOOST_REQUIRE(error == 0); -// error = EN_getpatternindex(ph, (char *)"Pat3", &pat3Idx); -// BOOST_REQUIRE(error == 0); -// -// double f2[] = {2.1, 2.2}; -// double f3[] = {3.1, 3.2, 3.3, 3.4}; -// error = EN_setpattern(ph, pat2Idx, f2, 2); -// BOOST_REQUIRE(error == 0); -// error = EN_setpattern(ph, pat3Idx, f3, 4); -// BOOST_REQUIRE(error == 0); -// -// // Assign Pat3 to 3rd junction -// error = EN_setdemandpattern(ph, 3, 1, pat3Idx); -// BOOST_REQUIRE(error == 0); -// -// // Delete Pat2 and check for 2 patterns -// //error = EN_deletepattern(ph, pat2Idx); -// //BOOST_REQUIRE(error == 0); -// //error = EN_getcount(ph, EN_PATCOUNT, &n); -// //BOOST_REQUIRE(error == 0); -// //BOOST_CHECK(n == 2); -// -// // Check that Pat3 with 4 factors is still assigned to 3rd junction -// error = EN_getdemandpattern(ph, 3, 1, &patIdx); -// BOOST_REQUIRE(error == 0); -// error = EN_getpatternlen(ph, patIdx, &n); -// BOOST_REQUIRE(error == 0); -// BOOST_CHECK(n == 4); -// -// // Delete the default pattern -// //error = EN_deletepattern(ph, defPatIdx); -// //BOOST_REQUIRE(error == 0); -// -// // Check that junction 4 has no pattern -// error = EN_getdemandpattern(ph, 4, 1, &patIdx); -// BOOST_REQUIRE(error == 0); -// BOOST_CHECK(patIdx == 0); -// -// // And that junction 3 still uses Pat3 -// error = EN_getdemandpattern(ph, 3, 1, &pat3Idx); -// BOOST_REQUIRE(error == 0); -// error = EN_getpatternindex(ph, (char *)"Pat3", &patIdx); -// BOOST_REQUIRE(error == 0); -// BOOST_CHECK(pat3Idx == patIdx); -//} BOOST_AUTO_TEST_SUITE_END() From 405822cdf62f51b29035b6b64d56b2a217b648e0 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Fri, 19 Apr 2019 21:34:25 -0400 Subject: [PATCH 14/36] Cleaning up build on gcc --- src/inpfile.c | 14 +++++++++----- tests/test_demand_data.cpp | 6 +++--- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/inpfile.c b/src/inpfile.c index 6df3d2c..6e668e9 100644 --- a/src/inpfile.c +++ b/src/inpfile.c @@ -332,8 +332,8 @@ int saveinpfile(Project *pr, const char *fname) fprintf(f, s_DEMANDS); ucf = pr->Ucf[DEMAND]; - list_t *dlist; - list_node_t *lnode; + list_t *dlist = NULL; + list_node_t *lnode = NULL; char *temp = NULL; for (i = 1; i <= net->Njuncs; i++) @@ -341,11 +341,15 @@ int saveinpfile(Project *pr, const char *fname) node = &net->Node[i]; if (dlist = node->D) { for (lnode = first_list(dlist); done_list(lnode); lnode = next_list(lnode)) { - sprintf(s, " %-31s %14.6f", node->ID, ucf * get_base_demand(lnode)); - if ((j = get_pattern_index(lnode)) > 0) sprintf(s1, " %-31s", net->Pattern[j].ID); - else strcpy(s1, " "); + + if + ((j = get_pattern_index(lnode)) > 0) sprintf(s1, " %-31s", net->Pattern[j].ID); + else + strcpy(s1, " "); + fprintf(f, "\n%s %-31s", s, s1); + if (temp = get_category_name(lnode)) { fprintf(f, " ;%s", temp); free(temp); diff --git a/tests/test_demand_data.cpp b/tests/test_demand_data.cpp index 80b6cb0..616dc6f 100644 --- a/tests/test_demand_data.cpp +++ b/tests/test_demand_data.cpp @@ -128,12 +128,12 @@ BOOST_FIXTURE_TEST_CASE(test_category_getset, Fixture) char *name = NULL; name = get_category_name(lnode); - BOOST_CHECK(check_string(name, "CUB_SCOUT_BASE_CAMP")); + BOOST_CHECK(check_string(name, (char *)"CUB_SCOUT_BASE_CAMP")); free(name); name = NULL; - set_category_name(lnode, "CUB_SCOUT_COMMAND"); + set_category_name(lnode, (char *)"CUB_SCOUT_COMMAND"); name = get_category_name(lnode); BOOST_CHECK(check_string(name, "CUB_SCOUT_COMMAND")); @@ -258,7 +258,7 @@ BOOST_FIXTURE_TEST_CASE(test_pattern_edits, FixtureSingleNode) error = EN_addpattern(ph, (char *)"Pat3"); BOOST_REQUIRE(error == 0); - error = EN_getpatternindex(ph, "Pat3", &pat3_idx); + error = EN_getpatternindex(ph, (char *)"Pat3", &pat3_idx); BOOST_REQUIRE(error == 0); double f2[] = { 2.1, 2.2 }; From e2e12fab229cbac4e3f544db02315836c584a1dc Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Fri, 19 Apr 2019 21:51:55 -0400 Subject: [PATCH 15/36] Cleaning up gcc build --- src/demand.c | 6 +++--- src/demand.h | 6 +++--- src/inpfile.c | 9 ++++----- tests/test_demand_data.cpp | 2 +- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/demand.c b/src/demand.c index 48a7980..eecec99 100644 --- a/src/demand.c +++ b/src/demand.c @@ -33,7 +33,7 @@ typedef struct demand_data_s -list_t *create_demand_list(double base_demand, int pattern_index, char *category_name) +list_t *create_demand_list(double base_demand, int pattern_index, const char *category_name) { list_t *demand_list; demand_data_t *demand_data; @@ -50,7 +50,7 @@ list_t *create_demand_list(double base_demand, int pattern_index, char *category } -demand_data_t *create_demand_data(double base_demand, int pattern_index, char *category_name) +demand_data_t *create_demand_data(double base_demand, int pattern_index, const char *category_name) { demand_data_t *demand_data = (demand_data_t *)malloc(sizeof(demand_data_t)); @@ -122,7 +122,7 @@ char *get_category_name(list_node_t *lnode) return strdup(get_demand_data(lnode)->category_name); } -void set_category_name(list_node_t *lnode, char *category_name) +void set_category_name(list_node_t *lnode, const char *category_name) { free(get_demand_data(lnode)->category_name); get_demand_data(lnode)->category_name = strdup(category_name); diff --git a/src/demand.h b/src/demand.h index fcc7826..72dd3d8 100644 --- a/src/demand.h +++ b/src/demand.h @@ -29,10 +29,10 @@ typedef struct demand_data_s demand_data_t; // demand list gets declared in types.h struct Snode -list_t *create_demand_list(double base_demand, int pattern_index, char *category_name); +list_t *create_demand_list(double base_demand, int pattern_index, const char *category_name); -demand_data_t *create_demand_data(double base_demand, int pat_index, char *cat_name); +demand_data_t *create_demand_data(double base_demand, int pat_index, const char *cat_name); void delete_demand_data(void *data); @@ -49,7 +49,7 @@ int get_pattern_index(list_node_t *lnode); void set_pattern_index(list_node_t *lnode, int pattern_index); char *get_category_name(list_node_t *lnode); -void set_category_name(list_node_t *lnode, char *category_name); +void set_category_name(list_node_t *lnode, const char *category_name); // Make this private? demand_data_t *get_demand_data(list_node_t *lnode); diff --git a/src/inpfile.c b/src/inpfile.c index 6e668e9..3f6646f 100644 --- a/src/inpfile.c +++ b/src/inpfile.c @@ -332,15 +332,14 @@ int saveinpfile(Project *pr, const char *fname) fprintf(f, s_DEMANDS); ucf = pr->Ucf[DEMAND]; - list_t *dlist = NULL; + //list_t *dlist = NULL; list_node_t *lnode = NULL; char *temp = NULL; - for (i = 1; i <= net->Njuncs; i++) - { + for (i = 1; i <= net->Njuncs; i++) { node = &net->Node[i]; - if (dlist = node->D) { - for (lnode = first_list(dlist); done_list(lnode); lnode = next_list(lnode)) { + if (node->D) { + for (lnode = first_list(node->D); done_list(lnode); lnode = next_list(lnode)) { sprintf(s, " %-31s %14.6f", node->ID, ucf * get_base_demand(lnode)); if diff --git a/tests/test_demand_data.cpp b/tests/test_demand_data.cpp index 616dc6f..74cbf7a 100644 --- a/tests/test_demand_data.cpp +++ b/tests/test_demand_data.cpp @@ -253,7 +253,7 @@ BOOST_FIXTURE_TEST_CASE(test_pattern_edits, FixtureSingleNode) BOOST_REQUIRE(error == 0); error = EN_addpattern(ph, (char *)"Pat2"); BOOST_REQUIRE(error == 0); - error = EN_getpatternindex(ph, "Pat2", &pat2_idx); + error = EN_getpatternindex(ph, (char *)"Pat2", &pat2_idx); BOOST_REQUIRE(error == 0); error = EN_addpattern(ph, (char *)"Pat3"); From 17b82bd31fa76233203ea065d66e87b8e386eb2a Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Fri, 19 Apr 2019 21:59:09 -0400 Subject: [PATCH 16/36] Fixing bug --- tests/test_demand_data.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_demand_data.cpp b/tests/test_demand_data.cpp index 74cbf7a..b9f8275 100644 --- a/tests/test_demand_data.cpp +++ b/tests/test_demand_data.cpp @@ -67,7 +67,7 @@ BOOST_AUTO_TEST_CASE (test_create_destroy) BOOST_AUTO_TEST_CASE(test_get_size) { size_t size = get_demand_data_size(); - BOOST_CHECK(size == 8); + BOOST_CHECK(size == sizeof(demand_data_t *)); } From 8761543395e82ab66a0ed4585ed97a17f4500865 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Fri, 19 Apr 2019 22:24:31 -0400 Subject: [PATCH 17/36] Working on gcc bug Tests are passing on Appveyor --- src/inpfile.c | 72 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 29 deletions(-) diff --git a/src/inpfile.c b/src/inpfile.c index 3f6646f..89915a1 100644 --- a/src/inpfile.c +++ b/src/inpfile.c @@ -121,6 +121,45 @@ void saveauxdata(Project *pr, FILE *f) InFile = NULL; } +void write_demands(Project *pr, FILE *f) { + + int i, j; + + Snode *node = NULL; + list_node_t *lnode = NULL; + char *temp = NULL; + + char s[MAXLINE + 1], + s1[MAXLINE + 1]; + + double ucf = pr->Ucf[DEMAND]; + Network *net = &pr->network; + + fprintf(f, "\n\n"); + fprintf(f, s_DEMANDS); + + for (i = 1; i <= net->Njuncs; i++) { + node = &net->Node[i]; + if (node->D) { + for (lnode = first_list(node->D); done_list(lnode); lnode = next_list(lnode)) { + sprintf(s, " %-31s %14.6f", node->ID, ucf * get_base_demand(lnode)); + + if + ((j = get_pattern_index(lnode)) > 0) sprintf(s1, " %-31s", net->Pattern[j].ID); + else + strcpy(s1, " "); + + fprintf(f, "\n%s %-31s", s, s1); + + if (temp = get_category_name(lnode)) { + fprintf(f, " ;%s", temp); + free(temp); + } + } + } + } +} + int saveinpfile(Project *pr, const char *fname) /* ------------------------------------------------- @@ -137,7 +176,7 @@ int saveinpfile(Project *pr, const char *fname) Times *time = &pr->times; int i, j, n; - double d, kc, ke, km, ucf; + double d, kc, ke, km; char s[MAXLINE + 1], s1[MAXLINE + 1], s2[MAXLINE + 1]; //Pdemand demand; Psource source; @@ -327,35 +366,10 @@ int saveinpfile(Project *pr, const char *fname) if (link->Comment) fprintf(f, " ;%s", link->Comment); } + // Write [DEMANDS] section - fprintf(f, "\n\n"); - fprintf(f, s_DEMANDS); - ucf = pr->Ucf[DEMAND]; - - //list_t *dlist = NULL; - list_node_t *lnode = NULL; - char *temp = NULL; - - for (i = 1; i <= net->Njuncs; i++) { - node = &net->Node[i]; - if (node->D) { - for (lnode = first_list(node->D); done_list(lnode); lnode = next_list(lnode)) { - sprintf(s, " %-31s %14.6f", node->ID, ucf * get_base_demand(lnode)); - - if - ((j = get_pattern_index(lnode)) > 0) sprintf(s1, " %-31s", net->Pattern[j].ID); - else - strcpy(s1, " "); - - fprintf(f, "\n%s %-31s", s, s1); - - if (temp = get_category_name(lnode)) { - fprintf(f, " ;%s", temp); - free(temp); - } - } - } - } + write_demands(pr, f); + // Write [EMITTERS] section fprintf(f, "\n\n"); From 6a084cc764c95e2d371b60a7ddc60bc932633b92 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Fri, 19 Apr 2019 22:35:15 -0400 Subject: [PATCH 18/36] Update inpfile.c Trying to isolate bug --- src/inpfile.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/inpfile.c b/src/inpfile.c index 89915a1..a36bc67 100644 --- a/src/inpfile.c +++ b/src/inpfile.c @@ -121,8 +121,8 @@ void saveauxdata(Project *pr, FILE *f) InFile = NULL; } -void write_demands(Project *pr, FILE *f) { - + +void write_demands(Project *pr, FILE *f) { int i, j; Snode *node = NULL; @@ -142,24 +142,27 @@ void write_demands(Project *pr, FILE *f) { node = &net->Node[i]; if (node->D) { for (lnode = first_list(node->D); done_list(lnode); lnode = next_list(lnode)) { - sprintf(s, " %-31s %14.6f", node->ID, ucf * get_base_demand(lnode)); + if (lnode) { + sprintf(s, " %-31s %14.6f", node->ID, ucf * get_base_demand(lnode)); - if - ((j = get_pattern_index(lnode)) > 0) sprintf(s1, " %-31s", net->Pattern[j].ID); - else - strcpy(s1, " "); + if + ((j = get_pattern_index(lnode)) > 0) sprintf(s1, " %-31s", net->Pattern[j].ID); + else + strcpy(s1, " "); - fprintf(f, "\n%s %-31s", s, s1); + fprintf(f, "\n%s %-31s", s, s1); - if (temp = get_category_name(lnode)) { - fprintf(f, " ;%s", temp); - free(temp); + if (temp = get_category_name(lnode)) { + fprintf(f, " ;%s", temp); + free(temp); + } } } } } } + int saveinpfile(Project *pr, const char *fname) /* ------------------------------------------------- From f05746cea21f0fe3c3f86d8a043f97d3c1cffa0e Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Fri, 19 Apr 2019 22:56:08 -0400 Subject: [PATCH 19/36] GCC Bug --- src/demand.c | 4 ++-- src/inpfile.c | 20 +++++++++----------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/demand.c b/src/demand.c index eecec99..5c58712 100644 --- a/src/demand.c +++ b/src/demand.c @@ -24,7 +24,7 @@ #include "demand.h" -typedef struct demand_data_s +typedef struct demand_data_s { double base_demand; int pattern_index; @@ -60,7 +60,7 @@ demand_data_t *create_demand_data(double base_demand, int pattern_index, const c if (category_name) demand_data->category_name = strdup(category_name); else - demand_data->category_name = NULL; + demand_data->category_name = '\0'; return demand_data; } diff --git a/src/inpfile.c b/src/inpfile.c index a36bc67..a352e1d 100644 --- a/src/inpfile.c +++ b/src/inpfile.c @@ -142,20 +142,18 @@ void write_demands(Project *pr, FILE *f) { node = &net->Node[i]; if (node->D) { for (lnode = first_list(node->D); done_list(lnode); lnode = next_list(lnode)) { - if (lnode) { - sprintf(s, " %-31s %14.6f", node->ID, ucf * get_base_demand(lnode)); + sprintf(s, " %-31s %14.6f", node->ID, ucf * 100.0); // get_base_demand(lnode)); - if - ((j = get_pattern_index(lnode)) > 0) sprintf(s1, " %-31s", net->Pattern[j].ID); - else - strcpy(s1, " "); + if + ((j = get_pattern_index(lnode)) > 0) sprintf(s1, " %-31s", net->Pattern[j].ID); + else + strcpy(s1, " "); - fprintf(f, "\n%s %-31s", s, s1); + fprintf(f, "\n%s %-31s", s, s1); - if (temp = get_category_name(lnode)) { - fprintf(f, " ;%s", temp); - free(temp); - } + if (temp = get_category_name(lnode)) { + fprintf(f, " ;%s", temp); + free(temp); } } } From b80b4ed09cf26350e96c2c6faa1015bc32d42fd6 Mon Sep 17 00:00:00 2001 From: michaeltryby Date: Mon, 22 Apr 2019 10:52:04 -0400 Subject: [PATCH 20/36] Update inpfile.c Testing linux build --- src/inpfile.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/inpfile.c b/src/inpfile.c index a36bc67..2024f90 100644 --- a/src/inpfile.c +++ b/src/inpfile.c @@ -122,14 +122,14 @@ void saveauxdata(Project *pr, FILE *f) } -void write_demands(Project *pr, FILE *f) { +void write_demands(Project *pr, FILE *f) { int i, j; - + Snode *node = NULL; list_node_t *lnode = NULL; char *temp = NULL; - - char s[MAXLINE + 1], + + char s[MAXLINE + 1], s1[MAXLINE + 1]; double ucf = pr->Ucf[DEMAND]; @@ -152,10 +152,10 @@ void write_demands(Project *pr, FILE *f) { fprintf(f, "\n%s %-31s", s, s1); - if (temp = get_category_name(lnode)) { - fprintf(f, " ;%s", temp); - free(temp); - } + //if (temp = get_category_name(lnode)) { + // fprintf(f, " ;%s", temp); + // free(temp); + //} } } } @@ -372,7 +372,7 @@ int saveinpfile(Project *pr, const char *fname) // Write [DEMANDS] section write_demands(pr, f); - + // Write [EMITTERS] section fprintf(f, "\n\n"); From 97f70e445df22e0c1fd5788343169e77a9222479 Mon Sep 17 00:00:00 2001 From: michaeltryby Date: Mon, 22 Apr 2019 11:07:01 -0400 Subject: [PATCH 21/36] Update epanet.c Trying to isolate bug --- src/epanet.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/src/epanet.c b/src/epanet.c index 407a5ff..2d3eb0a 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -2851,7 +2851,7 @@ int DLLEXPORT EN_getdemandname(EN_Project p, int nodeIndex, int demandIndex, { //Pdemand d; //int n = 1; - char *temp = NULL; + char *temp = NULL; strcpy(demandName, ""); @@ -2860,23 +2860,19 @@ int DLLEXPORT EN_getdemandname(EN_Project p, int nodeIndex, int demandIndex, if (nodeIndex <= 0 || nodeIndex > p->network.Njuncs) return 203; // Locate demand category record and retrieve its name - list_t *dlist = p->network.Node[nodeIndex].D; - list_node_t *lnode = get_nth_list(dlist, demandIndex); - if (!lnode) - return 253; - else - temp = get_category_name(lnode); - - //for (d = p->network.Node[nodeIndex].D; - // n < demandIndex && d->next != NULL; d = d->next) n++; - //if (n != demandIndex) return 253; - - if (temp) { - strcpy(demandName, temp); - //else demandName[0] = '\0'; - free(temp); - } + list_t *dlist = p->network.Node[nodeIndex].D; + if (dlist) { + list_node_t *lnode = get_nth_list(dlist, demandIndex); + if (!lnode) + return 253; + else + temp = get_category_name(lnode); + if (temp) { + strcpy(demandName, temp); + free(temp); + } + } return 0; } @@ -2938,7 +2934,7 @@ int DLLEXPORT EN_getdemandpattern(EN_Project p, int nodeIndex, int demandIndex, // Check for valid arguments if (!p->Openflag) return 102; if (nodeIndex <= 0 || nodeIndex > p->network.Nnodes) return 203; - + // Locate demand category record and assign demandName to it list_t *dlist = p->network.Node[nodeIndex].D; list_node_t *lnode = get_nth_list(dlist, demandIndex); From d34ac67172a1e10ce7fbd65a08b5de15bbe167cd Mon Sep 17 00:00:00 2001 From: michaeltryby Date: Mon, 22 Apr 2019 12:14:33 -0400 Subject: [PATCH 22/36] updating get demand name and write demands Everything passing locally --- src/epanet.c | 2 ++ src/inpfile.c | 58 +++++++++++++++++++++++++-------------------------- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/src/epanet.c b/src/epanet.c index 2d3eb0a..6500421 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -2873,6 +2873,8 @@ int DLLEXPORT EN_getdemandname(EN_Project p, int nodeIndex, int demandIndex, free(temp); } } + else return 253; + return 0; } diff --git a/src/inpfile.c b/src/inpfile.c index 2024f90..a0d0f82 100644 --- a/src/inpfile.c +++ b/src/inpfile.c @@ -123,43 +123,43 @@ void saveauxdata(Project *pr, FILE *f) void write_demands(Project *pr, FILE *f) { - int i, j; + int i, j; - Snode *node = NULL; - list_node_t *lnode = NULL; - char *temp = NULL; + Snode *node = NULL; + list_node_t *lnode = NULL; + char *temp = NULL; - char s[MAXLINE + 1], - s1[MAXLINE + 1]; + char s[MAXLINE + 1], + s1[MAXLINE + 1]; - double ucf = pr->Ucf[DEMAND]; - Network *net = &pr->network; + double ucf = pr->Ucf[DEMAND]; + Network *net = &pr->network; - fprintf(f, "\n\n"); - fprintf(f, s_DEMANDS); + fprintf(f, "\n\n"); + fprintf(f, s_DEMANDS); - for (i = 1; i <= net->Njuncs; i++) { - node = &net->Node[i]; - if (node->D) { - for (lnode = first_list(node->D); done_list(lnode); lnode = next_list(lnode)) { - if (lnode) { - sprintf(s, " %-31s %14.6f", node->ID, ucf * get_base_demand(lnode)); + for (i = 1; i <= net->Njuncs; i++) { + node = &net->Node[i]; + if (node->D) { + for (lnode = first_list(node->D); done_list(lnode); lnode = next_list(lnode)) { + if (lnode) { + sprintf(s, " %-31s %14.6f", node->ID, ucf * get_base_demand(lnode)); - if - ((j = get_pattern_index(lnode)) > 0) sprintf(s1, " %-31s", net->Pattern[j].ID); - else - strcpy(s1, " "); + if + ((j = get_pattern_index(lnode)) > 0) sprintf(s1, " %-31s", net->Pattern[j].ID); + else + strcpy(s1, " "); - fprintf(f, "\n%s %-31s", s, s1); + fprintf(f, "\n%s %-31s", s, s1); - //if (temp = get_category_name(lnode)) { - // fprintf(f, " ;%s", temp); - // free(temp); - //} - } - } - } - } + if (temp = get_category_name(lnode)) { + fprintf(f, " ;%s", temp); + free(temp); + } + } + } + } + } } From ca097a948bea9fd7ee8110e712f6f8935293f55d Mon Sep 17 00:00:00 2001 From: michaeltryby Date: Mon, 22 Apr 2019 12:22:15 -0400 Subject: [PATCH 23/36] Update test_project.cpp Isolating bug on gcc --- tests/test_project.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_project.cpp b/tests/test_project.cpp index 098f8f4..c0223cc 100644 --- a/tests/test_project.cpp +++ b/tests/test_project.cpp @@ -78,10 +78,10 @@ BOOST_AUTO_TEST_CASE(test_save) error = EN_open(ph_save, DATA_PATH_NET1, DATA_PATH_RPT, DATA_PATH_OUT); BOOST_REQUIRE(error == 0); - error = EN_saveinpfile(ph_save, "test_reopen.inp"); - BOOST_REQUIRE(error == 0); +// error = EN_saveinpfile(ph_save, "test_reopen.inp"); +// BOOST_REQUIRE(error == 0); - BOOST_CHECK(boost::filesystem::exists("test_reopen.inp") == true); +// BOOST_CHECK(boost::filesystem::exists("test_reopen.inp") == true); error = EN_close(ph_save); BOOST_REQUIRE(error == 0); From c98a43e72c0de30260a0a52ca980c7066f5ca859 Mon Sep 17 00:00:00 2001 From: michaeltryby Date: Mon, 22 Apr 2019 12:47:52 -0400 Subject: [PATCH 24/36] Isolating bug Not writing demand section of input file should eliminate it --- src/inpfile.c | 2 +- tests/test_demand.cpp | 14 +++++++------- tests/test_project.cpp | 10 +++++----- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/inpfile.c b/src/inpfile.c index a0d0f82..c937196 100644 --- a/src/inpfile.c +++ b/src/inpfile.c @@ -371,7 +371,7 @@ int saveinpfile(Project *pr, const char *fname) // Write [DEMANDS] section - write_demands(pr, f); + //write_demands(pr, f); // Write [EMITTERS] section diff --git a/tests/test_demand.cpp b/tests/test_demand.cpp index 1ef0cf3..07a597d 100644 --- a/tests/test_demand.cpp +++ b/tests/test_demand.cpp @@ -66,15 +66,15 @@ BOOST_AUTO_TEST_CASE(test_categories_reopen, * boost::unit_test::depends_on("tes error = EN_getnodeindex(ph, (char *)"12", &Nindex); BOOST_REQUIRE(error == 0); - error = EN_getnumdemands(ph, Nindex, &ndem); - BOOST_REQUIRE(error == 0); - BOOST_CHECK(ndem == 1); + //error = EN_getnumdemands(ph, Nindex, &ndem); + //BOOST_REQUIRE(error == 0); + //BOOST_CHECK(ndem == 1); - char demname[31]; - error = EN_getdemandname(ph, Nindex, ndem, demname); - BOOST_REQUIRE(error == 0); + //char demname[31]; + //error = EN_getdemandname(ph, Nindex, ndem, demname); + //BOOST_CHECK(error == 0); - BOOST_CHECK(check_string(demname, "CUB_SCOUT_MOTOR_POOL")); + //BOOST_CHECK(check_string(demname, "CUB_SCOUT_MOTOR_POOL")); error = EN_close(ph); BOOST_REQUIRE(error == 0); diff --git a/tests/test_project.cpp b/tests/test_project.cpp index c0223cc..dd0c3b7 100644 --- a/tests/test_project.cpp +++ b/tests/test_project.cpp @@ -78,13 +78,13 @@ BOOST_AUTO_TEST_CASE(test_save) error = EN_open(ph_save, DATA_PATH_NET1, DATA_PATH_RPT, DATA_PATH_OUT); BOOST_REQUIRE(error == 0); -// error = EN_saveinpfile(ph_save, "test_reopen.inp"); -// BOOST_REQUIRE(error == 0); + error = EN_saveinpfile(ph_save, "test_reopen.inp"); + BOOST_REQUIRE(error == 0); -// BOOST_CHECK(boost::filesystem::exists("test_reopen.inp") == true); + BOOST_CHECK(boost::filesystem::exists("test_reopen.inp") == true); - error = EN_close(ph_save); - BOOST_REQUIRE(error == 0); + error = EN_close(ph_save); + BOOST_REQUIRE(error == 0); EN_deleteproject(&ph_save); } From 60853ecb15b978fba7f39dbc84a0b3d360c71b0c Mon Sep 17 00:00:00 2001 From: michaeltryby Date: Mon, 22 Apr 2019 13:08:43 -0400 Subject: [PATCH 25/36] Update demand.c Fixing bug in get_category_name when category_name is NULL --- src/demand.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/demand.c b/src/demand.c index eecec99..510e97d 100644 --- a/src/demand.c +++ b/src/demand.c @@ -67,7 +67,7 @@ demand_data_t *create_demand_data(double base_demand, int pattern_index, const c void delete_demand_data(void *data) { - // TODO: This cast is a problem! + // TODO: This cast is a problem! demand_data_t *demand_data = *(demand_data_t **)data; if (demand_data->category_name) @@ -119,7 +119,12 @@ void set_pattern_index(list_node_t *lnode, int pattern_index) char *get_category_name(list_node_t *lnode) // Be advised: caller must free memory returned { - return strdup(get_demand_data(lnode)->category_name); + char *temp = get_demand_data(lnode)->category_name; + + if (temp) + return strdup(temp); + else + return NULL; } void set_category_name(list_node_t *lnode, const char *category_name) From ce70d144ceae73b8dc78740cd81557d4a82c4a57 Mon Sep 17 00:00:00 2001 From: michaeltryby Date: Mon, 22 Apr 2019 13:13:38 -0400 Subject: [PATCH 26/36] Restoring write_demands section in saveinpfile --- src/inpfile.c | 2 +- tests/test_demand.cpp | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/inpfile.c b/src/inpfile.c index c937196..be24616 100644 --- a/src/inpfile.c +++ b/src/inpfile.c @@ -371,7 +371,7 @@ int saveinpfile(Project *pr, const char *fname) // Write [DEMANDS] section - //write_demands(pr, f); + write_demands(pr, f); // Write [EMITTERS] section diff --git a/tests/test_demand.cpp b/tests/test_demand.cpp index 07a597d..d9b0e69 100644 --- a/tests/test_demand.cpp +++ b/tests/test_demand.cpp @@ -66,15 +66,15 @@ BOOST_AUTO_TEST_CASE(test_categories_reopen, * boost::unit_test::depends_on("tes error = EN_getnodeindex(ph, (char *)"12", &Nindex); BOOST_REQUIRE(error == 0); - //error = EN_getnumdemands(ph, Nindex, &ndem); - //BOOST_REQUIRE(error == 0); - //BOOST_CHECK(ndem == 1); + error = EN_getnumdemands(ph, Nindex, &ndem); + BOOST_REQUIRE(error == 0); + BOOST_CHECK(ndem == 1); - //char demname[31]; - //error = EN_getdemandname(ph, Nindex, ndem, demname); - //BOOST_CHECK(error == 0); + char demname[31]; + error = EN_getdemandname(ph, Nindex, ndem, demname); + BOOST_CHECK(error == 0); - //BOOST_CHECK(check_string(demname, "CUB_SCOUT_MOTOR_POOL")); + BOOST_CHECK(check_string(demname, "CUB_SCOUT_MOTOR_POOL")); error = EN_close(ph); BOOST_REQUIRE(error == 0); From a0048b7b0913c83d87f6b51c04058101a9258bcc Mon Sep 17 00:00:00 2001 From: michaeltryby Date: Mon, 22 Apr 2019 13:37:41 -0400 Subject: [PATCH 27/36] Update test_demand_data.cpp Adding index to addnode calls. Fixing indent --- tests/test_demand_data.cpp | 316 ++++++++++++++++++------------------- 1 file changed, 158 insertions(+), 158 deletions(-) diff --git a/tests/test_demand_data.cpp b/tests/test_demand_data.cpp index b9f8275..82fab3e 100644 --- a/tests/test_demand_data.cpp +++ b/tests/test_demand_data.cpp @@ -1,14 +1,14 @@ /* - ****************************************************************************** - Project: OWA EPANET - Version: 2.2 - Module: /test_demand_data.cpp - Description: tests demand data list node struct - Authors: see AUTHORS - Copyright: see AUTHORS - License: see LICENSE - Last Updated: 04/18/2019 - ****************************************************************************** +****************************************************************************** +Project: OWA EPANET +Version: 2.2 +Module: /test_demand_data.cpp +Description: tests demand data list node struct +Authors: see AUTHORS +Copyright: see AUTHORS +License: see LICENSE +Last Updated: 04/18/2019 +****************************************************************************** */ #define BOOST_TEST_MODULE demand_data @@ -26,10 +26,10 @@ boost::test_tools::predicate_result check_string(std::string test, std::string ref) { - if (ref.compare(test) == 0) - return true; - else - return false; + if (ref.compare(test) == 0) + return true; + else + return false; } @@ -38,12 +38,12 @@ BOOST_AUTO_TEST_SUITE(test_demand_data) BOOST_AUTO_TEST_CASE(test_create_destroy_demand_list) { - list_t *dlist; + list_t *dlist; - dlist = create_demand_list(100.0, 1, "CUB_SCOUT_DAY_CAMP"); - BOOST_CHECK(dlist != NULL); + dlist = create_demand_list(100.0, 1, "CUB_SCOUT_DAY_CAMP"); + BOOST_CHECK(dlist != NULL); - delete_list(dlist); + delete_list(dlist); } @@ -56,117 +56,117 @@ BOOST_AUTO_TEST_CASE (test_create_destroy) delete_demand_data(&data); - data = NULL; + data = NULL; - data = create_demand_data(100.0, 1, "CUB_SCOUT_BASE_CAMP"); - BOOST_CHECK(data != NULL); + data = create_demand_data(100.0, 1, "CUB_SCOUT_BASE_CAMP"); + BOOST_CHECK(data != NULL); - delete_demand_data(&data); + delete_demand_data(&data); } BOOST_AUTO_TEST_CASE(test_get_size) { - size_t size = get_demand_data_size(); - BOOST_CHECK(size == sizeof(demand_data_t *)); + size_t size = get_demand_data_size(); + BOOST_CHECK(size == sizeof(demand_data_t *)); } struct Fixture { - Fixture() { - _data = NULL; - dlist = NULL; + Fixture() { + _data = NULL; + dlist = NULL; - dlist = create_list(get_demand_data_size(), delete_demand_data); - _data = create_demand_data(100.0, 1, "CUB_SCOUT_BASE_CAMP"); - - append_list(dlist, &_data); - } - ~Fixture() { - delete_list(dlist); - } - demand_data_t *_data; - list_t *dlist; + dlist = create_list(get_demand_data_size(), delete_demand_data); + _data = create_demand_data(100.0, 1, "CUB_SCOUT_BASE_CAMP"); + + append_list(dlist, &_data); + } + ~Fixture() { + delete_list(dlist); + } + demand_data_t *_data; + list_t *dlist; }; BOOST_FIXTURE_TEST_CASE(test_demand_list, Fixture) { - list_node_t *lnode = head_list(dlist, false); - BOOST_CHECK(lnode != NULL); + list_node_t *lnode = head_list(dlist, false); + BOOST_CHECK(lnode != NULL); } BOOST_FIXTURE_TEST_CASE(test_demand_getset, Fixture) { - list_node_t *lnode = head_list(dlist, false); - double demand; + list_node_t *lnode = head_list(dlist, false); + double demand; - demand = get_base_demand(lnode); - BOOST_CHECK(demand == 100.0); + demand = get_base_demand(lnode); + BOOST_CHECK(demand == 100.0); - set_base_demand(lnode, 200.0); + set_base_demand(lnode, 200.0); - demand = get_base_demand(lnode); - BOOST_CHECK(demand == 200.0); + demand = get_base_demand(lnode); + BOOST_CHECK(demand == 200.0); } BOOST_FIXTURE_TEST_CASE(test_pattern_getset, Fixture) { - list_node_t *lnode = head_list(dlist, false); - int index; + list_node_t *lnode = head_list(dlist, false); + int index; - index = get_pattern_index(lnode); - BOOST_CHECK(index == 1); + index = get_pattern_index(lnode); + BOOST_CHECK(index == 1); - set_pattern_index(lnode, 2); + set_pattern_index(lnode, 2); - index = get_pattern_index(lnode); - BOOST_CHECK(index == 2); + index = get_pattern_index(lnode); + BOOST_CHECK(index == 2); } BOOST_FIXTURE_TEST_CASE(test_category_getset, Fixture) { - list_node_t *lnode = head_list(dlist, false); - char *name = NULL; + list_node_t *lnode = head_list(dlist, false); + char *name = NULL; - name = get_category_name(lnode); - BOOST_CHECK(check_string(name, (char *)"CUB_SCOUT_BASE_CAMP")); + name = get_category_name(lnode); + BOOST_CHECK(check_string(name, (char *)"CUB_SCOUT_BASE_CAMP")); - free(name); - name = NULL; + free(name); + name = NULL; - set_category_name(lnode, (char *)"CUB_SCOUT_COMMAND"); + set_category_name(lnode, (char *)"CUB_SCOUT_COMMAND"); - name = get_category_name(lnode); - BOOST_CHECK(check_string(name, "CUB_SCOUT_COMMAND")); + name = get_category_name(lnode); + BOOST_CHECK(check_string(name, "CUB_SCOUT_COMMAND")); - free(name); + free(name); } BOOST_FIXTURE_TEST_CASE(test_convert_demand, Fixture) { - list_node_t *lnode = head_list(dlist, false); - BOOST_CHECK(lnode != NULL); - - // 100.0 GPM == 6.31 LPS - convert_units(lnode, 15.850); - double demand = get_base_demand(lnode); - BOOST_TEST(demand == 6.31, boost::test_tools::tolerance(0.01)); + list_node_t *lnode = head_list(dlist, false); + BOOST_CHECK(lnode != NULL); + + // 100.0 GPM == 6.31 LPS + convert_units(lnode, 15.850); + double demand = get_base_demand(lnode); + BOOST_TEST(demand == 6.31, boost::test_tools::tolerance(0.01)); } BOOST_AUTO_TEST_CASE(test_initclose) { - int error; + int error; - EN_Project ph = NULL; + EN_Project ph = NULL; - EN_createproject(&ph); + EN_createproject(&ph); - error = EN_init(ph, DATA_PATH_RPT, DATA_PATH_OUT, EN_GPM, EN_HW); - BOOST_REQUIRE(error == 0); + error = EN_init(ph, DATA_PATH_RPT, DATA_PATH_OUT, EN_GPM, EN_HW); + BOOST_REQUIRE(error == 0); - error = EN_close(ph); - BOOST_REQUIRE(error == 0); + error = EN_close(ph); + BOOST_REQUIRE(error == 0); - EN_deleteproject(&ph); + EN_deleteproject(&ph); } @@ -177,116 +177,116 @@ BOOST_AUTO_TEST_CASE(test_initclose) struct FixtureSingleNode { - FixtureSingleNode() { - error = 0; - ph = NULL; + FixtureSingleNode() { + error = 0; + ph = NULL; - EN_createproject(&ph); - EN_init(ph, DATA_PATH_RPT, DATA_PATH_OUT, EN_GPM, EN_HW); + EN_createproject(&ph); + EN_init(ph, DATA_PATH_RPT, DATA_PATH_OUT, EN_GPM, EN_HW); - EN_addnode(ph, (char *)"CUB_SCOUT_QUONSET_HUT", EN_JUNCTION); - EN_getnodeindex(ph, (char *)"CUB_SCOUT_QUONSET_HUT", &node_qhut); - } + EN_addnode(ph, (char *)"CUB_SCOUT_QUONSET_HUT", EN_JUNCTION, &node_qhut); + //EN_getnodeindex(ph, (char *)"CUB_SCOUT_QUONSET_HUT", &node_qhut); + } - ~FixtureSingleNode() { - EN_close(ph); - EN_deleteproject(&ph); - } - int error, node_qhut; - EN_Project ph; + ~FixtureSingleNode() { + EN_close(ph); + EN_deleteproject(&ph); + } + int error, index, node_qhut; + EN_Project ph; }; BOOST_FIXTURE_TEST_CASE(test_single_node, FixtureSingleNode) { - int demand_idx, pattern_idx, n; - double demand; + int demand_idx, pattern_idx, n; + double demand; - error = EN_getnumdemands(ph, node_qhut, &n); - BOOST_REQUIRE(error == 0); - BOOST_CHECK(n == 0); + error = EN_getnumdemands(ph, node_qhut, &n); + BOOST_REQUIRE(error == 0); + BOOST_CHECK(n == 0); - demand_idx = 1; - error = EN_getbasedemand(ph, node_qhut, demand_idx, &demand); - BOOST_REQUIRE(error == 253); - - error = EN_getdemandpattern(ph, node_qhut, demand_idx, &pattern_idx); - BOOST_REQUIRE(error == 253); + demand_idx = 1; + error = EN_getbasedemand(ph, node_qhut, demand_idx, &demand); + BOOST_REQUIRE(error == 253); - char demname[31]; - error = EN_getdemandname(ph, node_qhut, demand_idx, demname); - BOOST_REQUIRE(error == 253); - BOOST_CHECK(check_string(demname, "\0")); + error = EN_getdemandpattern(ph, node_qhut, demand_idx, &pattern_idx); + BOOST_REQUIRE(error == 253); - error = EN_setbasedemand(ph, node_qhut, demand_idx, 100.0); - BOOST_REQUIRE(error == 0); + char demname[31]; + error = EN_getdemandname(ph, node_qhut, demand_idx, demname); + BOOST_REQUIRE(error == 253); + BOOST_CHECK(check_string(demname, "\0")); - // only one demand category - pattern_idx = 1; - error = EN_setdemandpattern(ph, node_qhut, demand_idx, pattern_idx); - BOOST_REQUIRE(error == 205); + error = EN_setbasedemand(ph, node_qhut, demand_idx, 100.0); + BOOST_REQUIRE(error == 0); - // create pattern - error = EN_addpattern(ph, (char *)"Pat2"); - BOOST_REQUIRE(error == 0); - error = EN_getpatternindex(ph, (char *)"Pat2", &pattern_idx); - BOOST_REQUIRE(error == 0); + // only one demand category + pattern_idx = 1; + error = EN_setdemandpattern(ph, node_qhut, demand_idx, pattern_idx); + BOOST_REQUIRE(error == 205); - error = EN_setdemandpattern(ph, node_qhut, demand_idx, pattern_idx); - BOOST_REQUIRE(error == 0); + // create pattern + error = EN_addpattern(ph, (char *)"Pat2"); + BOOST_REQUIRE(error == 0); + error = EN_getpatternindex(ph, (char *)"Pat2", &pattern_idx); + BOOST_REQUIRE(error == 0); - error = EN_setdemandname(ph, node_qhut, demand_idx, (char *)"CUB_SCOUT_MESS_HALL"); - BOOST_REQUIRE(error == 0); + error = EN_setdemandpattern(ph, node_qhut, demand_idx, pattern_idx); + BOOST_REQUIRE(error == 0); + + error = EN_setdemandname(ph, node_qhut, demand_idx, (char *)"CUB_SCOUT_MESS_HALL"); + BOOST_REQUIRE(error == 0); } BOOST_FIXTURE_TEST_CASE(test_pattern_edits, FixtureSingleNode) { - int n, node_cpoint, pat2_idx, pat3_idx; + int n, node_cpoint, pat2_idx, pat3_idx; - EN_addnode(ph, (char *)"CUB_SCOUT_CHECKPOINT", EN_JUNCTION); - EN_getnodeindex(ph, (char *)"CUB_SCOUT_CHECKPOINT", &node_cpoint); + EN_addnode(ph, (char *)"CUB_SCOUT_CHECKPOINT", EN_JUNCTION, &node_cpoint); + //EN_getnodeindex(ph, (char *)"CUB_SCOUT_CHECKPOINT", &node_cpoint); - // Add 2 new patterns - error = EN_addpattern(ph, (char *)"DefPat"); - BOOST_REQUIRE(error == 0); - error = EN_addpattern(ph, (char *)"Pat2"); - BOOST_REQUIRE(error == 0); - error = EN_getpatternindex(ph, (char *)"Pat2", &pat2_idx); - BOOST_REQUIRE(error == 0); + // Add 2 new patterns + error = EN_addpattern(ph, (char *)"DefPat"); + BOOST_REQUIRE(error == 0); + error = EN_addpattern(ph, (char *)"Pat2"); + BOOST_REQUIRE(error == 0); + error = EN_getpatternindex(ph, (char *)"Pat2", &pat2_idx); + BOOST_REQUIRE(error == 0); - error = EN_addpattern(ph, (char *)"Pat3"); - BOOST_REQUIRE(error == 0); - error = EN_getpatternindex(ph, (char *)"Pat3", &pat3_idx); - BOOST_REQUIRE(error == 0); + error = EN_addpattern(ph, (char *)"Pat3"); + BOOST_REQUIRE(error == 0); + error = EN_getpatternindex(ph, (char *)"Pat3", &pat3_idx); + BOOST_REQUIRE(error == 0); - double f2[] = { 2.1, 2.2 }; - double f3[] = { 3.1, 3.2, 3.3, 3.4 }; - error = EN_setpattern(ph, pat2_idx, f2, 2); - BOOST_REQUIRE(error == 0); - error = EN_setpattern(ph, pat3_idx, f3, 4); - BOOST_REQUIRE(error == 0); + double f2[] = { 2.1, 2.2 }; + double f3[] = { 3.1, 3.2, 3.3, 3.4 }; + error = EN_setpattern(ph, pat2_idx, f2, 2); + BOOST_REQUIRE(error == 0); + error = EN_setpattern(ph, pat3_idx, f3, 4); + BOOST_REQUIRE(error == 0); - // Assign Pat3 to 3rd junction - error = EN_setdemandpattern(ph, node_cpoint, 1, pat3_idx); - BOOST_REQUIRE(error == 0); + // Assign Pat3 to 3rd junction + error = EN_setdemandpattern(ph, node_cpoint, 1, pat3_idx); + BOOST_REQUIRE(error == 0); - // Delete Pat2 - error = EN_deletepattern(ph, pat2_idx); - BOOST_REQUIRE(error == 0); + // Delete Pat2 + error = EN_deletepattern(ph, pat2_idx); + BOOST_REQUIRE(error == 0); - //Check that there are now 2 patterns - error = EN_getcount(ph, EN_PATCOUNT, &n); - BOOST_REQUIRE(error == 0); - BOOST_CHECK(n == 2); + //Check that there are now 2 patterns + error = EN_getcount(ph, EN_PATCOUNT, &n); + BOOST_REQUIRE(error == 0); + BOOST_CHECK(n == 2); - // Check that Pat3 with 4 factors is still assigned to 3rd junction - error = EN_getdemandpattern(ph, node_cpoint, 1, &pat3_idx); - BOOST_REQUIRE(error == 0); - error = EN_getpatternlen(ph, pat3_idx, &n); - BOOST_REQUIRE(error == 0); - BOOST_CHECK(n == 4); + // Check that Pat3 with 4 factors is still assigned to 3rd junction + error = EN_getdemandpattern(ph, node_cpoint, 1, &pat3_idx); + BOOST_REQUIRE(error == 0); + error = EN_getpatternlen(ph, pat3_idx, &n); + BOOST_REQUIRE(error == 0); + BOOST_CHECK(n == 4); } From 73bc53ad5467a838b6dd5208f001f4e7efebb01f Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 23 Apr 2019 08:51:22 -0400 Subject: [PATCH 28/36] Update demand.c --- src/demand.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/demand.c b/src/demand.c index d730b17..510e97d 100644 --- a/src/demand.c +++ b/src/demand.c @@ -24,7 +24,7 @@ #include "demand.h" -typedef struct demand_data_s +typedef struct demand_data_s { double base_demand; int pattern_index; @@ -60,7 +60,7 @@ demand_data_t *create_demand_data(double base_demand, int pattern_index, const c if (category_name) demand_data->category_name = strdup(category_name); else - demand_data->category_name = '\0'; + demand_data->category_name = NULL; return demand_data; } From 5d3eeb91d9af73ef5da5a21a3584b9287d458788 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 23 Apr 2019 11:44:02 -0400 Subject: [PATCH 29/36] Reverted handling of default pattern When creating demands, no pattern is marked with a zero. Then when data is adjusted it gets updated to default. --- src/input1.c | 25 +++++++++++-------------- src/input3.c | 38 ++------------------------------------ src/project.c | 14 ++++---------- 3 files changed, 17 insertions(+), 60 deletions(-) diff --git a/src/input1.c b/src/input1.c index aafa576..391fc69 100644 --- a/src/input1.c +++ b/src/input1.c @@ -331,20 +331,17 @@ void adjustdata(Project *pr) tank = &net->Tank[i]; if (tank->Kb == MISSING) tank->Kb = qual->Kbulk; } - - // It is expensive to iterate over every demand at every node. - // cheaper to apply default pattern when creating the demand data. - -// // Use default pattern if none assigned to a demand -// parser->DefPat = findpattern(net, parser->DefPatID); -// if (parser->DefPat > 0) for (i = 1; i <= net->Nnodes; i++) -// { -// node = &net->Node[i]; -// for (demand = node->D; demand != NULL; demand = demand->next) -// { -// if (demand->Pat == 0) demand->Pat = parser->DefPat; -// } -// } + + // Use default pattern if none assigned to a demand + parser->DefPat = findpattern(net, parser->DefPatID); + if (parser->DefPat > 0) { + for (i = 1; i <= net->Nnodes; i++) { + for (list_node_t *lnode = first_list((&net->Node[i])->D); done_list(lnode); lnode = next_list(lnode)) { + if (get_pattern_index(lnode) == 0) + set_pattern_index(lnode, parser->DefPat); + } + } + } // Remove QUALITY as a reporting variable if no WQ analysis if (qual->Qualflag == NONE) rpt->Field[QUALITY].Enabled = FALSE; diff --git a/src/input3.c b/src/input3.c index 9837bd4..7951cdf 100644 --- a/src/input3.c +++ b/src/input3.c @@ -124,8 +124,6 @@ int juncdata(Project *pr) // create demand data only if a demand has been specified if (y != 0.0) { - // apply the default demand pattern and append the data - if (p == 0) p = findpattern(net, parser->DefPatID); demand_list = create_demand_list(y, p, NULL); if (!demand_list) return 101; } @@ -752,50 +750,18 @@ int demanddata(Project *pr) net->Node[j].D = demand_list; } - // else delete the demand data in [JUNCTIONS] section + // else replace the demand data entered in [JUNCTIONS] section else if (size_list(demand_list) == 1) { list_node_t *lnode = head_list(demand_list, true); delete_node(demand_list, lnode); } - // apply the default demand pattern and append the data - if (p == 0) p = findpattern(net, parser->DefPatID); + // append the data to the list demand_data = create_demand_data(y, p, parser->Comment); if (demand_data == NULL) return 101; append_list(demand_list, &demand_data); - - // //if (hyd->NodeDemand[j] != MISSING) - // { - // // First category encountered will overwrite "dummy" demand category - // // with what is specified in this section - // demand->Base = y; - // demand->Pat = p; - // if (parser->Comment[0]) - // { - // demand->Name = xstrcpy(&demand->Name, parser->Comment, MAXID); - // } - // hyd->NodeDemand[j] = MISSING; // marker - next iteration will append a new category. - // } - // - // // Otherwise add new demand to junction - // else - // { - // cur_demand = net->Node[j].D; - // while (cur_demand->next != NULL) cur_demand = cur_demand->next; - // demand = (struct Sdemand *)malloc(sizeof(struct Sdemand)); - // if (demand == NULL) return 101; - // demand->Base = y; - // demand->Pat = p; - // demand->Name = NULL; - // if (parser->Comment[0]) - // { - // demand->Name = xstrcpy(&demand->Name, parser->Comment, MAXID); - // } - // demand->next = NULL; - // cur_demand->next = demand; - // } return 0; } diff --git a/src/project.c b/src/project.c index 8e44be7..1df2911 100644 --- a/src/project.c +++ b/src/project.c @@ -409,13 +409,7 @@ void freedata(Project *pr) list_t *demand = pr->network.Node[j].D; if(demand) delete_list(demand); - /*while (demand != NULL) - { - nextdemand = demand->next; - free(demand->Name); - free(demand); - demand = nextdemand; - }*/ + // Free memory used for WQ source data free(pr->network.Node[j].S); free(pr->network.Node[j].Comment); @@ -797,8 +791,8 @@ void adjustpattern(int *pat, int index) } -void _adjustpattern(list_node_t *lnode, int del_idx) -{ +void adjust_demand_pattern(list_node_t *lnode, int del_idx) +{ int pat_idx = get_pattern_index(lnode); if (pat_idx == del_idx) set_pattern_index(lnode, 0); @@ -825,7 +819,7 @@ void adjustpatterns(Network *network, int index) list_t *dlist = network->Node[j].D; if (dlist) { for (list_node_t *lnode = first_list(dlist); done_list(lnode); lnode = next_list(lnode)) - _adjustpattern(lnode, index); + adjust_demand_pattern(lnode, index); } // Adjust WQ source patterns source = network->Node[j].S; From feee7f2c80e7edab48636e899357a3f2b84109d0 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 23 Apr 2019 14:42:37 -0400 Subject: [PATCH 30/36] Update epanet.c Updating EN_getnodevalue() and EN_setnodevalue() to process the primary demand located at the head of the demand list --- src/epanet.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/epanet.c b/src/epanet.c index 75654f8..0cc926c 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -2107,16 +2107,12 @@ int DLLEXPORT EN_getnodevalue(EN_Project p, int index, int property, double *val case EN_PATTERN: v = 0.0; - // NOTE: primary demand category is last on demand list + // NOTE: primary demand category is first on demand list if (index <= nJuncs) { list_t *demand = Node[index].D; if (demand) - v = get_pattern_index(tail_list(demand)); - //for (demand = Node[index].D; demand != NULL; demand = demand->next) - //{ - // v = (double)(demand->Pat); - //} + v = get_pattern_index(head_list(demand, false)); } else v = (double)(Tank[index - nJuncs].Pat); break; @@ -2294,24 +2290,24 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int property, double valu break; case EN_BASEDEMAND: - // NOTE: primary demand category is last on demand list + // NOTE: primary demand category is first on demand list if (index <= nJuncs) { list_t *demand = Node[index].D; if (demand) - set_base_demand(tail_list(demand), value / Ucf[FLOW]); + set_base_demand(head_list(demand, false), value / Ucf[FLOW]); } break; case EN_PATTERN: - // NOTE: primary demand category is last on demand list + // NOTE: primary demand category is first on demand list j = ROUND(value); if (j < 0 || j > nPats) return 205; if (index <= nJuncs) { list_t *demand = Node[index].D; if (demand) - set_pattern_index(tail_list(demand), j); + set_pattern_index(head_list(demand, false), j); } else Tank[index - nJuncs].Pat = j; break; From 900813367e1537fdebc4d461bbb72c2e7b038207 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 23 Apr 2019 14:44:11 -0400 Subject: [PATCH 31/36] Update demand.c --- src/demand.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/demand.c b/src/demand.c index 510e97d..6f005c4 100644 --- a/src/demand.c +++ b/src/demand.c @@ -66,8 +66,7 @@ demand_data_t *create_demand_data(double base_demand, int pattern_index, const c } void delete_demand_data(void *data) -{ - // TODO: This cast is a problem! +{ demand_data_t *demand_data = *(demand_data_t **)data; if (demand_data->category_name) From cf97cf8c9ca0cda4f732b5bc43d6f9e9d23307cc Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Tue, 23 Apr 2019 17:52:11 -0400 Subject: [PATCH 32/36] Work in progress code cleanup, addressed issue raised in review, and implemented EN_adddemand() --- include/epanet2_2.h | 11 ++++- src/epanet.c | 83 +++++++++++++++++++++++++------------- src/project.c | 18 ++++----- tests/test_demand.cpp | 14 +++++++ tests/test_demand_data.cpp | 1 + tests/test_toolkit.hpp | 20 +++++++++ 6 files changed, 108 insertions(+), 39 deletions(-) diff --git a/include/epanet2_2.h b/include/epanet2_2.h index 051e623..67bf91a 100644 --- a/include/epanet2_2.h +++ b/include/epanet2_2.h @@ -165,7 +165,7 @@ typedef struct Project *EN_Project; @return an error code */ int DLLEXPORT EN_setcomment(EN_Project ph, int object, int index, char *comment); - + /** @brief Retrieves the number of objects of a given type in a project. @param ph an EPANET project handle. @@ -851,7 +851,14 @@ typedef struct Project *EN_Project; These properties have units that depend on the units used for flow rate (see @ref Units). */ int DLLEXPORT EN_setjuncdata(EN_Project ph, int index, double elev, double dmnd, - char *dmndpat); + char *dmndpat); + + + int DLLEXPORT EN_adddemand(EN_Project p, int node_index, double demand, + char *demand_pattern, const char *category_name, int *demand_index); + + int DLLEXPORT EN_removedemand(EN_Project p, int node_index, int demand_index); + /** @brief Sets a group of properties for a tank node. diff --git a/src/epanet.c b/src/epanet.c index 0cc926c..3138be3 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -1888,15 +1888,9 @@ int DLLEXPORT EN_deletenode(EN_Project p, int index, int actionCode) // Free memory allocated to node's demands, WQ source & comment demand = node->D; - if (demand) - delete_list(demand); -// while (demand != NULL) - // { - // nextdemand = demand->next; - // free(demand->Name); - // free(demand); - // demand = nextdemand; - // } + if (demand) + delete_list(demand); + free(node->S); free(node->Comment); @@ -2063,7 +2057,6 @@ int DLLEXPORT EN_getnodevalue(EN_Project p, int index, int property, double *val Quality *qual = &p->quality; double v = 0.0; - //Pdemand demand; Psource source; Snode *Node = net->Node; @@ -2090,17 +2083,12 @@ int DLLEXPORT EN_getnodevalue(EN_Project p, int index, int property, double *val case EN_BASEDEMAND: v = 0.0; - // NOTE: primary demand category is last on demand list + // NOTE: primary demand category is first on demand list if (index <= nJuncs) { - list_t *demand = Node[index].D; - if (demand) - v = get_base_demand(tail_list(demand)); - - //for (demand = Node[index].D; demand != NULL; demand = demand->next) - //{ - // v = (demand->Base); - //} + list_t *demand = Node[index].D; + if (demand) + v = get_base_demand(head_list(demand, false)); } v *= Ucf[FLOW]; break; @@ -2110,9 +2098,9 @@ int DLLEXPORT EN_getnodevalue(EN_Project p, int index, int property, double *val // NOTE: primary demand category is first on demand list if (index <= nJuncs) { - list_t *demand = Node[index].D; - if (demand) - v = get_pattern_index(head_list(demand, false)); + list_t *demand = Node[index].D; + if (demand) + v = get_pattern_index(head_list(demand, false)); } else v = (double)(Tank[index - nJuncs].Pat); break; @@ -2267,7 +2255,6 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int property, double valu double *Ucf = p->Ucf; int i, j, n; -// Pdemand demand; Psource source; double hTmp; @@ -2293,9 +2280,9 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int property, double valu // NOTE: primary demand category is first on demand list if (index <= nJuncs) { - list_t *demand = Node[index].D; - if (demand) - set_base_demand(head_list(demand, false), value / Ucf[FLOW]); + list_t *demand = Node[index].D; + if (demand) + set_base_demand(head_list(demand, false), value / Ucf[FLOW]); } break; @@ -2504,7 +2491,6 @@ int DLLEXPORT EN_setjuncdata(EN_Project p, int index, double elev, int i, patIndex = 0; Snode *Node = net->Node; - //Pdemand demand; // Check that junction exists if (!p->Openflag) return 102; @@ -2532,7 +2518,7 @@ int DLLEXPORT EN_setjuncdata(EN_Project p, int index, double elev, demand_list = create_list(get_demand_data_size(), delete_demand_data); if (!demand_list) return 101; } - demand_data_t *demand_data = create_demand_data(dmnd / p->Ucf[FLOW], patIndex, NULL); + demand_data_t *demand_data = create_demand_data(dmnd/p->Ucf[FLOW], patIndex, NULL); if (!demand_data) return 101; append_list(demand_list, &demand_data); @@ -2540,6 +2526,47 @@ int DLLEXPORT EN_setjuncdata(EN_Project p, int index, double elev, return 0; } +int DLLEXPORT EN_adddemand(EN_Project p, int node_index, double demand, + char *demand_pattern, const char *category_name, int *demand_index) +{ + Network *net = &p->network; + + int pattern_index, error = 0; + *demand_index = -1; + + if (error = EN_getpatternindex(p, demand_pattern, &pattern_index) != 0) return error; + + Snode *Node = net->Node; + list_t *demand_list = Node[node_index].D; + if (!demand_list) { + demand_list = create_demand_list(demand/p->Ucf[FLOW], pattern_index, category_name); + if (!demand_list) return 101; + + Node[node_index].D = demand_list; + } + else { + demand_data_t *demand_data = create_demand_data(demand/p->Ucf[FLOW], pattern_index, category_name); + if (!demand_data) return 101; + + append_list(demand_list, &demand_data); + } + + *demand_index = size_list(demand_list); + return 0; +} + +int DLLEXPORT EN_removedemand(EN_Project p, int node_index, int demand_index) { + // Problem: Removing a demand will in most cases invalidate the index + // returned previously in EN_adddemand(). This occurs in all cases except + // when the demand at the tail of the list is removed. This is why indexing + // is a flawed strategy for random access to a list data structure. + // One possible solution is to have the user be responsible for creating a + // unique category name. Another possible solution would be for the + // application to create a unique key for each demand entry. They have + // random access based on searching for a key value in the list. + return 0; +} + int DLLEXPORT EN_settankdata(EN_Project p, int index, double elev, double initlvl, double minlvl, double maxlvl, double diam, diff --git a/src/project.c b/src/project.c index 1df2911..49696a3 100644 --- a/src/project.c +++ b/src/project.c @@ -791,12 +791,12 @@ void adjustpattern(int *pat, int index) } -void adjust_demand_pattern(list_node_t *lnode, int del_idx) +void adjust_demand_pattern(list_node_t *list_node, int deletion_index) { - int pat_idx = get_pattern_index(lnode); + int pat_idx = get_pattern_index(list_node); - if (pat_idx == del_idx) set_pattern_index(lnode, 0); - else if (pat_idx > del_idx) set_pattern_index(lnode, --pat_idx); + if (pat_idx == deletion_index) set_pattern_index(list_node, 0); + else if (pat_idx > deletion_index) set_pattern_index(list_node, --pat_idx); } @@ -816,11 +816,11 @@ void adjustpatterns(Network *network, int index) for (j = 1; j <= network->Nnodes; j++) { // Adjust demand patterns - list_t *dlist = network->Node[j].D; - if (dlist) { - for (list_node_t *lnode = first_list(dlist); done_list(lnode); lnode = next_list(lnode)) - adjust_demand_pattern(lnode, index); - } + list_t *dlist = network->Node[j].D; + if (dlist) { + for (list_node_t *lnode = first_list(dlist); done_list(lnode); lnode = next_list(lnode)) + adjust_demand_pattern(lnode, index); + } // Adjust WQ source patterns source = network->Node[j].S; if (source) adjustpattern(&source->Pat, index); diff --git a/tests/test_demand.cpp b/tests/test_demand.cpp index d9b0e69..fa3d4f9 100644 --- a/tests/test_demand.cpp +++ b/tests/test_demand.cpp @@ -82,5 +82,19 @@ BOOST_AUTO_TEST_CASE(test_categories_reopen, * boost::unit_test::depends_on("tes BOOST_REQUIRE(error == 0); } +BOOST_FIXTURE_TEST_CASE(test_adddemand, FixtureSingleNode) +{ + int demand_index; + + error = EN_adddemand(ph, node_qhut, 100.0, "PrimaryPattern", "PrimaryDemand", &demand_index); + BOOST_CHECK(error != 0); + + error = EN_addpattern(ph, (char *)"PrimaryPattern"); + BOOST_REQUIRE(error == 0); + + error = EN_adddemand(ph, node_qhut, 100.0, "PrimaryPattern", "PrimaryDemand", &demand_index); + BOOST_CHECK(error == 0); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/test_demand_data.cpp b/tests/test_demand_data.cpp index 82fab3e..bbf8526 100644 --- a/tests/test_demand_data.cpp +++ b/tests/test_demand_data.cpp @@ -291,4 +291,5 @@ BOOST_FIXTURE_TEST_CASE(test_pattern_edits, FixtureSingleNode) + BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/test_toolkit.hpp b/tests/test_toolkit.hpp index 08f6538..b682d5d 100644 --- a/tests/test_toolkit.hpp +++ b/tests/test_toolkit.hpp @@ -102,6 +102,26 @@ struct FixtureAfterStep{ EN_Project ph; }; +struct FixtureSingleNode { + FixtureSingleNode() { + error = 0; + ph = NULL; + + EN_createproject(&ph); + EN_init(ph, DATA_PATH_RPT, DATA_PATH_OUT, EN_GPM, EN_HW); + + EN_addnode(ph, (char *)"CUB_SCOUT_QUONSET_HUT", EN_JUNCTION, &node_qhut); + } + + ~FixtureSingleNode() { + EN_close(ph); + EN_deleteproject(&ph); + } + int error, index, node_qhut; + EN_Project ph; +}; + + boost::test_tools::predicate_result check_cdd_double(std::vector& test, std::vector& ref, long cdd_tol); boost::test_tools::predicate_result check_string(std::string test, std::string ref); From 9b3173f9be364dadb6f97ca53f97a6a371fc26cb Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Wed, 24 Apr 2019 13:15:43 -0400 Subject: [PATCH 33/36] Adding key and search to list --- src/util/list.c | 55 +++++++++++++++++++++++++++++++++++----- src/util/list.h | 21 ++++++++++----- tests/util/test_list.cpp | 34 ++++++++++++++++--------- 3 files changed, 85 insertions(+), 25 deletions(-) diff --git a/src/util/list.c b/src/util/list.c index 0b568d9..1bd6970 100644 --- a/src/util/list.c +++ b/src/util/list.c @@ -22,6 +22,7 @@ #endif #include +#include #include #include "list.h" @@ -29,6 +30,7 @@ typedef struct list_node_s { void *data; + int key; struct list_node_s *next; } list_node_t; @@ -42,6 +44,9 @@ typedef struct list_s { } list_t; +// local declarations +int gen_key(); + list_t *create_list(size_t elementSize, freeFunction freeFn) { list_t *list; @@ -67,12 +72,14 @@ void delete_list(list_t *list) free(list); } -void prepend_list(list_t *list, void *element) +int prepend_list(list_t *list, void *element) { list_node_t *node = malloc(sizeof(list_node_t)); node->data = malloc(list->elementSize); memcpy(node->data, element, list->elementSize); + node->key = gen_key(); + node->next = list->head; list->head = node; @@ -82,14 +89,18 @@ void prepend_list(list_t *list, void *element) } list->logicalLength++; + + return node->key; } -void append_list(list_t *list, void *element) +int append_list(list_t *list, void *element) { list_node_t *node = malloc(sizeof(list_node_t)); node->data = malloc(list->elementSize); node->next = NULL; + node->key = gen_key(); + memcpy(node->data, element, list->elementSize); if(list->logicalLength == 0) { @@ -100,8 +111,11 @@ void append_list(list_t *list, void *element) } list->logicalLength++; + + return node->key; } + void for_each_list(list_t *list, listIterator iterator) { assert(iterator != NULL); @@ -110,18 +124,16 @@ void for_each_list(list_t *list, listIterator iterator) bool result = true; while(node != NULL && result) { - result = (iterator); + result = iterator(node); node = node->next; } } list_node_t *head_list(list_t *list, bool removeFromList) -// // Warning: When node is removed caller is responsible for freeing it. -// { // assert(list->head != NULL); - + if (list) { list_node_t *node = list->head; if (removeFromList) { @@ -141,7 +153,7 @@ list_node_t *tail_list(list_t *list) } list_node_t *get_nth_list(list_t *list, int index) -{ +{ int n; list_node_t *lnode; @@ -152,11 +164,31 @@ list_node_t *get_nth_list(list_t *list, int index) return lnode; } +list_node_t *search_list(list_t *list, int key) +// Naive list search. Will not perform for large lists. +{ + list_node_t *lnode = first_list(list); + + while (done_list(lnode)) { + + if (get_key(lnode) == key) + return lnode; + + lnode = next_list(lnode); + } + return NULL; +} + int size_list(list_t *list) { return list->logicalLength; } +int get_key(list_node_t *lnode) +{ + return lnode->key; +} + void *get_data(list_node_t *lnode) { return lnode->data; @@ -175,3 +207,12 @@ void delete_node(list_t *list, list_node_t *lnode) free(lnode->data); free(lnode); } + + +// local functions + +int gen_key() +// Naive key generator. No guarentee of uniqueness +{ + return rand(); +} diff --git a/src/util/list.h b/src/util/list.h index e2e9185..b3583b3 100644 --- a/src/util/list.h +++ b/src/util/list.h @@ -46,14 +46,14 @@ with each node’s data pointer. void delete_list(list_t *list); /** -@brief Adds a node to the head of the list. +@brief Adds a node to the head of the list and returns its key. */ -void prepend_list(list_t *list, void *element); +int prepend_list(list_t *list, void *element); /** -@brief Adds a node to the tail of the list. +@brief Adds a node to the tail of the list and returns its key. */ -void append_list(list_t *list, void *element); +int append_list(list_t *list, void *element); /** @brief Returns the number of items in the list. @@ -67,7 +67,12 @@ int size_list(list_t *list); void *get_data(list_node_t *lnode); /** -@brief Returns next list node. +@brief Returns list node's key value. +*/ +int get_key(list_node_t *lnode); + +/** +@brief Returns next list node. */ list_node_t *get_next(list_node_t *lnode); @@ -94,10 +99,14 @@ list_node_t *head_list(list_t *list, bool removeFromList); list_node_t *tail_list(list_t *list); /** -@brief Returns nth node of the list or NULL. +@brief Returns nth node of the list or NULL. */ list_node_t *get_nth_list(list_t *list, int index); +/** +@brief Returns the list node with the given key or NULL. +*/ +list_node_t *search_list(list_t *list, int key); // // Iterator first/done/next operations diff --git a/tests/util/test_list.cpp b/tests/util/test_list.cpp index 787c1ed..7c592a5 100644 --- a/tests/util/test_list.cpp +++ b/tests/util/test_list.cpp @@ -13,7 +13,9 @@ ****************************************************************************** */ +#include #include +#include #define BOOST_TEST_MODULE list #include @@ -35,7 +37,7 @@ int *get_int_data(list_node_t *lnode) { bool iterate_int(list_node_t *lnode) { - printf("Found value: %d\n", *get_int_data(lnode)); + printf("At Key: %d Found value: %d\n", get_key(lnode), *get_int_data(lnode)); return true; } @@ -57,16 +59,23 @@ BOOST_AUTO_TEST_CASE(test_int_list){ int i, numbers = 10; list_t *list = NULL; + int key[10 + 1]; + + srand((unsigned int)time(0)); + list = create_list(sizeof(int), NULL); for(i = 1; i <= numbers; i++) { - append_list(list, &i); + key[i] = append_list(list, &i); } BOOST_CHECK(size_list(list) == 10); - + listIterator iterator = (listIterator)iterate_int; for_each_list(list, iterator); + list_node_t *lnode = search_list(list, key[5]); + BOOST_CHECK(get_key(lnode) == key[5]); + delete_list(list); } @@ -179,9 +188,15 @@ bool iterate_test_data(list_node_t *lnode) } +char *get_name(list_node_t *lnode) +{ + return get_test_data(lnode)->name; +} BOOST_AUTO_TEST_CASE(test_struct_list){ + int key; + list_t *list = NULL; list = create_list(sizeof(test_data_t *), delete_test_data); @@ -190,7 +205,7 @@ BOOST_AUTO_TEST_CASE(test_struct_list){ append_list(list, &data); data = create_test_data(2, "Kevin"); - append_list(list, &data); + key = append_list(list, &data); data = create_test_data(3, "Michael"); append_list(list, &data); @@ -202,16 +217,11 @@ BOOST_AUTO_TEST_CASE(test_struct_list){ for_each_list(list, iterator); - list_node_t *lnode; - // Iterate over list while maintaining containment of list abstraction - for (lnode = first_list(list); done_list(lnode); lnode = next_list(lnode)) { - test_data_t *test_data = get_test_data(lnode); + // locate a list node by a key + printf("Found %s!\n", get_name(search_list(list, key))); - if (test_data->num == 2) - printf("Found %s!\n", test_data->name); - } - lnode = head_list(list, true); + list_node_t *lnode = head_list(list, true); delete_node(list, lnode); delete_list(list); From d927851d2047f7f586dfcf4114c086f138eb863f Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Wed, 24 Apr 2019 16:29:57 -0400 Subject: [PATCH 34/36] Adding remove node method to generic list --- src/util/list.c | 66 ++++++++++++++++++++++++++++------------ src/util/list.h | 5 +++ tests/util/test_list.cpp | 22 ++++++++++++-- 3 files changed, 71 insertions(+), 22 deletions(-) diff --git a/src/util/list.c b/src/util/list.c index 1bd6970..443fcf2 100644 --- a/src/util/list.c +++ b/src/util/list.c @@ -132,16 +132,14 @@ void for_each_list(list_t *list, listIterator iterator) list_node_t *head_list(list_t *list, bool removeFromList) // Warning: When node is removed caller is responsible for freeing it. { -// assert(list->head != NULL); - - if (list) { - list_node_t *node = list->head; - if (removeFromList) { - // Disconnecting head node - list->head = node->next; - list->logicalLength--; - } - return node; + if (list) { + list_node_t *node = list->head; + if (removeFromList) { + // Disconnecting head node + list->head = node->next; + list->logicalLength--; + } + return node; } return NULL; } @@ -154,14 +152,14 @@ list_node_t *tail_list(list_t *list) list_node_t *get_nth_list(list_t *list, int index) { - int n; - list_node_t *lnode; + int n; + list_node_t *lnode; - for (n = 1, lnode = first_list(list); n < index && done_list(lnode); n++, lnode = next_list(lnode)); - if (n != index) - return NULL; - else - return lnode; + for (n = 1, lnode = first_list(list); n < index && done_list(lnode); n++, lnode = next_list(lnode)); + if (n != index) + return NULL; + else + return lnode; } list_node_t *search_list(list_t *list, int key) @@ -170,15 +168,45 @@ list_node_t *search_list(list_t *list, int key) list_node_t *lnode = first_list(list); while (done_list(lnode)) { - if (get_key(lnode) == key) return lnode; - lnode = next_list(lnode); } return NULL; } +void remove_node(list_t *list, int key) +{ + list_node_t *temp; + list_node_t *target = search_list(list, key); + + if (target == list->head) + delete_node(list, head_list(list, true)); + + else if (target == list->tail) { + // find next to last node + temp = list->head; + while (temp != NULL) { + if (temp->next == target) + break; + temp = temp->next; + } + // detatch tail + temp->next = NULL; + delete_node(list, list->tail); + } + else { + temp = target->next; + list->freeFn(target->data); + free(target->data); + + target->data = temp->data; + target->next = temp->next; + + free(temp); + } +} + int size_list(list_t *list) { return list->logicalLength; diff --git a/src/util/list.h b/src/util/list.h index b3583b3..599acde 100644 --- a/src/util/list.h +++ b/src/util/list.h @@ -108,6 +108,11 @@ list_node_t *get_nth_list(list_t *list, int index); */ list_node_t *search_list(list_t *list, int key); +/** +@brief Removes the list node with the given key from the list. +*/ +void remove_node(list_t *list, int key); + // // Iterator first/done/next operations // http://www.cs.yale.edu/homes/aspnes/pinewiki/C(2f)Iterators.html diff --git a/tests/util/test_list.cpp b/tests/util/test_list.cpp index 7c592a5..86fcd29 100644 --- a/tests/util/test_list.cpp +++ b/tests/util/test_list.cpp @@ -195,14 +195,14 @@ char *get_name(list_node_t *lnode) BOOST_AUTO_TEST_CASE(test_struct_list){ - int key; + int key, head_key, tail_key; list_t *list = NULL; list = create_list(sizeof(test_data_t *), delete_test_data); test_data_t *data = create_test_data(1, "David"); - append_list(list, &data); + head_key = append_list(list, &data); data = create_test_data(2, "Kevin"); key = append_list(list, &data); @@ -210,8 +210,13 @@ BOOST_AUTO_TEST_CASE(test_struct_list){ data = create_test_data(3, "Michael"); append_list(list, &data); + data = create_test_data(4, "Craig"); + append_list(list, &data); - BOOST_CHECK(size_list(list) == 3); + data = create_test_data(5, "Jimi"); + tail_key = append_list(list, &data); + + BOOST_CHECK(size_list(list) == 5); listIterator iterator = (listIterator)iterate_test_data; for_each_list(list, iterator); @@ -220,6 +225,17 @@ BOOST_AUTO_TEST_CASE(test_struct_list){ // locate a list node by a key printf("Found %s!\n", get_name(search_list(list, key))); + printf("Removing Kevin\n"); + remove_node(list, key); + for_each_list(list, iterator); + + printf("Removing David\n"); + remove_node(list, head_key); + for_each_list(list, iterator); + + printf("Removing Jimi\n"); + remove_node(list, tail_key); + for_each_list(list, iterator); list_node_t *lnode = head_list(list, true); delete_node(list, lnode); From dc3c2ffe1a8d265ab80f31119f6a55f8850edb90 Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Wed, 24 Apr 2019 16:30:27 -0400 Subject: [PATCH 35/36] Adding remove demand method to toolkit --- src/epanet.c | 28 +++++++++++++--------------- tests/test_demand.cpp | 6 +++--- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/epanet.c b/src/epanet.c index 3138be3..02047c4 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -2527,12 +2527,12 @@ int DLLEXPORT EN_setjuncdata(EN_Project p, int index, double elev, } int DLLEXPORT EN_adddemand(EN_Project p, int node_index, double demand, - char *demand_pattern, const char *category_name, int *demand_index) + char *demand_pattern, const char *category_name, int *demand_key) { Network *net = &p->network; int pattern_index, error = 0; - *demand_index = -1; + *demand_key = -1; if (error = EN_getpatternindex(p, demand_pattern, &pattern_index) != 0) return error; @@ -2541,29 +2541,27 @@ int DLLEXPORT EN_adddemand(EN_Project p, int node_index, double demand, if (!demand_list) { demand_list = create_demand_list(demand/p->Ucf[FLOW], pattern_index, category_name); if (!demand_list) return 101; - + Node[node_index].D = demand_list; } else { demand_data_t *demand_data = create_demand_data(demand/p->Ucf[FLOW], pattern_index, category_name); if (!demand_data) return 101; - append_list(demand_list, &demand_data); + *demand_key = append_list(demand_list, &demand_data); } - - *demand_index = size_list(demand_list); return 0; } -int DLLEXPORT EN_removedemand(EN_Project p, int node_index, int demand_index) { - // Problem: Removing a demand will in most cases invalidate the index - // returned previously in EN_adddemand(). This occurs in all cases except - // when the demand at the tail of the list is removed. This is why indexing - // is a flawed strategy for random access to a list data structure. - // One possible solution is to have the user be responsible for creating a - // unique category name. Another possible solution would be for the - // application to create a unique key for each demand entry. They have - // random access based on searching for a key value in the list. +int DLLEXPORT EN_removedemand(EN_Project p, int node_index, int demand_key) +{ + Network *net = &p->network; + Snode *Node = net->Node; + + list_t *dlist = Node[node_index].D; + + remove_node(dlist, search_list(dlist, demand_key)); + return 0; } diff --git a/tests/test_demand.cpp b/tests/test_demand.cpp index fa3d4f9..1f8ead4 100644 --- a/tests/test_demand.cpp +++ b/tests/test_demand.cpp @@ -84,15 +84,15 @@ BOOST_AUTO_TEST_CASE(test_categories_reopen, * boost::unit_test::depends_on("tes BOOST_FIXTURE_TEST_CASE(test_adddemand, FixtureSingleNode) { - int demand_index; + int demand_key; - error = EN_adddemand(ph, node_qhut, 100.0, "PrimaryPattern", "PrimaryDemand", &demand_index); + error = EN_adddemand(ph, node_qhut, 100.0, "PrimaryPattern", "PrimaryDemand", &demand_key); BOOST_CHECK(error != 0); error = EN_addpattern(ph, (char *)"PrimaryPattern"); BOOST_REQUIRE(error == 0); - error = EN_adddemand(ph, node_qhut, 100.0, "PrimaryPattern", "PrimaryDemand", &demand_index); + error = EN_adddemand(ph, node_qhut, 100.0, "PrimaryPattern", "PrimaryDemand", &demand_key); BOOST_CHECK(error == 0); } From 35cf9bd422880ff6da94c388ddf93805c3f924fd Mon Sep 17 00:00:00 2001 From: Michael Tryby Date: Wed, 24 Apr 2019 18:40:47 -0400 Subject: [PATCH 36/36] Fix bug and test remove demand --- src/epanet.c | 2 +- tests/test_demand.cpp | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/epanet.c b/src/epanet.c index 02047c4..3419097 100644 --- a/src/epanet.c +++ b/src/epanet.c @@ -2560,7 +2560,7 @@ int DLLEXPORT EN_removedemand(EN_Project p, int node_index, int demand_key) list_t *dlist = Node[node_index].D; - remove_node(dlist, search_list(dlist, demand_key)); + remove_node(dlist, demand_key); return 0; } diff --git a/tests/test_demand.cpp b/tests/test_demand.cpp index 1f8ead4..80bf042 100644 --- a/tests/test_demand.cpp +++ b/tests/test_demand.cpp @@ -84,7 +84,7 @@ BOOST_AUTO_TEST_CASE(test_categories_reopen, * boost::unit_test::depends_on("tes BOOST_FIXTURE_TEST_CASE(test_adddemand, FixtureSingleNode) { - int demand_key; + int key, demand_key; error = EN_adddemand(ph, node_qhut, 100.0, "PrimaryPattern", "PrimaryDemand", &demand_key); BOOST_CHECK(error != 0); @@ -94,6 +94,21 @@ BOOST_FIXTURE_TEST_CASE(test_adddemand, FixtureSingleNode) error = EN_adddemand(ph, node_qhut, 100.0, "PrimaryPattern", "PrimaryDemand", &demand_key); BOOST_CHECK(error == 0); + + error = EN_addpattern(ph, (char *)"SecondaryPattern"); + BOOST_REQUIRE(error == 0); + + error = EN_adddemand(ph, node_qhut, 10.0, "SecondaryPattern", "SecondaryDemand", &key); + BOOST_CHECK(error == 0); + + error = EN_addpattern(ph, (char *)"TertiaryPattern"); + BOOST_REQUIRE(error == 0); + + error = EN_adddemand(ph, node_qhut, 1.0, "TertiaryPattern", "TertiaryDemand", &demand_key); + BOOST_CHECK(error == 0); + + error = EN_removedemand(ph, node_qhut, key); + BOOST_CHECK(error == 0); }