Refactors the API's demand editing functions

This commit is contained in:
Lew Rossman
2019-05-09 10:26:40 -04:00
parent 52bda22833
commit 365ab00dcb
22 changed files with 449 additions and 1124 deletions

View File

@@ -1,133 +0,0 @@
/*
******************************************************************************
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);
}

View File

@@ -1,63 +0,0 @@
/*
******************************************************************************
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 */

View File

@@ -20,7 +20,6 @@
#endif
#include <stdio.h>
#include <string.h>
#include <float.h>
#include <math.h>
@@ -30,8 +29,6 @@
#include "text.h"
#include "enumstxt.h"
#include "demand.h"
#ifdef _WIN32
#define snprintf _snprintf
#endif
@@ -1721,8 +1718,7 @@ int DLLEXPORT EN_addnode(EN_Project p, char *id, int nodeType, int *index)
Hydraul *hyd = &p->hydraul;
Quality *qual = &p->quality;
int i, nIdx;
int size;
int i, nIdx, size;
Stank *tank;
Snode *node;
Scontrol *control;
@@ -1752,8 +1748,8 @@ int DLLEXPORT EN_addnode(EN_Project p, char *id, int nodeType, int *index)
net->Njuncs++;
nIdx = net->Njuncs;
node = &net->Node[nIdx];
node->D = NULL;
node->D = NULL;
adddemand(node, 0.0, 0, NULL);
// shift rest of Node array
for (i = net->Nnodes; i >= net->Njuncs; i--)
@@ -1766,21 +1762,18 @@ int DLLEXPORT EN_addnode(EN_Project p, char *id, int nodeType, int *index)
{
net->Tank[i].Node += 1;
}
// shift indices of Links, if necessary
for (i = 1; i <= net->Nlinks; i++)
{
if (net->Link[i].N1 > net->Njuncs - 1) net->Link[i].N1 += 1;
if (net->Link[i].N2 > net->Njuncs - 1) net->Link[i].N2 += 1;
}
// shift indices of tanks/reservoir nodes in controls
for (i = 1; i <= net->Ncontrols; ++i)
{
control = &net->Control[i];
if (control->Node > net->Njuncs - 1) control->Node += 1;
}
// adjust indices of tanks/reservoirs in Rule premises (see RULES.C)
adjusttankrules(p);
}
@@ -1854,7 +1847,6 @@ int DLLEXPORT EN_deletenode(EN_Project p, int index, int actionCode)
int i, nodeType, tankindex;
Snode *node;
list_t *demand;
// Cannot modify network structure while solvers are active
if (!p->Openflag) return 102;
@@ -1886,10 +1878,7 @@ int DLLEXPORT EN_deletenode(EN_Project p, int index, int actionCode)
hashtable_delete(net->NodeHashTable, node->ID);
// Free memory allocated to node's demands, WQ source & comment
demand = node->D;
if (demand)
delete_list(demand);
freedemands(node);
free(node->S);
free(node->Comment);
@@ -2081,25 +2070,18 @@ int DLLEXPORT EN_getnodevalue(EN_Project p, int index, int property, double *val
break;
case EN_BASEDEMAND:
v = 0.0;
// NOTE: primary demand category is first on demand list
if (index <= nJuncs)
{
list_t *demand = Node[index].D;
if (demand)
v = get_base_demand(head_list(demand, false));
if (Node[index].D) v = Node[index].D->Base * Ucf[FLOW];
}
v *= Ucf[FLOW];
break;
case EN_PATTERN:
v = 0.0;
// 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));
if (Node[index].D) v = (double)(Node[index].D->Pat);
}
else v = (double)(Tank[index - nJuncs].Pat);
break;
@@ -2280,9 +2262,7 @@ 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]);
if (Node[index].D) Node[index].D->Base = value / Ucf[FLOW];
}
break;
@@ -2292,9 +2272,7 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int property, double valu
if (j < 0 || j > nPats) return 205;
if (index <= nJuncs)
{
list_t *demand = Node[index].D;
if (demand)
set_pattern_index(head_list(demand, false), j);
if (Node[index].D) Node[index].D->Pat = j;
}
else Tank[index - nJuncs].Pat = j;
break;
@@ -2542,81 +2520,33 @@ int DLLEXPORT EN_setjuncdata(EN_Project p, int index, double elev,
**----------------------------------------------------------------
*/
{
Network *net = &p->network;
int i, patIndex = 0;
Snode *Node = net->Node;
int patIndex = 0;
Snode *node;
// Check that junction exists
if (!p->Openflag) return 102;
if (index <= 0 || index > net->Njuncs) return 203;
if (index <= 0 || index > p->network.Njuncs) return 203;
// Check that demand pattern exists
if (strlen(dmndpat) > 0)
if (dmndpat && strlen(dmndpat) > 0)
{
for (i = 1; i <= net->Npats; i++)
{
if (strcmp(dmndpat, net->Pattern[i].ID) == 0)
{
patIndex = i;
break;
}
}
if (patIndex == 0) return 205;
if (EN_getpatternindex(p, dmndpat, &patIndex) > 0) return 205;
}
// Assign values to junction's parameters
Node[index].El = elev / p->Ucf[ELEV];
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;
// Assign demand parameters to junction's primary demand category
node = &(p->network.Node[index]);
dmnd /= p->Ucf[FLOW];
// Category exists - update its properties
if (node->D)
{
(node->D)->Base = dmnd;
(node->D)->Pat = patIndex;
}
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);
// No demand categories exist -- create a new one
else if (!adddemand(node, dmnd, patIndex, NULL)) return 101;
// Assign new elevation value to junction
node->El = elev / p->Ucf[ELEV];
return 0;
}
@@ -2793,6 +2723,138 @@ int DLLEXPORT EN_setdemandmodel(EN_Project p, int model, double pmin,
return 0;
}
int DLLEXPORT EN_adddemand(EN_Project p, int nodeIndex, double baseDemand,
char *demandPattern, char *demandName)
/*----------------------------------------------------------------
** Input: nodeIndex = node index
** baseDemand = baseline demand value
** demandPattern = name of demand's time pattern (can be NULL or empty)
** demandName = name of demand's category (can be NULL or empty)
** Returns: error code
** Purpose: adds a new demand category to a junction node
**----------------------------------------------------------------
*/
{
int patIndex = 0;
Snode *node;
// Check for valid arguments
if (!p->Openflag) return 102;
if (nodeIndex <= 0 || nodeIndex > p->network.Nnodes) return 203;
if (demandPattern && strlen(demandPattern) > 0)
{
if (EN_getpatternindex(p, demandPattern, &patIndex) > 0) return 205;
}
// Do nothing if node is not a junction
if (nodeIndex > p->network.Njuncs) return 0;
// Add the new demand to the node's demands list
node = &(p->network.Node[nodeIndex]);
if (!adddemand(node, baseDemand / p->Ucf[FLOW], patIndex, demandName)) return 101;
return 0;
}
int DLLEXPORT EN_deletedemand(EN_Project p, int nodeIndex, int demandIndex)
/*----------------------------------------------------------------
** Input: nodeIndex = node index
** demandIndex = index of node's demand to be deleted
** Returns: error code
** Purpose: deletes an existing demand category from a junction node
**----------------------------------------------------------------
*/
{
Pdemand d, dprev;
Snode *node;
int n = 1;
// Check for valid arguments
if (!p->Openflag) return 102;
if (nodeIndex <= 0 || nodeIndex > p->network.Nnodes) return 203;
// Only junctions have demands
if (nodeIndex <= p->network.Njuncs)
{
// Find head of node's list of demands
node = &p->network.Node[nodeIndex];
d = node->D;
if (d == NULL) return 253;
dprev = d;
// Check if target demand is head of demand list
if (demandIndex == 1)
{
node->D = d->next;
free(d->Name);
free(d);
return 0;
}
// Otherwise locate target demand in demand list
while (d != NULL && n < demandIndex)
{
dprev = d;
d = d->next;
n++;
}
// Return error if target demand not found
if (d == NULL) return 253;
// Link the demands that precede and follow the target
dprev->next = d->next;
// Delete the target demand
free(d->Name);
free(d);
}
return 0;
}
int DLLEXPORT EN_getdemandindex(EN_Project p, int nodeIndex, char *demandName,
int *demandIndex)
/*----------------------------------------------------------------
** Input: nodeIndex = node index
** demandName = name of demand being sought
** Output: demandIndex = index of demand being sought
** Returns: error code
** Purpose: retrieves the position of a named demand category
** in a node's list of demands
**----------------------------------------------------------------
*/
{
Pdemand d;
int n = 0;
int nameEmpty = FALSE;
int found = FALSE;
// Check for valid arguments
*demandIndex = 0;
if (!p->Openflag) return 102;
if (nodeIndex <= 0 || nodeIndex > p->network.Nnodes) return 203;
if (demandName == NULL) return 253;
// Check if target name is empty
if (strlen(demandName) == 0) nameEmpty = TRUE;
// Locate target demand in node's demands list
for (d = p->network.Node[nodeIndex].D; d != NULL; d = d->next)
{
n++;
if (d->Name == NULL)
{
if (nameEmpty) found = TRUE;;
}
else if (strcmp(d->Name, demandName) == 0) found = TRUE;
if (found) break;
}
// Return target demand's index
if (!found) return 253;
*demandIndex = n;
return 0;
}
int DLLEXPORT EN_getnumdemands(EN_Project p, int nodeIndex, int *numDemands)
/*----------------------------------------------------------------
** Input: nodeIndex = node index
@@ -2802,20 +2864,16 @@ 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
list_t *demand_list = p->network.Node[nodeIndex].D;
if (demand_list)
*numDemands = size_list(demand_list);
else
*numDemands = 0;
// Count the number of demand categories assigned to node
for (d = p->network.Node[nodeIndex].D; d != NULL; d = d->next) n++;
*numDemands = n;
return 0;
}
@@ -2830,22 +2888,19 @@ int DLLEXPORT EN_getbasedemand(EN_Project p, int nodeIndex, int demandIndex,
**----------------------------------------------------------------
*/
{
Pdemand d;
// Check for valid arguments
*baseDemand = 0.0;
if (!p->Openflag) return 102;
if (nodeIndex <= 0 || nodeIndex > p->network.Nnodes) return 203;
// Retrieve 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
*baseDemand = get_base_demand(lnode) * p->Ucf[FLOW];
}
else *baseDemand = (double)(0.0);
// Locate target demand in node's demands list
d = finddemand(p->network.Node[nodeIndex].D, demandIndex);
if (d == NULL) return 253;
// Retrieve target demand's base value
*baseDemand = d->Base * p->Ucf[FLOW];
return 0;
}
@@ -2861,30 +2916,18 @@ int DLLEXPORT EN_setbasedemand(EN_Project p, int nodeIndex, int demandIndex,
**----------------------------------------------------------------
*/
{
Pdemand d;
// Check for valid arguments
if (!p->Openflag) return 102;
if (nodeIndex <= 0 || nodeIndex > p->network.Nnodes) return 203;
// Set baseline demand for specified category
if (nodeIndex <= p->network.Njuncs)
{
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;
// Locate target demand in node's demands list
d = finddemand(p->network.Node[nodeIndex].D, demandIndex);
if (d == NULL) return 253;
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]);
}
}
// Assign new base value to target demand
d->Base = baseDemand / p->Ucf[FLOW];
return 0;
}
@@ -2899,7 +2942,7 @@ int DLLEXPORT EN_getdemandname(EN_Project p, int nodeIndex, int demandIndex,
**----------------------------------------------------------------
*/
{
char *temp = NULL;
Pdemand d;
strcpy(demandName, "");
@@ -2907,22 +2950,12 @@ int DLLEXPORT EN_getdemandname(EN_Project p, int nodeIndex, int demandIndex,
if (!p->Openflag) return 102;
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;
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;
// Locate target demand in node's demands list
d = finddemand(p->network.Node[nodeIndex].D, demandIndex);
if (d == NULL) return 253;
// Retrieve target demand's category name
if (d->Name) strcpy(demandName, d->Name);
return 0;
}
@@ -2938,29 +2971,18 @@ int DLLEXPORT EN_setdemandname(EN_Project p, int nodeIndex, int demandIndex,
**----------------------------------------------------------------
*/
{
Pdemand d;
// Check for valid arguments
if (!p->Openflag) return 102;
if (nodeIndex <= 0 || nodeIndex > p->network.Njuncs) return 203;
// Check that demandName is not too long
if (strlen(demandName) > MAXID) return 252;
// Locate target demand in node's demands list
d = finddemand(p->network.Node[nodeIndex].D, demandIndex);
if (d == NULL) return 253;
// Locate demand category record and assign demandName to it
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);
}
// Assign category name to target demand
d->Name = xstrcpy(&d->Name, demandName, MAXID);
return 0;
}
@@ -2976,18 +2998,19 @@ int DLLEXPORT EN_getdemandpattern(EN_Project p, int nodeIndex, int demandIndex,
**----------------------------------------------------------------
*/
{
Pdemand d;
// Check for valid arguments
*patIndex = 0;
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);
if (!lnode)
return 253;
else
*patIndex = get_pattern_index(lnode);
// Locate target demand in node's demand list
d = finddemand(p->network.Node[nodeIndex].D, demandIndex);
if (d == NULL) return 253;
// Retrieve that demand's pattern index
*patIndex = d->Pat;
return 0;
}
@@ -3005,29 +3028,19 @@ int DLLEXPORT EN_setdemandpattern(EN_Project p, int nodeIndex, int demandIndex,
{
Network *net = &p->network;
Pdemand d;
// 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;
if (patIndex < 0 || patIndex > net->Npats) return 205;
// Locate demand category record and assign time pattern to it
if (nodeIndex <= net->Njuncs) {
// Locate target demand in node's demand list
d = finddemand(p->network.Node[nodeIndex].D, demandIndex);
if (d == NULL) return 253;
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);
}
}
// Assign new time pattern to target demand
d->Pat = patIndex;
return 0;
}

View File

@@ -385,6 +385,22 @@ int DLLEXPORT ENsetdemandmodel(int model, EN_API_FLOAT_TYPE pmin,
return EN_setdemandmodel(_defaultProject, model, pmin, preq, pexp);
}
int DLLEXPORT ENadddemand(int nodeIndex, EN_API_FLOAT_TYPE baseDemand,
char *demandPattern, char *demandName)
{
return EN_adddemand(_defaultProject, nodeIndex, baseDemand, demandPattern, demandName);
}
int DLLEXPORT ENdeletedemand(int nodeIndex, int demandIndex)
{
return EN_deletedemand(_defaultProject, nodeIndex, demandIndex);
}
int DLLEXPORT ENgetdemandindex(int nodeIndex, char *demandName, int *demandIndex)
{
return EN_getdemandindex(_defaultProject, nodeIndex, demandName, demandIndex);
}
int DLLEXPORT ENgetnumdemands(int nodeIndex, int *numDemands)
{
return EN_getnumdemands(_defaultProject, nodeIndex, numDemands);

View File

@@ -37,6 +37,10 @@ int findpump(Network *, int);
int findpattern(Network *, char *);
int findcurve(Network *, char *);
Pdemand finddemand(Pdemand, int);
int adddemand(Snode *, double, int, char *);
void freedemands(Snode *);
void adjustpatterns(Network *, int);
void adjustcurves(Network *, int);
int resizecurve(Scurve *, int);

View File

@@ -27,9 +27,6 @@
#include "funcs.h"
#include "text.h"
#include "demand.h"
const double QZERO = 1.e-6; // Equivalent to zero flow in cfs
// Imported functions
@@ -556,7 +553,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;
@@ -566,19 +563,15 @@ void demands(Project *pr)
for (i = 1; i <= net->Njuncs; i++)
{
sum = 0.0;
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;
}
}
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;
}
hyd->NodeDemand[i] = sum;
// Initialize pressure dependent demand

View File

@@ -28,7 +28,6 @@ Last Updated: 04/03/2019
#include "hash.h"
#include "text.h"
#include "demand.h"
// Defined in enumstxt.h in EPANET.C
extern char *LinkTxt[];
@@ -121,48 +120,6 @@ 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)
/*
-------------------------------------------------
@@ -179,9 +136,9 @@ int saveinpfile(Project *pr, const char *fname)
Times *time = &pr->times;
int i, j, n;
double d, kc, ke, km;
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;
@@ -371,7 +328,21 @@ int saveinpfile(Project *pr, const char *fname)
// Write [DEMANDS] section
write_demands(pr, f);
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 [EMITTERS] section

View File

@@ -20,11 +20,8 @@ Last Updated: 04/03/2019
#endif
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "demand.h"
#include "types.h"
#include "funcs.h"
#include "hash.h"
@@ -222,9 +219,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
@@ -334,14 +331,14 @@ void adjustdata(Project *pr)
// 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);
}
}
}
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;
@@ -544,7 +541,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;
@@ -564,15 +561,10 @@ void convertunits(Project *pr)
for (i = 1; i <= net->Njuncs; i++)
{
node = &net->Node[i];
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];
// }
for (demand = node->D; demand != NULL; demand = demand->next)
{
demand->Base /= pr->Ucf[DEMAND];
}
}
hyd->Pmin /= pr->Ucf[PRESSURE];

View File

@@ -20,10 +20,8 @@ Last Updated: 04/03/2019
#endif
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "demand.h"
#include "types.h"
#include "funcs.h"
#include "hash.h"
@@ -86,10 +84,6 @@ int juncdata(Project *pr)
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
@@ -122,13 +116,9 @@ int juncdata(Project *pr)
node->Type = JUNCTION;
node->Comment = xstrcpy(&node->Comment, parser->Comment, MAXMSG);
// 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;
// Create a demand for the junction and use NodeDemand as an indicator
// to be used when processing demands from the [DEMANDS] section
if (!adddemand(node, y, p, NULL)) return 101;
hyd->NodeDemand[njuncs] = y;
return 0;
}
@@ -713,11 +703,7 @@ int demanddata(Project *pr)
int j, n, p = 0;
double y;
list_t *demand_list = NULL;
demand_data_t *demand_data = NULL;
//Pdemand demand;
//Pdemand cur_demand;
Pdemand demand;
// Extract data from tokens
n = parser->Ntokens;
@@ -741,27 +727,23 @@ int demanddata(Project *pr)
if (p == 0) return setError(parser, 2, 205);
}
// 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);
// Replace any demand entered in [JUNCTIONS] section
demand = net->Node[j].D;
if (demand && hyd->NodeDemand[j] != MISSING)
{
// First category encountered will overwrite demand category
// created when junction was read from [JUNCTIONS] 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 if (!adddemand(&net->Node[j], y, p, parser->Comment) > 0) return 101;
return 0;
}

View File

@@ -29,7 +29,6 @@
#include "types.h"
#include "funcs.h"
#include "demand.h"
int openfiles(Project *pr, const char *f1, const char *f2, const char *f3)
/*----------------------------------------------------------------
@@ -387,7 +386,6 @@ void freedata(Project *pr)
*/
{
int j;
//Pdemand demand, nextdemand;
// Free memory for computed results
free(pr->hydraul.NodeDemand);
@@ -405,12 +403,8 @@ void freedata(Project *pr)
{
for (j = 1; j <= pr->parser.MaxNodes; j++)
{
// Free memory used for demand category list
list_t *demand = pr->network.Node[j].D;
if(demand)
delete_list(demand);
// Free memory used for WQ source data
// Free memory used for demands and WQ source data
freedemands(&(pr->network.Node[j]));
free(pr->network.Node[j].S);
free(pr->network.Node[j].Comment);
}
@@ -471,6 +465,83 @@ void freedata(Project *pr)
}
}
Pdemand finddemand(Pdemand d, int index)
/*----------------------------------------------------------------
** Input: d = pointer to start of a list of demands
** index = the position of the demand to retrieve
** Output: none
** Returns: the demand at the requested position
** Purpose: finds the demand at a given position in a demand list
**----------------------------------------------------------------
*/
{
int n = 1;
if (index <= 0)return NULL;
while (d)
{
if (n == index) break;
n++;
d = d->next;
}
return d;
}
int adddemand(Snode *node, double dbase, int dpat, char *dname)
/*----------------------------------------------------------------
** Input: node = a network junction node
** dbase = base demand value
** dpat = demand pattern index
** dname = name of demand category
** Output: returns TRUE if successful, FALSE if not
** Purpose: adds a new demand category to a node.
**----------------------------------------------------------------
*/
{
Pdemand demand, lastdemand;
// Create a new demand struct
demand = (struct Sdemand *)malloc(sizeof(struct Sdemand));
if (demand == NULL) return FALSE;
// Assign it the designated properties
demand->Base = dbase;
demand->Pat = dpat;
demand->Name = NULL;
if (dname && strlen(dname) > 0) xstrcpy(&demand->Name, dname, MAXID);
demand->next = NULL;
// If node has no demands make this its first demand category
if (node->D == NULL) node->D = demand;
// Otherwise append this demand to the end of the node's demands list
else
{
lastdemand = node->D;
while (lastdemand->next) lastdemand = lastdemand->next;
lastdemand->next = demand;
}
return TRUE;
}
void freedemands(Snode *node)
/*----------------------------------------------------------------
** Input: node = a network junction node
** Output: node
** Purpose: frees the memory used for a node's list of demands.
**----------------------------------------------------------------
*/
{
Pdemand nextdemand;
Pdemand demand = node->D;
while (demand != NULL)
{
nextdemand = demand->next;
free(demand->Name);
free(demand);
demand = nextdemand;
}
node->D = NULL;
}
int buildadjlists(Network *net)
/*
@@ -790,16 +861,6 @@ void adjustpattern(int *pat, int index)
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
@@ -809,17 +870,16 @@ 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
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);
for (demand = network->Node[j].D; demand != NULL; demand = demand->next)
{
adjustpattern(&demand->Pat, index);
}
// Adjust WQ source patterns
source = network->Node[j].S;

View File

@@ -16,9 +16,7 @@
#include <stdio.h>
#include "hash.h"
#include "util/list.h"
/*
-------------------------------------------
@@ -339,14 +337,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
{
@@ -373,8 +371,7 @@ typedef struct // Node Object
double X; // x-coordinate
double Y; // y-coordinate
double El; // elevation
// Pdemand D; // demand pointer
list_t *D; // pointer to demand list
Pdemand D; // demand pointer
Psource S; // source pointer
double C0; // initial quality
double Ke; // emitter coeff.