Merge pull request #688 from OpenWaterAnalytics/681-request-additional-api-function-for-getting-finer-grained-time-step-information

adds an API function to get information about upcoming events
This commit is contained in:
Sam Hatchett
2023-01-20 09:47:17 -05:00
committed by GitHub
11 changed files with 92 additions and 15 deletions

View File

@@ -25,6 +25,7 @@ This document describes the changes and updates that have been made in version 2
- A possible loss of network connectivity when evaluating a Pressure Sustaining Valve was prevented. - A possible loss of network connectivity when evaluating a Pressure Sustaining Valve was prevented.
- Having the implied loss coefficient for an active Flow Control Valve be less than its fully opened value was prevented. - Having the implied loss coefficient for an active Flow Control Valve be less than its fully opened value was prevented.
- A new type of valve, a Positional Control Valve (PCV), was added that uses a valve characteristic curve to relate its loss coefficient to its fraction open setting. - A new type of valve, a Positional Control Valve (PCV), was added that uses a valve characteristic curve to relate its loss coefficient to its fraction open setting.
- A new set of functions have been added to get information about upcoming time step events. Users will now see what type of event is going to cause the end of a time step to occur. See ENtimetonextevent and EN_timetonextevent.
- A new set of functions have been added to allow users to set a reporting callback function. The user-supplied function will recieve all output normally directed to the report file.

View File

@@ -253,6 +253,12 @@ Public Const EN_R_IS_OPEN = 1 ' Rule status types
Public Const EN_R_IS_CLOSED = 2 Public Const EN_R_IS_CLOSED = 2
Public Const EN_R_IS_ACTIVE = 3 Public Const EN_R_IS_ACTIVE = 3
Public Const EN_STEP_REPORT = 0 ' Types of events that can cause a timestep to end
Public Const EN_STEP_HYD = 1
Public Const EN_STEP_WQ = 2
Public Const EN_STEP_TANKEVENT = 3
Public Const EN_STEP_CONTROLEVENT = 4
Public Const EN_MISSING As Double = -1.0E10 Public Const EN_MISSING As Double = -1.0E10
'These are the external functions that comprise the DLL 'These are the external functions that comprise the DLL
@@ -302,6 +308,7 @@ Public Const EN_MISSING As Double = -1.0E10
Declare Function ENgeterror Lib "epanet2.dll" (ByVal errcode As Long, ByVal errmsg As String, ByVal maxLen As Long) As Long Declare Function ENgeterror Lib "epanet2.dll" (ByVal errcode As Long, ByVal errmsg As String, ByVal maxLen As Long) As Long
Declare Function ENgetstatistic Lib "epanet2.dll" (ByVal type_ As Long, ByRef value As Single) As Long Declare Function ENgetstatistic Lib "epanet2.dll" (ByVal type_ As Long, ByRef value As Single) As Long
Declare Function ENgetresultindex Lib "epanet2.dll" (ByVal type_ As Long, ByVal index As Long, ByRef value As Long) As Long Declare Function ENgetresultindex Lib "epanet2.dll" (ByVal type_ As Long, ByVal index As Long, ByRef value As Long) As Long
Declare Function ENtimetonextevent Lib "epanet2.dll" (eventType As Long, duration As Long, elementIndex As Long) As Long
'Analysis Options Functions 'Analysis Options Functions
Declare Function ENgetoption Lib "epanet2.dll" (ByVal option_ As Long, value As Single) As Long Declare Function ENgetoption Lib "epanet2.dll" (ByVal option_ As Long, value As Single) As Long

View File

@@ -131,3 +131,4 @@ EXPORTS
ENstepQ = _ENstepQ@4 ENstepQ = _ENstepQ@4
ENusehydfile = _ENusehydfile@4 ENusehydfile = _ENusehydfile@4
ENwriteline = _ENwriteline@4 ENwriteline = _ENwriteline@4
ENtimetonextevent = _ENtimetonextevent@12

View File

@@ -159,6 +159,8 @@ extern "C" {
int DLLEXPORT ENgetresultindex(int type, int index, int *value); int DLLEXPORT ENgetresultindex(int type, int index, int *value);
int DLLEXPORT ENtimetonextevent(int *eventType, long *duration, int *elementIndex);
int DLLEXPORT ENsetreportcallback(void (*callback)(void *userData, void *EN_projectHandle, char*)); int DLLEXPORT ENsetreportcallback(void (*callback)(void *userData, void *EN_projectHandle, char*));
int DLLEXPORT ENsetreportcallbackuserdata(void *userData); int DLLEXPORT ENsetreportcallbackuserdata(void *userData);

View File

@@ -650,6 +650,16 @@ typedef struct Project *EN_Project;
*/ */
int DLLEXPORT EN_getstatistic(EN_Project ph, int type, double* out_value); int DLLEXPORT EN_getstatistic(EN_Project ph, int type, double* out_value);
/**
@brief Get information about upcoming time step events, and what causes them.
@param ph an EPANET project handle.
@param[out] eventType the type of event that will occur (see @ref EN_TimestepEvent).
@param[out] duration the amount of time in the future this event will occur
@param[out] elementIndex the index of the element causing the event.
**/
int DLLEXPORT EN_timetonextevent(EN_Project ph, int *eventType, long *duration, int *elementIndex);
/** /**
@brief Retrieves the order in which a node or link appears in an @ref OutFile "output file". @brief Retrieves the order in which a node or link appears in an @ref OutFile "output file".
@param ph an EPANET project handle. @param ph an EPANET project handle.

View File

@@ -126,6 +126,18 @@ typedef enum {
EN_NEXTEVENTTANK = 15 //!< Index of tank with shortest time to become empty or full (read only) EN_NEXTEVENTTANK = 15 //!< Index of tank with shortest time to become empty or full (read only)
} EN_TimeParameter; } EN_TimeParameter;
/**
These are the types of events that can cause a timestep to end.
**/
typedef enum {
EN_STEP_REPORT = 0,
EN_STEP_HYD = 1,
EN_STEP_WQ = 2,
EN_STEP_TANKEVENT = 3,
EN_STEP_CONTROLEVENT = 4
} EN_TimestepEvent;
/// Analysis convergence statistics /// Analysis convergence statistics
/** /**
These statistics report the convergence criteria for the most current hydraulic analysis These statistics report the convergence criteria for the most current hydraulic analysis

View File

@@ -1623,6 +1623,42 @@ int DLLEXPORT EN_settimeparam(EN_Project p, int param, long value)
return 0; return 0;
} }
/// get the time to next event, and give a reason for the time step truncation
int DLLEXPORT EN_timetonextevent(EN_Project p, int *eventType, long *duration, int *elementIndex)
{
Times *time = &p->times;
long hydStep, tankStep, controlStep;
int iTank, iControl;
hydStep = time->Hstep;
tankStep = hydStep;
controlStep = hydStep;
iTank = tanktimestep(p, &tankStep);
iControl = controltimestep(p, &controlStep);
// return the lesser of the three step lengths
if (controlStep < tankStep) {
*eventType = (int)EN_STEP_CONTROLEVENT;
*duration = controlStep;
*elementIndex = iControl;
}
else if (tankStep < hydStep) {
*eventType = (int)EN_STEP_TANKEVENT;
*duration = tankStep;
*elementIndex = iTank;
}
else {
*eventType = (int)EN_STEP_HYD;
*duration = hydStep;
*elementIndex = 0;
}
return 0;
}
int DLLEXPORT EN_getqualinfo(EN_Project p, int *qualType, char *chemName, int DLLEXPORT EN_getqualinfo(EN_Project p, int *qualType, char *chemName,
char *chemUnits, int *traceNode) char *chemUnits, int *traceNode)
/*---------------------------------------------------------------- /*----------------------------------------------------------------

View File

@@ -242,6 +242,10 @@ int DLLEXPORT ENgetresultindex(int type, int index, int *value)
return EN_getresultindex(_defaultProject, type, index, value); return EN_getresultindex(_defaultProject, type, index, value);
} }
int DLLEXPORT ENtimetonextevent(int *eventType, long *duration, int *elementIndex)
{
return EN_timetonextevent(_defaultProject, eventType, duration, elementIndex);
}
/******************************************************************** /********************************************************************

View File

@@ -155,6 +155,7 @@ void closehyd(Project *);
void setlinkstatus(Project *, int, char, StatusType *, double *); void setlinkstatus(Project *, int, char, StatusType *, double *);
void setlinksetting(Project *, int, double, StatusType *, double *); void setlinksetting(Project *, int, double, StatusType *, double *);
int tanktimestep(Project *, long *); int tanktimestep(Project *, long *);
int controltimestep(Project *, long *);
void getenergy(Project *, int, double *, double *); void getenergy(Project *, int, double *, double *);
double tankvolume(Project *, int, double); double tankvolume(Project *, int, double);
double tankgrade(Project *, int, double); double tankgrade(Project *, int, double);
@@ -164,7 +165,7 @@ double tankgrade(Project *, int, double);
void resistcoeff(Project *, int); void resistcoeff(Project *, int);
void headlosscoeffs(Project *); void headlosscoeffs(Project *);
void matrixcoeffs(Project *); void matrixcoeffs(Project *);
void emitterheadloss(Project *, int, double *, double *); void emitterheadloss(Project *, int, double *, double *);
void demandheadloss(Project *, int, double, double, double *, double *); void demandheadloss(Project *, int, double, double, double *, double *);
double pcvlosscoeff(Project *, int, double); double pcvlosscoeff(Project *, int, double);

View File

@@ -34,7 +34,6 @@ void initlinkflow(Project *, int, char, double);
void demands(Project *); void demands(Project *);
int controls(Project *); int controls(Project *);
long timestep(Project *); long timestep(Project *);
void controltimestep(Project *, long *);
void ruletimestep(Project *, long *); void ruletimestep(Project *, long *);
void addenergy(Project *, long); void addenergy(Project *, long);
void tanklevels(Project *, long); void tanklevels(Project *, long);
@@ -192,7 +191,7 @@ int runhyd(Project *pr, long *t)
int iter; // Iteration count int iter; // Iteration count
int errcode; // Error code int errcode; // Error code
double relerr; // Solution accuracy double relerr; // Solution accuracy
// Find new demands & control actions // Find new demands & control actions
*t = time->Htime; *t = time->Htime;
demands(pr); demands(pr);
@@ -390,7 +389,7 @@ void setlinkstatus(Project *pr, int index, char value, StatusType *s, double *k
if (t == PUMP) if (t == PUMP)
{ {
*k = 1.0; *k = 1.0;
// Check if a re-opened pump needs its flow reset // Check if a re-opened pump needs its flow reset
if (*s == CLOSED) resetpumpflow(pr, index); if (*s == CLOSED) resetpumpflow(pr, index);
} }
if (t > PUMP && t != GPV) *k = MISSING; if (t > PUMP && t != GPV) *k = MISSING;
@@ -597,11 +596,11 @@ int controls(Project *pr)
k1 = hyd->LinkSetting[k]; k1 = hyd->LinkSetting[k];
k2 = k1; k2 = k1;
if (link->Type > PIPE) k2 = control->Setting; if (link->Type > PIPE) k2 = control->Setting;
// Check if a re-opened pump needs its flow reset // Check if a re-opened pump needs its flow reset
if (link->Type == PUMP && s1 == CLOSED && s2 == OPEN) if (link->Type == PUMP && s1 == CLOSED && s2 == OPEN)
resetpumpflow(pr, k); resetpumpflow(pr, k);
if (s1 != s2 || k1 != k2) if (s1 != s2 || k1 != k2)
{ {
hyd->LinkStatus[k] = s2; hyd->LinkStatus[k] = s2;
@@ -706,7 +705,7 @@ int tanktimestep(Project *pr, long *tstep)
} }
void controltimestep(Project *pr, long *tstep) int controltimestep(Project *pr, long *tstep)
/* /*
**------------------------------------------------------------------ **------------------------------------------------------------------
** Input: *tstep = current time step ** Input: *tstep = current time step
@@ -719,7 +718,7 @@ void controltimestep(Project *pr, long *tstep)
Network *net = &pr->network; Network *net = &pr->network;
Hydraul *hyd = &pr->hydraul; Hydraul *hyd = &pr->hydraul;
int i, j, k, n; int i, j, k, n, controlIndex;
double h, q, v; double h, q, v;
long t, t1, t2; long t, t1, t2;
Slink *link; Slink *link;
@@ -776,9 +775,14 @@ void controltimestep(Project *pr, long *tstep)
k = control->Link; k = control->Link;
link = &net->Link[k]; link = &net->Link[k];
if ( (link->Type > PIPE && hyd->LinkSetting[k] != control->Setting) if ( (link->Type > PIPE && hyd->LinkSetting[k] != control->Setting)
|| (hyd->LinkStatus[k] != control->Status) ) *tstep = t; || (hyd->LinkStatus[k] != control->Status) )
{
*tstep = t;
controlIndex = i;
}
} }
} }
return controlIndex;
} }
@@ -1011,7 +1015,7 @@ void getallpumpsenergy(Project *pr)
getenergy(pr, pump->Link, &(pump->Energy.CurrentPower), getenergy(pr, pump->Link, &(pump->Energy.CurrentPower),
&(pump->Energy.CurrentEffic)); &(pump->Energy.CurrentEffic));
} }
} }
void tanklevels(Project *pr, long tstep) void tanklevels(Project *pr, long tstep)
@@ -1131,6 +1135,5 @@ void resetpumpflow(Project *pr, int i)
Network *net = &pr->network; Network *net = &pr->network;
Spump *pump = &net->Pump[findpump(net, i)]; Spump *pump = &net->Pump[findpump(net, i)];
if (pump->Ptype == CONST_HP) if (pump->Ptype == CONST_HP)
pr->hydraul.LinkFlow[i] = pump->Q0; pr->hydraul.LinkFlow[i] = pump->Q0;
} }

View File

@@ -885,14 +885,14 @@ void writeline(Project *pr, char *s)
**-------------------------------------------------------------- **--------------------------------------------------------------
*/ */
{ {
Report *rpt = &pr->report;
if (pr->report.reportCallback != NULL) if (pr->report.reportCallback != NULL)
{ {
pr->report.reportCallback(pr->report.reportCallbackUserData, pr, s); pr->report.reportCallback(pr->report.reportCallbackUserData, pr, s);
return; return;
} }
Report *rpt = &pr->report;
if (rpt->RptFile == NULL) return; if (rpt->RptFile == NULL) return;
if (rpt->Rptflag) if (rpt->Rptflag)
{ {