PDA fixes
This commit is contained in:
46
src/epanet.c
46
src/epanet.c
@@ -7,7 +7,7 @@
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 05/15/2019
|
||||
Last Updated: 07/18/2019
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -68,7 +68,6 @@ int DLLEXPORT EN_deleteproject(EN_Project p)
|
||||
remove(p->TmpOutFname);
|
||||
remove(p->TmpStatFname);
|
||||
free(p);
|
||||
p = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1040,19 +1039,25 @@ int DLLEXPORT EN_getstatistic(EN_Project p, int type, double *value)
|
||||
switch (type)
|
||||
{
|
||||
case EN_ITERATIONS:
|
||||
*value = (double)p->hydraul.Iterations;
|
||||
*value = p->hydraul.Iterations;
|
||||
break;
|
||||
case EN_RELATIVEERROR:
|
||||
*value = (double)p->hydraul.RelativeError;
|
||||
*value = p->hydraul.RelativeError;
|
||||
break;
|
||||
case EN_MAXHEADERROR:
|
||||
*value = (double)(p->hydraul.MaxHeadError * p->Ucf[HEAD]);
|
||||
*value = p->hydraul.MaxHeadError * p->Ucf[HEAD];
|
||||
break;
|
||||
case EN_MAXFLOWCHANGE:
|
||||
*value = (double)(p->hydraul.MaxFlowChange * p->Ucf[FLOW]);
|
||||
*value = p->hydraul.MaxFlowChange * p->Ucf[FLOW];
|
||||
break;
|
||||
case EN_DEFICIENTNODES:
|
||||
*value = p->hydraul.DeficientNodes;
|
||||
break;
|
||||
case EN_DEMANDREDUCTION:
|
||||
*value = p->hydraul.DemandReduction;
|
||||
break;
|
||||
case EN_MASSBALANCE:
|
||||
*value = (double)(p->quality.MassBalance.ratio);
|
||||
*value = p->quality.MassBalance.ratio;
|
||||
break;
|
||||
default:
|
||||
*value = 0.0;
|
||||
@@ -2050,7 +2055,6 @@ int DLLEXPORT EN_getnodevalue(EN_Project p, int index, int property, double *val
|
||||
int nJuncs = net->Njuncs;
|
||||
|
||||
double *Ucf = p->Ucf;
|
||||
double *NodeDemand = hyd->NodeDemand;
|
||||
double *NodeHead = hyd->NodeHead;
|
||||
double *NodeQual = qual->NodeQual;
|
||||
|
||||
@@ -2128,7 +2132,7 @@ int DLLEXPORT EN_getnodevalue(EN_Project p, int index, int property, double *val
|
||||
break;
|
||||
|
||||
case EN_DEMAND:
|
||||
v = NodeDemand[index] * Ucf[FLOW];
|
||||
v = hyd->NodeDemand[index] * Ucf[FLOW];
|
||||
break;
|
||||
|
||||
case EN_HEAD:
|
||||
@@ -2204,7 +2208,16 @@ int DLLEXPORT EN_getnodevalue(EN_Project p, int index, int property, double *val
|
||||
if (Node[index].Type != TANK) return 0;
|
||||
v = Tank[index - nJuncs].CanOverflow;
|
||||
break;
|
||||
|
||||
|
||||
case EN_DEMANDDEFICIT:
|
||||
if (index > nJuncs) return 0;
|
||||
// After an analysis, DemandFlow contains node's required demand
|
||||
// while NodeDemand contains delivered demand + emitter flow
|
||||
if (hyd->DemandFlow[index] < 0.0) return 0;
|
||||
v = (hyd->DemandFlow[index] -
|
||||
(hyd->NodeDemand[index] - hyd->EmitterFlow[index])) * Ucf[FLOW];
|
||||
break;
|
||||
|
||||
default:
|
||||
return 251;
|
||||
}
|
||||
@@ -2702,9 +2715,9 @@ int DLLEXPORT EN_getdemandmodel(EN_Project p, int *model, double *pmin,
|
||||
*/
|
||||
{
|
||||
*model = p->hydraul.DemandModel;
|
||||
*pmin = (double)(p->hydraul.Pmin * p->Ucf[PRESSURE]);
|
||||
*preq = (double)(p->hydraul.Preq * p->Ucf[PRESSURE]);
|
||||
*pexp = (double)(p->hydraul.Pexp);
|
||||
*pmin = p->hydraul.Pmin * p->Ucf[PRESSURE];
|
||||
*preq = p->hydraul.Preq * p->Ucf[PRESSURE];
|
||||
*pexp = p->hydraul.Pexp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2722,7 +2735,12 @@ int DLLEXPORT EN_setdemandmodel(EN_Project p, int model, double pmin,
|
||||
*/
|
||||
{
|
||||
if (model < 0 || model > EN_PDA) return 251;
|
||||
if (pmin > preq || pexp <= 0.0) return 209;
|
||||
if (model == EN_PDA)
|
||||
{
|
||||
if (pexp <= 0.0) return 208;
|
||||
if (pmin < 0.0) return 208;
|
||||
if (preq - pmin < MINPDIFF) return 208;
|
||||
}
|
||||
p->hydraul.DemandModel = model;
|
||||
p->hydraul.Pmin = pmin / p->Ucf[PRESSURE];
|
||||
p->hydraul.Preq = preq / p->Ucf[PRESSURE];
|
||||
|
||||
@@ -22,6 +22,7 @@ DAT(204,"undefined link")
|
||||
DAT(205,"undefined time pattern")
|
||||
DAT(206,"undefined curve")
|
||||
DAT(207,"attempt to control CV/GPV link")
|
||||
DAT(208,"illegal PDA pressure limits")
|
||||
DAT(209,"illegal node property value")
|
||||
DAT(211,"illegal link property value")
|
||||
DAT(212,"undefined trace node")
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 05/15/2019
|
||||
Last Updated: 07/08/2019
|
||||
******************************************************************************
|
||||
*/
|
||||
#ifndef FUNCS_H
|
||||
@@ -157,9 +157,8 @@ double tankgrade(Project *, int, double);
|
||||
void resistcoeff(Project *, int);
|
||||
void headlosscoeffs(Project *);
|
||||
void matrixcoeffs(Project *);
|
||||
void emitheadloss(Project *, int, double *, double *);
|
||||
double demandflowchange(Project *, int, double, double);
|
||||
void demandparams(Project *, double *, double *);
|
||||
void emitterheadloss(Project *, int, double *, double *);
|
||||
void demandheadloss(Project *, int, double, double, double *, double *);
|
||||
|
||||
// ------- QUALITY.C --------------------
|
||||
|
||||
|
||||
128
src/hydcoeffs.c
128
src/hydcoeffs.c
@@ -7,7 +7,7 @@
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 05/15/2019
|
||||
Last Updated: 07/08/2019
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -38,9 +38,8 @@ const double CBIG = 1.e8;
|
||||
//void resistcoeff(Project *, int );
|
||||
//void headlosscoeffs(Project *);
|
||||
//void matrixcoeffs(Project *);
|
||||
//void emitheadloss(Project *, int, double *, double *);
|
||||
//double demandflowchange(Project *, int, double, double);
|
||||
//void demandparams(Project *, double *, double *);
|
||||
//void emitterheadloss(Project *, int, double *, double *);
|
||||
//void demandheadloss(Project *, int, double, double, double *, double *);
|
||||
|
||||
// Local functions
|
||||
static void linkcoeffs(Project *pr);
|
||||
@@ -48,8 +47,6 @@ static void nodecoeffs(Project *pr);
|
||||
static void valvecoeffs(Project *pr);
|
||||
static void emittercoeffs(Project *pr);
|
||||
static void demandcoeffs(Project *pr);
|
||||
static void demandheadloss(double d, double dfull, double dp,
|
||||
double n, double *hloss, double *hgrad);
|
||||
|
||||
static void pipecoeff(Project *pr, int k);
|
||||
static void DWpipecoeff(Project *pr, int k);
|
||||
@@ -370,7 +367,7 @@ void emittercoeffs(Project *pr)
|
||||
if (node->Ke == 0.0) continue;
|
||||
|
||||
// Find emitter head loss and gradient
|
||||
emitheadloss(pr, i, &hloss, &hgrad);
|
||||
emitterheadloss(pr, i, &hloss, &hgrad);
|
||||
|
||||
// Row of solution matrix
|
||||
row = sm->Row[i];
|
||||
@@ -385,7 +382,7 @@ void emittercoeffs(Project *pr)
|
||||
}
|
||||
|
||||
|
||||
void emitheadloss(Project *pr, int i, double *hloss, double *hgrad)
|
||||
void emitterheadloss(Project *pr, int i, double *hloss, double *hgrad)
|
||||
/*
|
||||
**-------------------------------------------------------------
|
||||
** Input: i = node index
|
||||
@@ -424,37 +421,6 @@ void emitheadloss(Project *pr, int i, double *hloss, double *hgrad)
|
||||
}
|
||||
|
||||
|
||||
void demandparams(Project *pr, double *dp, double *n)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: dp = pressure range over which demands can vary
|
||||
** n = exponent in head loss v. demand function
|
||||
** Purpose: retrieves parameters that define a pressure
|
||||
** dependent demand function.
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
// If required pressure equals minimum pressure, use a linear demand
|
||||
// curve with a 0.01 PSI pressure range to approximate an all or
|
||||
// nothing demand solution
|
||||
if (hyd->Preq == hyd->Pmin)
|
||||
{
|
||||
*dp = 0.01 / PSIperFT;
|
||||
*n = 1.0;
|
||||
}
|
||||
|
||||
// Otherwise use the user-supplied demand curve parameters
|
||||
else
|
||||
{
|
||||
*dp = hyd->Preq - hyd->Pmin;
|
||||
*n = 1.0 / hyd->Pexp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void demandcoeffs(Project *pr)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
@@ -479,81 +445,57 @@ void demandcoeffs(Project *pr)
|
||||
n, // exponent in head loss v. demand function
|
||||
hloss, // head loss in supplying demand (ft)
|
||||
hgrad; // gradient of demand head loss (ft/cfs)
|
||||
|
||||
|
||||
// Get demand function parameters
|
||||
if (hyd->DemandModel == DDA) return;
|
||||
demandparams(pr, &dp, &n);
|
||||
dp = hyd->Preq - hyd->Pmin;
|
||||
n = 1.0 / hyd->Pexp;
|
||||
|
||||
// Examine each junction node
|
||||
for (i = 1; i <= net->Njuncs; i++)
|
||||
{
|
||||
// Skip junctions with non-positive demands
|
||||
if (hyd->NodeDemand[i] <= 0.0) continue;
|
||||
|
||||
|
||||
// Find head loss for demand outflow at node's elevation
|
||||
demandheadloss(hyd->DemandFlow[i], hyd->NodeDemand[i], dp, n,
|
||||
&hloss, &hgrad);
|
||||
|
||||
demandheadloss(pr, i, dp, n, &hloss, &hgrad);
|
||||
|
||||
// Update row of solution matrix A & its r.h.s. F
|
||||
row = sm->Row[i];
|
||||
sm->Aii[row] += 1.0 / hgrad;
|
||||
sm->F[row] += (hloss + net->Node[i].El + hyd->Pmin) / hgrad;
|
||||
if (hgrad > 0.0)
|
||||
{
|
||||
row = sm->Row[i];
|
||||
sm->Aii[row] += 1.0 / hgrad;
|
||||
sm->F[row] += (hloss + net->Node[i].El + hyd->Pmin) / hgrad;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
double demandflowchange(Project *pr, int i, double dp, double n)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: i = node index
|
||||
** dp = pressure range fro demand funtion (ft)
|
||||
** n = exponent in head v. demand function
|
||||
** Output: returns change in pressure dependent demand flow
|
||||
** Purpose: computes change in outflow at at a node subject to
|
||||
** pressure dependent demands
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
double hloss, hgrad;
|
||||
|
||||
demandheadloss(hyd->DemandFlow[i], hyd->NodeDemand[i], dp, n, &hloss, &hgrad);
|
||||
return (hloss - hyd->NodeHead[i] + pr->network.Node[i].El + hyd->Pmin) / hgrad;
|
||||
}
|
||||
|
||||
|
||||
void demandheadloss(double d, double dfull, double dp, double n,
|
||||
void demandheadloss(Project *pr, int i, double dp, double n,
|
||||
double *hloss, double *hgrad)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: d = actual junction demand (cfs)
|
||||
** dfull = full junction demand required (cfs)
|
||||
** dp = pressure range for demand function (ft)
|
||||
** n = exponent in head v. demand function
|
||||
** Output: hloss = head loss delivering demand d (ft)
|
||||
** Input: i = junction index
|
||||
** dp = pressure range for demand function (ft)
|
||||
** n = exponent in head v. demand function
|
||||
** Output: hloss = pressure dependent demand head loss (ft)
|
||||
** hgrad = gradient of head loss (ft/cfs)
|
||||
** Purpose: computes head loss and its gradient for delivering
|
||||
** a pressure dependent demand flow.
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
const double RB = 1.0e9;
|
||||
const double EPS = 0.001;
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
const double EPS = 0.01;
|
||||
double d = hyd->DemandFlow[i];
|
||||
double dfull = hyd->NodeDemand[i];
|
||||
double r = d / dfull;
|
||||
|
||||
// Use upper barrier function for excess demand above full value
|
||||
if (r > 1.0)
|
||||
{
|
||||
*hgrad = RB;
|
||||
*hloss = dp + RB * (d - dfull);
|
||||
}
|
||||
|
||||
|
||||
// Use lower barrier function for negative demand
|
||||
else if (r < 0)
|
||||
if (r <= 0)
|
||||
{
|
||||
*hgrad = RB;
|
||||
*hloss = RB * d;
|
||||
*hgrad = CBIG;
|
||||
*hloss = CBIG * d;
|
||||
}
|
||||
|
||||
// Use linear head loss function for near zero demand
|
||||
@@ -568,7 +510,15 @@ void demandheadloss(double d, double dfull, double dp, double n,
|
||||
{
|
||||
*hgrad = n * dp * pow(r, n - 1.0) / dfull;
|
||||
*hloss = (*hgrad) * d / n;
|
||||
|
||||
// Add on barrier function for any demand above full value
|
||||
if (r >= 1.0)
|
||||
{
|
||||
*hgrad += CBIG;
|
||||
*hloss += CBIG * (d - dfull);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -195,7 +195,7 @@ int runhyd(Project *pr, long *t)
|
||||
int iter; // Iteration count
|
||||
int errcode; // Error code
|
||||
double relerr; // Solution accuracy
|
||||
|
||||
|
||||
// Find new demands & control actions
|
||||
*t = time->Htime;
|
||||
demands(pr);
|
||||
@@ -203,7 +203,6 @@ int runhyd(Project *pr, long *t)
|
||||
|
||||
// Solve network hydraulic equations
|
||||
errcode = hydsolve(pr,&iter,&relerr);
|
||||
|
||||
if (!errcode)
|
||||
{
|
||||
// Report new status & save results
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 05/15/2019
|
||||
Last Updated: 07/15/2019
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -50,6 +50,7 @@ static void newdemandflows(Project *, Hydbalance *, double *, double *);
|
||||
|
||||
static void checkhydbalance(Project *, Hydbalance *);
|
||||
static int hasconverged(Project *, double *, Hydbalance *);
|
||||
static int pdaconverged(Project *);
|
||||
static void reporthydbal(Project *, Hydbalance *);
|
||||
|
||||
|
||||
@@ -92,12 +93,17 @@ int hydsolve(Project *pr, int *iter, double *relerr)
|
||||
int valveChange; // Valve status change flag
|
||||
int statChange; // Non-valve status change flag
|
||||
Hydbalance hydbal; // Hydraulic balance errors
|
||||
double fullDemand; // Full demand for a node (cfs)
|
||||
|
||||
// Initialize status checking & relaxation factor
|
||||
nextcheck = hyd->CheckFreq;
|
||||
hyd->RelaxFactor = 1.0;
|
||||
|
||||
// Initialize convergence criteria and PDA results
|
||||
hydbal.maxheaderror = 0.0;
|
||||
hydbal.maxflowchange = 0.0;
|
||||
hyd->DeficientNodes = 0;
|
||||
hyd->DemandReduction = 0.0;
|
||||
|
||||
// Repeat iterations until convergence or trial limit is exceeded.
|
||||
// (ExtraIter used to increase trials in case of status cycling.)
|
||||
@@ -189,10 +195,12 @@ int hydsolve(Project *pr, int *iter, double *relerr)
|
||||
errcode = 110;
|
||||
}
|
||||
|
||||
// Replace junction demands with total outflow values
|
||||
// Store actual junction outflow in NodeDemand & full demand in DemandFlow
|
||||
for (i = 1; i <= net->Njuncs; i++)
|
||||
{
|
||||
fullDemand = hyd->NodeDemand[i];
|
||||
hyd->NodeDemand[i] = hyd->DemandFlow[i] + hyd->EmitterFlow[i];
|
||||
hyd->DemandFlow[i] = fullDemand;
|
||||
}
|
||||
|
||||
// Save convergence info
|
||||
@@ -200,7 +208,6 @@ int hydsolve(Project *pr, int *iter, double *relerr)
|
||||
hyd->MaxHeadError = hydbal.maxheaderror;
|
||||
hyd->MaxFlowChange = hydbal.maxflowchange;
|
||||
hyd->Iterations = *iter;
|
||||
|
||||
return errcode;
|
||||
}
|
||||
|
||||
@@ -484,11 +491,12 @@ void newemitterflows(Project *pr, Hydbalance *hbal, double *qsum,
|
||||
if (net->Node[i].Ke == 0.0) continue;
|
||||
|
||||
// Find emitter head loss and gradient
|
||||
emitheadloss(pr, i, &hloss, &hgrad);
|
||||
emitterheadloss(pr, i, &hloss, &hgrad);
|
||||
|
||||
// Find emitter flow change
|
||||
dh = hyd->NodeHead[i] - net->Node[i].El;
|
||||
dq = (hloss - dh) / hgrad;
|
||||
dq *= hyd->RelaxFactor;
|
||||
hyd->EmitterFlow[i] -= dq;
|
||||
|
||||
// Update system flow summation
|
||||
@@ -523,32 +531,39 @@ void newdemandflows(Project *pr, Hydbalance *hbal, double *qsum, double *dqsum)
|
||||
|
||||
double dp, // pressure range over which demand can vary (ft)
|
||||
dq, // change in demand flow (cfs)
|
||||
n; // exponent in head loss v. demand function
|
||||
int k;
|
||||
|
||||
n, // exponent in head loss v. demand function
|
||||
hloss, // current head loss through outflow junction (ft)
|
||||
hgrad, // head loss gradient with respect to flow (ft/cfs)
|
||||
dh; // new head loss through outflow junction (ft)
|
||||
int i;
|
||||
|
||||
// Get demand function parameters
|
||||
if (hyd->DemandModel == DDA) return;
|
||||
demandparams(pr, &dp, &n);
|
||||
dp = MAX((hyd->Preq - hyd->Pmin), MINPDIFF);
|
||||
n = 1.0 / hyd->Pexp;
|
||||
|
||||
// Examine each junction
|
||||
for (k = 1; k <= net->Njuncs; k++)
|
||||
for (i = 1; i <= net->Njuncs; i++)
|
||||
{
|
||||
// Skip junctions with no positive demand
|
||||
if (hyd->NodeDemand[k] <= 0.0) continue;
|
||||
|
||||
if (hyd->NodeDemand[i] <= 0.0) continue;
|
||||
|
||||
// Find change in demand flow (see hydcoeffs.c)
|
||||
dq = demandflowchange(pr, k, dp, n);
|
||||
hyd->DemandFlow[k] -= dq;
|
||||
demandheadloss(pr, i, dp, n, &hloss, &hgrad);
|
||||
dh = hyd->NodeHead[i] - net->Node[i].El - hyd->Pmin;
|
||||
dq = (hloss - dh) / hgrad;
|
||||
dq *= hyd->RelaxFactor;
|
||||
hyd->DemandFlow[i] -= dq;
|
||||
|
||||
// Update system flow summation
|
||||
*qsum += ABS(hyd->DemandFlow[k]);
|
||||
*qsum += ABS(hyd->DemandFlow[i]);
|
||||
*dqsum += ABS(dq);
|
||||
|
||||
// Update identity of element with max. flow change
|
||||
if (ABS(dq) > hbal->maxflowchange)
|
||||
{
|
||||
hbal->maxflowchange = ABS(dq);
|
||||
hbal->maxflownode = k;
|
||||
hbal->maxflownode = i;
|
||||
hbal->maxflowlink = -1;
|
||||
}
|
||||
}
|
||||
@@ -605,20 +620,72 @@ int hasconverged(Project *pr, double *relerr, Hydbalance *hbal)
|
||||
*/
|
||||
{
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
|
||||
// Check that total relative flow change is small enough
|
||||
if (*relerr > hyd->Hacc) return 0;
|
||||
|
||||
// Find largest head loss error and absolute flow change
|
||||
checkhydbalance(pr, hbal);
|
||||
if (pr->report.Statflag == FULL)
|
||||
{
|
||||
reporthydbal(pr, hbal);
|
||||
}
|
||||
|
||||
// Check that head loss error and flow change criteria are met
|
||||
if (hyd->HeadErrorLimit > 0.0 &&
|
||||
hbal->maxheaderror > hyd->HeadErrorLimit) return 0;
|
||||
if (hyd->FlowChangeLimit > 0.0 &&
|
||||
hbal->maxflowchange > hyd->FlowChangeLimit) return 0;
|
||||
|
||||
// Check for pressure driven analysis convergence
|
||||
if (hyd->DemandModel == PDA) return pdaconverged(pr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int pdaconverged(Project *pr)
|
||||
/*
|
||||
**--------------------------------------------------------------
|
||||
** Input: none
|
||||
** Output: returns 1 if PDA converged, 0 if not
|
||||
** Purpose: checks if pressure driven analysis has converged
|
||||
** and updates total demand deficit
|
||||
**--------------------------------------------------------------
|
||||
*/
|
||||
{
|
||||
Hydraul *hyd = &pr->hydraul;
|
||||
|
||||
const double TOL = 0.001;
|
||||
int i, converged = 1;
|
||||
double totalDemand = 0.0, totalReduction = 0.0;
|
||||
|
||||
hyd->DeficientNodes = 0;
|
||||
hyd->DemandReduction = 0.0;
|
||||
|
||||
// Add up number of junctions with demand deficits
|
||||
for (i = 1; i <= pr->network.Njuncs; i++)
|
||||
{
|
||||
// Skip nodes whose required demand is non-positive
|
||||
if (hyd->NodeDemand[i] <= 0.0) continue;
|
||||
|
||||
// Check for negative demand flow or positive demand flow at negative pressure
|
||||
if (hyd->DemandFlow[i] < -TOL) converged = 0;
|
||||
if (hyd->DemandFlow[i] > TOL &&
|
||||
hyd->NodeHead[i] - pr->network.Node[i].El - hyd->Pmin < -TOL)
|
||||
converged = 0;
|
||||
|
||||
// Accumulate total required demand and demand deficit
|
||||
if (hyd->DemandFlow[i] + 0.0001 < hyd->NodeDemand[i])
|
||||
{
|
||||
hyd->DeficientNodes++;
|
||||
totalDemand += hyd->NodeDemand[i];
|
||||
totalReduction += hyd->NodeDemand[i] - hyd->DemandFlow[i];
|
||||
}
|
||||
}
|
||||
if (totalDemand > 0.0)
|
||||
hyd->DemandReduction = totalReduction / totalDemand * 100.0;
|
||||
return converged;
|
||||
}
|
||||
|
||||
|
||||
void reporthydbal(Project *pr, Hydbalance *hbal)
|
||||
/*
|
||||
|
||||
15
src/input1.c
15
src/input1.c
@@ -7,7 +7,7 @@ Description: retrieves network data from an EPANET input file
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 05/15/2019
|
||||
Last Updated: 07/08/2019
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -109,7 +109,7 @@ void setdefaults(Project *pr)
|
||||
hyd->HeadErrorLimit = 0.0; // Default head error limit
|
||||
hyd->DemandModel = DDA; // Demand driven analysis
|
||||
hyd->Pmin = 0.0; // Minimum demand pressure (ft)
|
||||
hyd->Preq = 0.0; // Required demand pressure (ft)
|
||||
hyd->Preq = MINPDIFF; // Required demand pressure (ft)
|
||||
hyd->Pexp = 0.5; // Pressure function exponent
|
||||
hyd->MaxIter = MAXITER; // Default max. hydraulic trials
|
||||
hyd->ExtraIter = -1; // Stop if network unbalanced
|
||||
@@ -267,7 +267,7 @@ void adjustdata(Project *pr)
|
||||
// Revise pressure units depending on flow units
|
||||
if (parser->Unitsflag != SI) parser->Pressflag = PSI;
|
||||
else if (parser->Pressflag == PSI) parser->Pressflag = METERS;
|
||||
|
||||
|
||||
// Store value of viscosity & diffusivity
|
||||
ucf = 1.0;
|
||||
if (parser->Unitsflag == SI) ucf = SQR(MperFT);
|
||||
@@ -322,9 +322,9 @@ void adjustdata(Project *pr)
|
||||
if (tank->Kb == MISSING) tank->Kb = qual->Kbulk;
|
||||
}
|
||||
|
||||
// Use default pattern if none assigned to a demand
|
||||
parser->DefPat = findpattern(net, parser->DefPatID);
|
||||
if (parser->DefPat > 0) for (i = 1; i <= net->Nnodes; i++)
|
||||
// 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)
|
||||
@@ -559,7 +559,8 @@ void convertunits(Project *pr)
|
||||
demand->Base /= pr->Ucf[DEMAND];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Convert PDA pressure limits
|
||||
hyd->Pmin /= pr->Ucf[PRESSURE];
|
||||
hyd->Preq /= pr->Ucf[PRESSURE];
|
||||
|
||||
|
||||
@@ -1924,12 +1924,20 @@ int optionvalue(Project *pr, int n)
|
||||
else if (match(tok0, w_MINIMUM))
|
||||
{
|
||||
if (y < 0.0) return setError(parser, nvalue, 213);
|
||||
// Required pressure still at default value
|
||||
if (hyd->Preq == MINPDIFF)
|
||||
hyd->Preq = y + MINPDIFF;
|
||||
// Required pressure already entered
|
||||
else if (hyd->Preq - y < MINPDIFF)
|
||||
return setError(parser, nvalue, 208);
|
||||
hyd->Pmin = y;
|
||||
return 0;
|
||||
}
|
||||
else if (match(tok0, w_REQUIRED))
|
||||
{
|
||||
if (y < 0.0) return setError(parser, nvalue, 213);
|
||||
if (y - hyd->Pmin < MINPDIFF)
|
||||
return setError(parser, nvalue, 208);
|
||||
hyd->Preq = y;
|
||||
return 0;
|
||||
}
|
||||
|
||||
93
src/report.c
93
src/report.c
@@ -7,7 +7,7 @@
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 06/20/2019
|
||||
Last Updated: 07/15/2019
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -358,7 +358,15 @@ void writehydstat(Project *pr, int iter, double relerr)
|
||||
{
|
||||
if (relerr <= hyd->Hacc) sprintf(s1, FMT58, atime, iter);
|
||||
else sprintf(s1, FMT59, atime, iter, relerr);
|
||||
writeline(pr, s1);
|
||||
writeline(pr, s1);
|
||||
if (hyd->DemandModel == PDA && hyd->DeficientNodes > 0)
|
||||
{
|
||||
if (hyd->DeficientNodes == 1)
|
||||
sprintf(s1, FMT69a, hyd->DemandReduction);
|
||||
else
|
||||
sprintf(s1, FMT69b, hyd->DeficientNodes, hyd->DemandReduction);
|
||||
writeline(pr, s1);
|
||||
}
|
||||
}
|
||||
|
||||
// Display status changes for tanks:
|
||||
@@ -1064,14 +1072,9 @@ int writehydwarn(Project *pr, int iter, double relerr)
|
||||
int i, j;
|
||||
char flag = 0;
|
||||
int s;
|
||||
Snode *Node = net->Node;
|
||||
Slink *Link = net->Link;
|
||||
Spump *Pump = net->Pump;
|
||||
Svalve *Valve = net->Valve;
|
||||
const int Njuncs = net->Njuncs;
|
||||
double *NodeDemand = hyd->NodeDemand;
|
||||
double *LinkFlow = hyd->LinkFlow;
|
||||
double *LinkSetting = hyd->LinkSetting;
|
||||
Snode *node;
|
||||
Slink *link;
|
||||
Spump *pump;
|
||||
|
||||
// Check if system unstable
|
||||
if (iter > hyd->MaxIter && relerr <= hyd->Hacc)
|
||||
@@ -1081,29 +1084,41 @@ int writehydwarn(Project *pr, int iter, double relerr)
|
||||
flag = 2;
|
||||
}
|
||||
|
||||
// Check for negative pressures
|
||||
for (i = 1; i <= Njuncs; i++)
|
||||
// Check for pressure deficient nodes
|
||||
if (hyd->DemandModel == DDA)
|
||||
{
|
||||
Snode *node = &Node[i];
|
||||
if (hyd->NodeHead[i] < node->El && NodeDemand[i] > 0.0)
|
||||
hyd->DeficientNodes = 0;
|
||||
for (i = 1; i <= net->Njuncs; i++)
|
||||
{
|
||||
sprintf(pr->Msg, WARN06, clocktime(rpt->Atime, time->Htime));
|
||||
if (rpt->Messageflag) writeline(pr, pr->Msg);
|
||||
node = &net->Node[i];
|
||||
if (hyd->NodeHead[i] < node->El && hyd->NodeDemand[i] > 0.0)
|
||||
hyd->DeficientNodes++;
|
||||
}
|
||||
if (hyd->DeficientNodes > 0)
|
||||
{
|
||||
if (rpt->Messageflag)
|
||||
{
|
||||
sprintf(pr->Msg, WARN06, clocktime(rpt->Atime, time->Htime));
|
||||
writeline(pr, pr->Msg);
|
||||
}
|
||||
flag = 6;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for abnormal valve condition
|
||||
for (i = 1; i <= net->Nvalves; i++)
|
||||
{
|
||||
j = Valve[i].Link;
|
||||
j = net->Valve[i].Link;
|
||||
link = &net->Link[j];
|
||||
if (hyd->LinkStatus[j] >= XFCV)
|
||||
{
|
||||
sprintf(pr->Msg, WARN05, LinkTxt[Link[j].Type], Link[j].ID,
|
||||
StatTxt[hyd->LinkStatus[j]],
|
||||
clocktime(rpt->Atime, time->Htime));
|
||||
if (rpt->Messageflag) writeline(pr, pr->Msg);
|
||||
if (rpt->Messageflag)
|
||||
{
|
||||
sprintf(pr->Msg, WARN05, LinkTxt[link->Type], link->ID,
|
||||
StatTxt[hyd->LinkStatus[j]],
|
||||
clocktime(rpt->Atime, time->Htime));
|
||||
writeline(pr, pr->Msg);
|
||||
}
|
||||
flag = 5;
|
||||
}
|
||||
}
|
||||
@@ -1111,18 +1126,22 @@ int writehydwarn(Project *pr, int iter, double relerr)
|
||||
// Check for abnormal pump condition
|
||||
for (i = 1; i <= net->Npumps; i++)
|
||||
{
|
||||
j = Pump[i].Link;
|
||||
pump = &net->Pump[i];
|
||||
j = pump->Link;
|
||||
s = hyd->LinkStatus[j];
|
||||
if (hyd->LinkStatus[j] >= OPEN)
|
||||
{
|
||||
if (LinkFlow[j] > LinkSetting[j] * Pump[i].Qmax) s = XFLOW;
|
||||
if (LinkFlow[j] < 0.0) s = XHEAD;
|
||||
if (hyd->LinkFlow[j] > hyd->LinkSetting[j] * pump->Qmax) s = XFLOW;
|
||||
if (hyd->LinkFlow[j] < 0.0) s = XHEAD;
|
||||
}
|
||||
if (s == XHEAD || s == XFLOW)
|
||||
{
|
||||
sprintf(pr->Msg, WARN04, Link[j].ID, StatTxt[s],
|
||||
clocktime(rpt->Atime, time->Htime));
|
||||
if (rpt->Messageflag) writeline(pr, pr->Msg);
|
||||
if (rpt->Messageflag)
|
||||
{
|
||||
sprintf(pr->Msg, WARN04, net->Link[j].ID, StatTxt[s],
|
||||
clocktime(rpt->Atime, time->Htime));
|
||||
writeline(pr, pr->Msg);
|
||||
}
|
||||
flag = 4;
|
||||
}
|
||||
}
|
||||
@@ -1130,9 +1149,12 @@ int writehydwarn(Project *pr, int iter, double relerr)
|
||||
// Check if system is unbalanced
|
||||
if (iter > hyd->MaxIter && relerr > hyd->Hacc)
|
||||
{
|
||||
sprintf(pr->Msg, WARN01, clocktime(rpt->Atime, time->Htime));
|
||||
if (hyd->ExtraIter == -1) strcat(pr->Msg, t_HALTED);
|
||||
if (rpt->Messageflag) writeline(pr, pr->Msg);
|
||||
if (rpt->Messageflag)
|
||||
{
|
||||
sprintf(pr->Msg, WARN01, clocktime(rpt->Atime, time->Htime));
|
||||
if (hyd->ExtraIter == -1) strcat(pr->Msg, t_HALTED);
|
||||
writeline(pr, pr->Msg);
|
||||
}
|
||||
flag = 1;
|
||||
}
|
||||
|
||||
@@ -1162,9 +1184,12 @@ void writehyderr(Project *pr, int errnode)
|
||||
|
||||
Snode *Node = net->Node;
|
||||
|
||||
sprintf(pr->Msg, FMT62, clocktime(rpt->Atime, time->Htime),
|
||||
Node[errnode].ID);
|
||||
if (rpt->Messageflag) writeline(pr, pr->Msg);
|
||||
if (rpt->Messageflag)
|
||||
{
|
||||
sprintf(pr->Msg, FMT62, clocktime(rpt->Atime, time->Htime),
|
||||
Node[errnode].ID);
|
||||
writeline(pr, pr->Msg);
|
||||
}
|
||||
writehydstat(pr, 0, 0);
|
||||
disconnected(pr);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 06/20/2019
|
||||
Last Updated: 07/15/2019
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -428,6 +428,8 @@
|
||||
#define FMT66 " maximum flow change = %.4f for Link %s"
|
||||
#define FMT67 " maximum flow change = %.4f for Node %s"
|
||||
#define FMT68 " maximum head error = %.4f for Link %s\n"
|
||||
#define FMT69a " 1 node had its demand reduced by a total of %.2f%%"
|
||||
#define FMT69b " %-d nodes had demands reduced by a total of %.2f%%"
|
||||
|
||||
//----- Energy Report Table -------------------------------
|
||||
|
||||
|
||||
10
src/types.h
10
src/types.h
@@ -7,7 +7,7 @@
|
||||
Authors: see AUTHORS
|
||||
Copyright: see AUTHORS
|
||||
License: see LICENSE
|
||||
Last Updated: 06/20/2019
|
||||
Last Updated: 07/08/2019
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
@@ -42,7 +42,6 @@ typedef int INT4;
|
||||
#define MAXLINE 1024 // Max. # characters read from input line
|
||||
#define MAXFNAME 259 // Max. # characters in file name
|
||||
#define MAXTOKS 40 // Max. items per line of input
|
||||
#define TZERO 1.E-4 // Zero time tolerance
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#define FULL 2
|
||||
@@ -53,6 +52,7 @@ typedef int INT4;
|
||||
// @ 20 deg C (sq ft/sec)
|
||||
#define VISCOS 1.1E-5 // Kinematic viscosity of water
|
||||
// @ 20 deg C (sq ft/sec)
|
||||
#define MINPDIFF 0.1 // PDA min. pressure difference (psi or m)
|
||||
#define SEPSTR " \t\n\r" // Token separator characters
|
||||
#ifdef M_PI
|
||||
#define PI M_PI
|
||||
@@ -689,7 +689,7 @@ typedef struct {
|
||||
double
|
||||
*NodeHead, // Node hydraulic heads
|
||||
*NodeDemand, // Node demand + emitter flows
|
||||
*DemandFlow, // Demand outflows
|
||||
*DemandFlow, // Work array of demand flows
|
||||
*EmitterFlow, // Emitter outflows
|
||||
*LinkFlow, // Link flows
|
||||
*LinkSetting, // Link settings
|
||||
@@ -716,6 +716,7 @@ typedef struct {
|
||||
RelativeError, // Total flow change / total flow
|
||||
MaxHeadError, // Max. error for link head loss
|
||||
MaxFlowChange, // Max. change in link flow
|
||||
DemandReduction, // % demand reduction at pressure deficient nodes
|
||||
RelaxFactor, // Relaxation factor for flow updating
|
||||
*P, // Inverse of head loss derivatives
|
||||
*Y, // Flow correction factors
|
||||
@@ -731,7 +732,8 @@ typedef struct {
|
||||
CheckFreq, // Hydraulic trials between status checks
|
||||
MaxCheck, // Hydraulic trials limit on status checks
|
||||
OpenHflag, // Hydraulic system opened flag
|
||||
Haltflag; // Flag to halt simulation
|
||||
Haltflag, // Flag to halt simulation
|
||||
DeficientNodes; // Number of pressure deficient nodes
|
||||
|
||||
StatusType
|
||||
*LinkStatus, // Link status
|
||||
|
||||
Reference in New Issue
Block a user