4
CMakeLists.txt
Executable file → Normal file
4
CMakeLists.txt
Executable file → Normal file
@@ -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/*.c)
|
||||
file(GLOB EPANET_LIB_ALL RELATIVE ${PROJECT_SOURCE_DIR} src/* src/util/*)
|
||||
# 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})
|
||||
|
||||
@@ -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.
|
||||
|
||||
133
src/demand.c
Normal file
133
src/demand.c
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Module: demand.c
|
||||
Description: data for demand pattern list
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 04/12/2019
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define _CRTDBG_MAP_ALLOC
|
||||
#include <stdlib.h>
|
||||
#include <crtdbg.h>
|
||||
#else
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "demand.h"
|
||||
|
||||
|
||||
typedef struct demand_data_s
|
||||
{
|
||||
double base_demand;
|
||||
int pattern_index;
|
||||
char *category_name;
|
||||
} demand_data_t;
|
||||
|
||||
|
||||
|
||||
list_t *create_demand_list(double base_demand, int pattern_index, const 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, const 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 = pattern_index;
|
||||
|
||||
if (category_name)
|
||||
demand_data->category_name = strdup(category_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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
double base_demand = get_base_demand(lnode);
|
||||
|
||||
set_base_demand(lnode, base_demand/unit_conversion);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
double get_base_demand(list_node_t *lnode)
|
||||
{
|
||||
return get_demand_data(lnode)->base_demand;
|
||||
}
|
||||
|
||||
void set_base_demand(list_node_t *lnode, double base_demand)
|
||||
{
|
||||
get_demand_data(lnode)->base_demand = base_demand;
|
||||
}
|
||||
|
||||
int get_pattern_index(list_node_t *lnode)
|
||||
{
|
||||
return get_demand_data(lnode)->pattern_index;
|
||||
}
|
||||
|
||||
void set_pattern_index(list_node_t *lnode, int pattern_index)
|
||||
{
|
||||
get_demand_data(lnode)->pattern_index = pattern_index;
|
||||
}
|
||||
|
||||
char *get_category_name(list_node_t *lnode)
|
||||
// Be advised: caller must free memory returned
|
||||
{
|
||||
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)
|
||||
{
|
||||
free(get_demand_data(lnode)->category_name);
|
||||
get_demand_data(lnode)->category_name = strdup(category_name);
|
||||
}
|
||||
63
src/demand.h
Normal file
63
src/demand.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
Project: OWA EPANET
|
||||
Version: 2.2
|
||||
Module: demand.h
|
||||
Description: data for 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"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
// Forward declarations
|
||||
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, const char *category_name);
|
||||
|
||||
|
||||
demand_data_t *create_demand_data(double base_demand, int pat_index, const char *cat_name);
|
||||
|
||||
void delete_demand_data(void *data);
|
||||
|
||||
size_t get_demand_data_size(void);
|
||||
|
||||
|
||||
bool convert_units(list_node_t *lnode, double unit_conversion);
|
||||
|
||||
|
||||
double get_base_demand(list_node_t *lnode);
|
||||
void set_base_demand(list_node_t *lnode, double base_demand);
|
||||
|
||||
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, const char *category_name);
|
||||
|
||||
// Make this private?
|
||||
demand_data_t *get_demand_data(list_node_t *lnode);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* DEMAND_H */
|
||||
254
src/epanet.c
254
src/epanet.c
@@ -30,6 +30,8 @@
|
||||
#include "text.h"
|
||||
#include "enumstxt.h"
|
||||
|
||||
#include "demand.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
@@ -1719,8 +1721,8 @@ int DLLEXPORT EN_addnode(EN_Project p, char *id, int nodeType, int *index)
|
||||
Hydraul *hyd = &p->hydraul;
|
||||
Quality *qual = &p->quality;
|
||||
|
||||
int i, nIdx, size;
|
||||
struct Sdemand *demand;
|
||||
int i, nIdx;
|
||||
int size;
|
||||
Stank *tank;
|
||||
Snode *node;
|
||||
Scontrol *control;
|
||||
@@ -1751,12 +1753,7 @@ int DLLEXPORT EN_addnode(EN_Project p, char *id, int nodeType, int *index)
|
||||
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;
|
||||
node->D = NULL;
|
||||
|
||||
// shift rest of Node array
|
||||
for (i = net->Nnodes; i >= net->Njuncs; i--)
|
||||
@@ -1857,7 +1854,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;
|
||||
@@ -1891,13 +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;
|
||||
while (demand != NULL)
|
||||
{
|
||||
nextdemand = demand->next;
|
||||
free(demand->Name);
|
||||
free(demand);
|
||||
demand = nextdemand;
|
||||
}
|
||||
if (demand)
|
||||
delete_list(demand);
|
||||
|
||||
free(node->S);
|
||||
free(node->Comment);
|
||||
|
||||
@@ -2064,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;
|
||||
@@ -2091,26 +2083,24 @@ 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)
|
||||
{
|
||||
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;
|
||||
|
||||
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)
|
||||
{
|
||||
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(head_list(demand, false));
|
||||
}
|
||||
else v = (double)(Tank[index - nJuncs].Pat);
|
||||
break;
|
||||
@@ -2265,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;
|
||||
|
||||
@@ -2288,26 +2277,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)
|
||||
{
|
||||
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(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)
|
||||
{
|
||||
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(head_list(demand, false), j);
|
||||
}
|
||||
else Tank[index - nJuncs].Pat = j;
|
||||
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;
|
||||
@@ -2526,14 +2512,56 @@ 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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DLLEXPORT EN_adddemand(EN_Project p, int node_index, double demand,
|
||||
char *demand_pattern, const char *category_name, int *demand_key)
|
||||
{
|
||||
Network *net = &p->network;
|
||||
|
||||
int pattern_index, error = 0;
|
||||
*demand_key = -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;
|
||||
|
||||
*demand_key = append_list(demand_list, &demand_data);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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, demand_key);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2714,16 +2742,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 = size_list(demand_list);
|
||||
else
|
||||
*numDemands = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2738,9 +2770,6 @@ int DLLEXPORT EN_getbasedemand(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;
|
||||
@@ -2748,10 +2777,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;
|
||||
@@ -2769,9 +2801,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;
|
||||
@@ -2779,10 +2808,22 @@ 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];
|
||||
list_t *dlist = p->network.Node[nodeIndex].D;
|
||||
// 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;
|
||||
}
|
||||
@@ -2798,8 +2839,7 @@ int DLLEXPORT EN_getdemandname(EN_Project p, int nodeIndex, int demandIndex,
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Pdemand d;
|
||||
int n = 1;
|
||||
char *temp = NULL;
|
||||
|
||||
strcpy(demandName, "");
|
||||
|
||||
@@ -2808,12 +2848,21 @@ 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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
else return 253;
|
||||
|
||||
if (d->Name) strcpy(demandName, d->Name);
|
||||
else demandName[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2829,8 +2878,6 @@ int DLLEXPORT EN_setdemandname(EN_Project p, int nodeIndex, int demandIndex,
|
||||
**----------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Pdemand d;
|
||||
int n = 1;
|
||||
|
||||
// Check for valid arguments
|
||||
if (!p->Openflag) return 102;
|
||||
@@ -2840,10 +2887,20 @@ int DLLEXPORT EN_setdemandname(EN_Project p, int nodeIndex, int demandIndex,
|
||||
if (strlen(demandName) > MAXID) return 252;
|
||||
|
||||
// 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;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -2859,16 +2916,18 @@ int DLLEXPORT EN_getdemandpattern(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;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -2886,21 +2945,28 @@ int DLLEXPORT EN_setdemandpattern(EN_Project p, int nodeIndex, int demandIndex,
|
||||
{
|
||||
Network *net = &p->network;
|
||||
|
||||
Pdemand d;
|
||||
int n = 1;
|
||||
|
||||
// Check for valid arguments
|
||||
if (!p->Openflag) return 102;
|
||||
if (nodeIndex <= 0 || nodeIndex > net->Nnodes) return 203;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
@@ -4338,7 +4404,7 @@ int DLLEXPORT EN_setcurveid(EN_Project p, int index, char *id)
|
||||
|
||||
// Check if id name contains invalid characters
|
||||
if (!namevalid(id)) return 252;
|
||||
|
||||
|
||||
for (i = 1; i <= p->network.Ncurves; i++)
|
||||
{
|
||||
if (i != index && strcmp(id, p->network.Curve[i].ID) == 0) return 215;
|
||||
|
||||
@@ -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,15 +566,19 @@ 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)
|
||||
{
|
||||
// pattern period (k) = (elapsed periods) modulus (periods per pattern)
|
||||
j = demand->Pat;
|
||||
k = p % (long) net->Pattern[j].Length;
|
||||
djunc = (demand->Base) * net->Pattern[j].F[k] * hyd->Dmult;
|
||||
if (djunc > 0.0) hyd->Dsystem += djunc;
|
||||
sum += djunc;
|
||||
}
|
||||
list_t *dlist = net->Node[i].D;
|
||||
|
||||
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
|
||||
|
||||
@@ -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[];
|
||||
@@ -119,6 +121,48 @@ 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)) {
|
||||
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, " ");
|
||||
|
||||
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)
|
||||
/*
|
||||
-------------------------------------------------
|
||||
@@ -135,9 +179,9 @@ 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;
|
||||
//Pdemand demand;
|
||||
Psource source;
|
||||
FILE *f;
|
||||
Slink *link;
|
||||
@@ -325,22 +369,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];
|
||||
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);
|
||||
}
|
||||
}
|
||||
write_demands(pr, f);
|
||||
|
||||
|
||||
// Write [EMITTERS] section
|
||||
fprintf(f, "\n\n");
|
||||
|
||||
44
src/input1.c
44
src/input1.c
@@ -23,6 +23,8 @@ Last Updated: 04/03/2019
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#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
|
||||
@@ -329,17 +331,17 @@ void adjustdata(Project *pr)
|
||||
tank = &net->Tank[i];
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
@@ -542,7 +544,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 +564,17 @@ 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;
|
||||
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];
|
||||
// }
|
||||
}
|
||||
|
||||
hyd->Pmin /= pr->Ucf[PRESSURE];
|
||||
hyd->Preq /= pr->Ucf[PRESSURE];
|
||||
|
||||
|
||||
90
src/input3.c
90
src/input3.c
@@ -23,6 +23,7 @@ Last Updated: 04/03/2019
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#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,13 @@ 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_list = create_demand_list(y, p, NULL);
|
||||
if (!demand_list) return 101;
|
||||
}
|
||||
node->D = demand_list;
|
||||
|
||||
hyd->NodeDemand[njuncs] = y;
|
||||
return 0;
|
||||
}
|
||||
@@ -709,8 +712,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 +741,27 @@ 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 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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,10 @@ 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)
|
||||
{
|
||||
nextdemand = demand->next;
|
||||
free(demand->Name);
|
||||
free(demand);
|
||||
demand = nextdemand;
|
||||
}
|
||||
list_t *demand = pr->network.Node[j].D;
|
||||
if(demand)
|
||||
delete_list(demand);
|
||||
|
||||
// Free memory used for WQ source data
|
||||
free(pr->network.Node[j].S);
|
||||
free(pr->network.Node[j].Comment);
|
||||
@@ -788,10 +786,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 adjust_demand_pattern(list_node_t *list_node, int deletion_index)
|
||||
{
|
||||
int pat_idx = get_pattern_index(list_node);
|
||||
|
||||
if (pat_idx == deletion_index) set_pattern_index(list_node, 0);
|
||||
else if (pat_idx > deletion_index) set_pattern_index(list_node, --pat_idx);
|
||||
}
|
||||
|
||||
|
||||
void adjustpatterns(Network *network, int index)
|
||||
/*----------------------------------------------------------------
|
||||
** Input: index = index of time pattern being deleted
|
||||
@@ -801,16 +809,17 @@ void adjustpatterns(Network *network, int index)
|
||||
*/
|
||||
{
|
||||
int j;
|
||||
Pdemand demand;
|
||||
//Pdemand demand;
|
||||
Psource source;
|
||||
|
||||
// Adjust patterns used by junctions
|
||||
for (j = 1; j <= network->Nnodes; 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;
|
||||
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;
|
||||
|
||||
122
src/types.h
122
src/types.h
@@ -14,15 +14,18 @@
|
||||
#ifndef TYPES_H
|
||||
#define TYPES_H
|
||||
|
||||
#include "hash.h"
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
#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
|
||||
------------------------------------------------------
|
||||
*/
|
||||
|
||||
@@ -336,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
|
||||
{
|
||||
@@ -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
|
||||
|
||||
128
src/util/list.c
128
src/util/list.c
@@ -22,6 +22,7 @@
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
|
||||
#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,34 +111,37 @@ 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);
|
||||
|
||||
list_node_t *node = list->head;
|
||||
bool result = true;
|
||||
while(node != NULL && result) {
|
||||
result = iterator(node);
|
||||
|
||||
while(node != NULL && result) {
|
||||
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);
|
||||
|
||||
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,16 +150,83 @@ 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int get_key(list_node_t *lnode)
|
||||
{
|
||||
return lnode->key;
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -155,22 +236,11 @@ void delete_node(list_t *list, list_node_t *lnode)
|
||||
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)
|
||||
{
|
||||
return list->head;
|
||||
}
|
||||
|
||||
bool done_list(list_node_t *lnode)
|
||||
{
|
||||
return lnode != NULL;
|
||||
}
|
||||
// local functions
|
||||
|
||||
list_node_t *next_list(list_node_t *lnode)
|
||||
int gen_key()
|
||||
// Naive key generator. No guarentee of uniqueness
|
||||
{
|
||||
return lnode->next;
|
||||
return rand();
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
#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 *);
|
||||
|
||||
|
||||
/**
|
||||
@@ -45,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.
|
||||
@@ -65,6 +66,16 @@ int size_list(list_t *list);
|
||||
*/
|
||||
void *get_data(list_node_t *lnode);
|
||||
|
||||
/**
|
||||
@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);
|
||||
|
||||
/**
|
||||
@brief Frees memory associated with a list node.
|
||||
*/
|
||||
@@ -87,21 +98,41 @@ 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);
|
||||
|
||||
/**
|
||||
@brief Returns the list node with the given key or NULL.
|
||||
*/
|
||||
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
|
||||
// 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)
|
||||
|
||||
@@ -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} epanet2)
|
||||
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
|
||||
|
||||
@@ -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;
|
||||
@@ -70,9 +72,9 @@ BOOST_AUTO_TEST_CASE(test_categories_reopen, * boost::unit_test::depends_on("tes
|
||||
|
||||
char demname[31];
|
||||
error = EN_getdemandname(ph, Nindex, ndem, demname);
|
||||
BOOST_REQUIRE(error == 0);
|
||||
BOOST_CHECK(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,34 @@ 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 key, demand_key;
|
||||
|
||||
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_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);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
295
tests/test_demand_data.cpp
Normal file
295
tests/test_demand_data.cpp
Normal file
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
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 <boost/test/unit_test.hpp>
|
||||
|
||||
#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)
|
||||
{
|
||||
if (ref.compare(test) == 0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
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 == sizeof(demand_data_t *));
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
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 = NULL;
|
||||
|
||||
name = get_category_name(lnode);
|
||||
BOOST_CHECK(check_string(name, (char *)"CUB_SCOUT_BASE_CAMP"));
|
||||
|
||||
free(name);
|
||||
name = NULL;
|
||||
|
||||
set_category_name(lnode, (char *)"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_CASE(test_initclose)
|
||||
{
|
||||
int error;
|
||||
|
||||
EN_Project ph = NULL;
|
||||
|
||||
EN_createproject(&ph);
|
||||
|
||||
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);
|
||||
|
||||
EN_deleteproject(&ph);
|
||||
}
|
||||
|
||||
|
||||
#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 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);
|
||||
//EN_getnodeindex(ph, (char *)"CUB_SCOUT_QUONSET_HUT", &node_qhut);
|
||||
}
|
||||
|
||||
~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;
|
||||
|
||||
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);
|
||||
|
||||
char demname[31];
|
||||
error = EN_getdemandname(ph, node_qhut, demand_idx, demname);
|
||||
BOOST_REQUIRE(error == 253);
|
||||
BOOST_CHECK(check_string(demname, "\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_qhut, demand_idx, pattern_idx);
|
||||
BOOST_REQUIRE(error == 205);
|
||||
|
||||
// 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_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;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
// 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);
|
||||
|
||||
//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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -81,10 +81,10 @@ BOOST_AUTO_TEST_CASE(test_save)
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<double>& test,
|
||||
std::vector<double>& ref, long cdd_tol);
|
||||
boost::test_tools::predicate_result check_string(std::string test, std::string ref);
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#define BOOST_TEST_MODULE list
|
||||
#include <boost/test/unit_test.hpp>
|
||||
@@ -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,14 +59,22 @@ 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);
|
||||
|
||||
for_each_list(list, iterate_int);
|
||||
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);
|
||||
}
|
||||
@@ -111,7 +121,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);
|
||||
}
|
||||
|
||||
|
||||
@@ -177,38 +188,56 @@ 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, 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");
|
||||
append_list(list, &data);
|
||||
key = append_list(list, &data);
|
||||
|
||||
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);
|
||||
|
||||
for_each_list(list, iterate_test_data);
|
||||
BOOST_CHECK(size_list(list) == 5);
|
||||
|
||||
listIterator iterator = (listIterator)iterate_test_data;
|
||||
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);
|
||||
}
|
||||
printf("Removing Kevin\n");
|
||||
remove_node(list, key);
|
||||
for_each_list(list, iterator);
|
||||
|
||||
lnode = head_list(list, true);
|
||||
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);
|
||||
|
||||
delete_list(list);
|
||||
|
||||
Reference in New Issue
Block a user