Merge pull request #689 from OpenWaterAnalytics/683-request-better-logging-functionality

adds client callback API function
This commit is contained in:
Sam Hatchett
2023-01-19 09:02:02 -05:00
committed by GitHub
7 changed files with 101 additions and 51 deletions

View File

@@ -72,9 +72,9 @@ extern "C" {
int DLLEXPORT ENopen(const char *inpFile, const char *rptFile, int DLLEXPORT ENopen(const char *inpFile, const char *rptFile,
const char *outFile); const char *outFile);
int DLLEXPORT ENgettitle(char *line1, char *line2, char *line3); int DLLEXPORT ENgettitle(char *line1, char *line2, char *line3);
int DLLEXPORT ENsettitle(char *line1, char *line2, char *line3); int DLLEXPORT ENsettitle(char *line1, char *line2, char *line3);
int DLLEXPORT ENgetcomment(int object, int index, char *comment); int DLLEXPORT ENgetcomment(int object, int index, char *comment);
@@ -156,9 +156,13 @@ extern "C" {
int DLLEXPORT ENgeterror(int errcode, char *errmsg, int maxLen); int DLLEXPORT ENgeterror(int errcode, char *errmsg, int maxLen);
int DLLEXPORT ENgetstatistic(int type, EN_API_FLOAT_TYPE* value); int DLLEXPORT ENgetstatistic(int type, EN_API_FLOAT_TYPE* value);
int DLLEXPORT ENgetresultindex(int type, int index, int *value); int DLLEXPORT ENgetresultindex(int type, int index, int *value);
int DLLEXPORT ENsetreportcallback(void (*callback)(void *userData, void *EN_projectHandle, char*));
int DLLEXPORT ENsetreportcallbackuserdata(void *userData);
/******************************************************************** /********************************************************************
Analysis Options Functions Analysis Options Functions
@@ -235,7 +239,7 @@ extern "C" {
char *demandPattern, char *demandName); char *demandPattern, char *demandName);
int DLLEXPORT ENdeletedemand(int nodeIndex, int demandIndex); int DLLEXPORT ENdeletedemand(int nodeIndex, int demandIndex);
int DLLEXPORT ENgetnumdemands(int nodeIndex, int *numDemands); int DLLEXPORT ENgetnumdemands(int nodeIndex, int *numDemands);
int DLLEXPORT ENgetdemandindex(int nodeIndex, char *demandName, int *demandIndex); int DLLEXPORT ENgetdemandindex(int nodeIndex, char *demandName, int *demandIndex);
@@ -285,13 +289,13 @@ extern "C" {
int DLLEXPORT ENsetpipedata(int index, EN_API_FLOAT_TYPE length, int DLLEXPORT ENsetpipedata(int index, EN_API_FLOAT_TYPE length,
EN_API_FLOAT_TYPE diam, EN_API_FLOAT_TYPE rough, EN_API_FLOAT_TYPE diam, EN_API_FLOAT_TYPE rough,
EN_API_FLOAT_TYPE mloss); EN_API_FLOAT_TYPE mloss);
int DLLEXPORT ENgetvertexcount(int index, int *count); int DLLEXPORT ENgetvertexcount(int index, int *count);
int DLLEXPORT ENgetvertex(int index, int vertex, double *x, double *y); int DLLEXPORT ENgetvertex(int index, int vertex, double *x, double *y);
int DLLEXPORT ENsetvertex(int index, int vertex, double x, double y); int DLLEXPORT ENsetvertex(int index, int vertex, double x, double y);
int DLLEXPORT ENsetvertices(int index, double *x, double *y, int count); int DLLEXPORT ENsetvertices(int index, double *x, double *y, int count);
/******************************************************************** /********************************************************************
@@ -351,7 +355,7 @@ extern "C" {
int DLLEXPORT ENgetcurvelen(int index, int *len); int DLLEXPORT ENgetcurvelen(int index, int *len);
int DLLEXPORT ENgetcurvetype(int index, int *type); int DLLEXPORT ENgetcurvetype(int index, int *type);
int DLLEXPORT ENsetcurvetype(int index, int type); int DLLEXPORT ENsetcurvetype(int index, int type);
int DLLEXPORT ENgetcurvevalue(int curveIndex, int pointIndex, int DLLEXPORT ENgetcurvevalue(int curveIndex, int pointIndex,
@@ -425,7 +429,7 @@ extern "C" {
int DLLEXPORT ENsetelseaction(int ruleIndex, int actionIndex, int linkIndex, int DLLEXPORT ENsetelseaction(int ruleIndex, int actionIndex, int linkIndex,
int status, EN_API_FLOAT_TYPE setting); int status, EN_API_FLOAT_TYPE setting);
int DLLEXPORT ENsetrulepriority(int index, EN_API_FLOAT_TYPE priority); int DLLEXPORT ENsetrulepriority(int index, EN_API_FLOAT_TYPE priority);
#if defined(__cplusplus) #if defined(__cplusplus)

View File

@@ -517,6 +517,18 @@ typedef struct Project *EN_Project;
********************************************************************/ ********************************************************************/
/**
@brief Set a user-supplied callback function for reporting
@param ph an EPANET project handle.
@param callback a function pointer with declared signature, which gets called by EPANET for reporting.
@return an error code.
@details The report callback function must have the signature specified - void(void* userData, EN_Project, char*) -
use the userData parameter to pass any client context necessary (a context pointer or wrapper object perhaps).
Leave un-set or set the report callback to NULL to revert to EPANET's default behavior.
**/
int DLLEXPORT EN_setreportcallback(EN_Project ph, void (*callback)(void *userData, void *EN_projectHandle, char*));
int DLLEXPORT EN_setreportcallbackuserdata(EN_Project ph, void *userData);
/** /**
@brief Writes a line of text to a project's report file. @brief Writes a line of text to a project's report file.
@param ph an EPANET project handle. @param ph an EPANET project handle.

View File

@@ -841,6 +841,19 @@ int DLLEXPORT EN_closeQ(EN_Project p)
********************************************************************/ ********************************************************************/
int DLLEXPORT EN_setreportcallback(EN_Project p, void (*callback)(void*,void*,char*))
{
p->report.reportCallback = callback;
return 0;
}
int DLLEXPORT EN_setreportcallbackuserdata(EN_Project p, void *userData)
{
p->report.reportCallbackUserData = userData;
return 0;
}
int DLLEXPORT EN_writeline(EN_Project p, char *line) int DLLEXPORT EN_writeline(EN_Project p, char *line)
/*---------------------------------------------------------------- /*----------------------------------------------------------------
** Input: line = line of text ** Input: line = line of text
@@ -1774,9 +1787,9 @@ int DLLEXPORT EN_addnode(EN_Project p, char *id, int nodeType, int *index)
// Check if a node with same id already exists // Check if a node with same id already exists
if (EN_getnodeindex(p, id, &i) == 0) return 215; if (EN_getnodeindex(p, id, &i) == 0) return 215;
// Check for valid node type // Check for valid node type
if (nodeType < EN_JUNCTION || nodeType > EN_TANK) return 251; if (nodeType < EN_JUNCTION || nodeType > EN_TANK) return 251;
// Grow node-related arrays to accomodate the new node // Grow node-related arrays to accomodate the new node
size = (net->Nnodes + 2) * sizeof(Snode); size = (net->Nnodes + 2) * sizeof(Snode);
@@ -1797,7 +1810,7 @@ int DLLEXPORT EN_addnode(EN_Project p, char *id, int nodeType, int *index)
hashtable_update(net->NodeHashTable, net->Node[i].ID, i + 1); hashtable_update(net->NodeHashTable, net->Node[i].ID, i + 1);
net->Node[i + 1] = net->Node[i]; net->Node[i + 1] = net->Node[i];
} }
// set index of new Junction node // set index of new Junction node
net->Njuncs++; net->Njuncs++;
nIdx = net->Njuncs; nIdx = net->Njuncs;
@@ -2254,20 +2267,20 @@ int DLLEXPORT EN_getnodevalue(EN_Project p, int index, int property, double *val
if (Node[index].Type != TANK) return 0; if (Node[index].Type != TANK) return 0;
v = Tank[index - nJuncs].CanOverflow; v = Tank[index - nJuncs].CanOverflow;
break; break;
case EN_DEMANDDEFICIT: case EN_DEMANDDEFICIT:
if (index > nJuncs) return 0; if (index > nJuncs) return 0;
// After an analysis, DemandFlow contains node's required demand // After an analysis, DemandFlow contains node's required demand
// while NodeDemand contains delivered demand + emitter flow // while NodeDemand contains delivered demand + emitter flow
if (hyd->DemandFlow[index] < 0.0) return 0; if (hyd->DemandFlow[index] < 0.0) return 0;
v = (hyd->DemandFlow[index] - v = (hyd->DemandFlow[index] -
(hyd->NodeDemand[index] - hyd->EmitterFlow[index])) * Ucf[FLOW]; (hyd->NodeDemand[index] - hyd->EmitterFlow[index])) * Ucf[FLOW];
break; break;
case EN_NODE_INCONTROL: case EN_NODE_INCONTROL:
v = (double)incontrols(p, NODE, index); v = (double)incontrols(p, NODE, index);
break; break;
default: default:
return 251; return 251;
} }
@@ -2483,7 +2496,7 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int property, double valu
Tank[j].Vmin = tankvolume(p, j, Tank[j].Hmin); // new min. volume Tank[j].Vmin = tankvolume(p, j, Tank[j].Hmin); // new min. volume
Tank[j].V0 = tankvolume(p, j, Tank[j].H0); // new init. volume Tank[j].V0 = tankvolume(p, j, Tank[j].H0); // new init. volume
Tank[j].Vmax = tankvolume(p, j, Tank[j].Hmax); // new max. volume Tank[j].Vmax = tankvolume(p, j, Tank[j].Hmax); // new max. volume
Tank[j].A = (curve->Y[n] - curve->Y[0]) / // nominal area Tank[j].A = (curve->Y[n] - curve->Y[0]) / // nominal area
(curve->X[n] - curve->X[0]); (curve->X[n] - curve->X[0]);
break; break;
@@ -3801,7 +3814,7 @@ int DLLEXPORT EN_getlinkvalue(EN_Project p, int index, int property, double *val
v = net->Valve[findvalve(&p->network, index)].Curve; v = net->Valve[findvalve(&p->network, index)].Curve;
} }
break; break;
case EN_GPV_CURVE: case EN_GPV_CURVE:
if (Link[index].Type == GPV) if (Link[index].Type == GPV)
{ {
@@ -3812,7 +3825,7 @@ int DLLEXPORT EN_getlinkvalue(EN_Project p, int index, int property, double *val
case EN_LINK_INCONTROL: case EN_LINK_INCONTROL:
v = (double)incontrols(p, LINK, index); v = (double)incontrols(p, LINK, index);
break; break;
default: default:
return 251; return 251;
} }
@@ -4029,7 +4042,7 @@ int DLLEXPORT EN_setlinkvalue(EN_Project p, int index, int property, double valu
net->Valve[findvalve(&p->network, index)].Curve = curveIndex; net->Valve[findvalve(&p->network, index)].Curve = curveIndex;
} }
break; break;
case EN_GPV_CURVE: case EN_GPV_CURVE:
if (Link[index].Type == GPV) if (Link[index].Type == GPV)
{ {
@@ -4095,20 +4108,20 @@ int DLLEXPORT EN_getvertexcount(EN_Project p, int index, int *count)
*/ */
{ {
Network *net = &p->network; Network *net = &p->network;
Slink *Link = net->Link; Slink *Link = net->Link;
Pvertices vertices; Pvertices vertices;
// Check that link exists // Check that link exists
*count = 0; *count = 0;
if (!p->Openflag) return 102; if (!p->Openflag) return 102;
if (index <= 0 || index > net->Nlinks) return 204; if (index <= 0 || index > net->Nlinks) return 204;
// Set count to number of vertices // Set count to number of vertices
vertices = Link[index].Vertices; vertices = Link[index].Vertices;
if (vertices) *count = vertices->Npts; if (vertices) *count = vertices->Npts;
return 0; return 0;
} }
int DLLEXPORT EN_getvertex(EN_Project p, int index, int vertex, double *x, double *y) int DLLEXPORT EN_getvertex(EN_Project p, int index, int vertex, double *x, double *y)
/*---------------------------------------------------------------- /*----------------------------------------------------------------
@@ -4122,22 +4135,22 @@ int DLLEXPORT EN_getvertex(EN_Project p, int index, int vertex, double *x, doubl
*/ */
{ {
Network *net = &p->network; Network *net = &p->network;
Slink *Link = net->Link; Slink *Link = net->Link;
Pvertices vertices; Pvertices vertices;
// Check that link exists // Check that link exists
*x = MISSING; *x = MISSING;
*y = MISSING; *y = MISSING;
if (!p->Openflag) return 102; if (!p->Openflag) return 102;
if (index <= 0 || index > net->Nlinks) return 204; if (index <= 0 || index > net->Nlinks) return 204;
// Check that vertex exists // Check that vertex exists
vertices = Link[index].Vertices; vertices = Link[index].Vertices;
if (vertices == NULL) return 255; if (vertices == NULL) return 255;
if (vertex <= 0 || vertex > vertices->Npts) return 255; if (vertex <= 0 || vertex > vertices->Npts) return 255;
*x = vertices->X[vertex - 1]; *x = vertices->X[vertex - 1];
*y = vertices->Y[vertex - 1]; *y = vertices->Y[vertex - 1];
return 0; return 0;
} }
@@ -4153,23 +4166,23 @@ int DLLEXPORT EN_setvertex(EN_Project p, int index, int vertex, double x, double
*/ */
{ {
Network *net = &p->network; Network *net = &p->network;
Slink *Link = net->Link; Slink *Link = net->Link;
Pvertices vertices; Pvertices vertices;
// Check that link exists // Check that link exists
if (!p->Openflag) return 102; if (!p->Openflag) return 102;
if (index <= 0 || index > net->Nlinks) return 204; if (index <= 0 || index > net->Nlinks) return 204;
// Check that vertex exists // Check that vertex exists
vertices = Link[index].Vertices; vertices = Link[index].Vertices;
if (vertices == NULL) return 255; if (vertices == NULL) return 255;
if (vertex <= 0 || vertex > vertices->Npts) return 255; if (vertex <= 0 || vertex > vertices->Npts) return 255;
vertices->X[vertex - 1] = x; vertices->X[vertex - 1] = x;
vertices->Y[vertex - 1] = y; vertices->Y[vertex - 1] = y;
return 0; return 0;
} }
int DLLEXPORT EN_setvertices(EN_Project p, int index, double *x, double *y, int count) int DLLEXPORT EN_setvertices(EN_Project p, int index, double *x, double *y, int count)
/*---------------------------------------------------------------- /*----------------------------------------------------------------
** Input: index = link index ** Input: index = link index
@@ -4182,11 +4195,11 @@ int DLLEXPORT EN_setvertices(EN_Project p, int index, double *x, double *y, int
*/ */
{ {
Network *net = &p->network; Network *net = &p->network;
Slink *link; Slink *link;
int i; int i;
int err = 0; int err = 0;
// Check that link exists // Check that link exists
if (!p->Openflag) return 102; if (!p->Openflag) return 102;
if (index <= 0 || index > net->Nlinks) return 204; if (index <= 0 || index > net->Nlinks) return 204;
@@ -4194,7 +4207,7 @@ int DLLEXPORT EN_setvertices(EN_Project p, int index, double *x, double *y, int
// Delete existing set of vertices // Delete existing set of vertices
freelinkvertices(link); freelinkvertices(link);
// Add each new vertex to the link // Add each new vertex to the link
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
{ {
@@ -4203,7 +4216,7 @@ int DLLEXPORT EN_setvertices(EN_Project p, int index, double *x, double *y, int
} }
if (err) freelinkvertices(link); if (err) freelinkvertices(link);
return err; return err;
} }
/******************************************************************** /********************************************************************
@@ -4287,16 +4300,16 @@ int DLLEXPORT EN_setheadcurveindex(EN_Project p, int linkIndex, int curveIndex)
pump = &p->network.Pump[pumpIndex]; pump = &p->network.Pump[pumpIndex];
oldCurveIndex = pump->Hcurve; oldCurveIndex = pump->Hcurve;
newCurveType = p->network.Curve[curveIndex].Type; newCurveType = p->network.Curve[curveIndex].Type;
// Assign the new curve to the pump // Assign the new curve to the pump
pump->Ptype = NOCURVE; pump->Ptype = NOCURVE;
pump->Hcurve = curveIndex; pump->Hcurve = curveIndex;
if (curveIndex == 0) return 0; if (curveIndex == 0) return 0;
// Update the pump's head curve parameters (which also changes // Update the pump's head curve parameters (which also changes
// the new curve's Type to PUMP_CURVE) // the new curve's Type to PUMP_CURVE)
err = updatepumpparams(p, pumpIndex); err = updatepumpparams(p, pumpIndex);
// If the parameter updating failed (new curve was not a valid pump curve) // If the parameter updating failed (new curve was not a valid pump curve)
// restore the pump's original curve and its parameters // restore the pump's original curve and its parameters
if (err > 0) if (err > 0)
@@ -4306,8 +4319,8 @@ int DLLEXPORT EN_setheadcurveindex(EN_Project p, int linkIndex, int curveIndex)
pump->Hcurve = oldCurveIndex; pump->Hcurve = oldCurveIndex;
if (oldCurveIndex == 0) return err; if (oldCurveIndex == 0) return err;
updatepumpparams(p, pumpIndex); updatepumpparams(p, pumpIndex);
} }
// Convert the units of the updated pump parameters to feet and cfs // Convert the units of the updated pump parameters to feet and cfs
if (pump->Ptype == POWER_FUNC) if (pump->Ptype == POWER_FUNC)
{ {
@@ -4796,7 +4809,7 @@ int DLLEXPORT EN_setcurvetype(EN_Project p, int index, int type)
Network *net = &p->network; Network *net = &p->network;
if (!p->Openflag) return 102; if (!p->Openflag) return 102;
if (index < 1 || index > net->Ncurves) return 206; if (index < 1 || index > net->Ncurves) return 206;
if (type < 0 || type > EN_GENERIC_CURVE) return 251; if (type < 0 || type > EN_GENERIC_CURVE) return 251;
net->Curve[index].Type = type; net->Curve[index].Type = type;
return 0; return 0;
} }
@@ -4870,7 +4883,7 @@ int DLLEXPORT EN_setcurvevalue(EN_Project p, int curveIndex, int pointIndex,
// Insert new point into curve // Insert new point into curve
curve->X[n] = x; curve->X[n] = x;
curve->Y[n] = y; curve->Y[n] = y;
// Adjust parameters for pumps using curve as a head curve // Adjust parameters for pumps using curve as a head curve
return adjustpumpparams(p, curveIndex); return adjustpumpparams(p, curveIndex);
} }
@@ -4944,7 +4957,7 @@ int DLLEXPORT EN_setcurve(EN_Project p, int index, double *xValues,
curve->X[j] = xValues[j]; curve->X[j] = xValues[j];
curve->Y[j] = yValues[j]; curve->Y[j] = yValues[j];
} }
// Adjust parameters for pumps using curve as a head curve // Adjust parameters for pumps using curve as a head curve
return adjustpumpparams(p, index); return adjustpumpparams(p, index);
} }

View File

@@ -212,6 +212,16 @@ int DLLEXPORT ENsetstatusreport(int level)
return EN_setstatusreport(_defaultProject, level); return EN_setstatusreport(_defaultProject, level);
} }
int DLLEXPORT ENsetreportcallback(void (*callback)(void *userData, void *EN_projectHandle, char*))
{
return EN_setreportcallback(_defaultProject, callback);
}
int DLLEXPORT ENsetreportcallbackuserdata(void *userData)
{
return EN_setreportcallbackuserdata(_defaultProject, userData);
}
int DLLEXPORT ENgetversion(int *version) { return EN_getversion(version); } int DLLEXPORT ENgetversion(int *version) { return EN_getversion(version); }
int DLLEXPORT ENgeterror(int errcode, char *errmsg, int maxLen) int DLLEXPORT ENgeterror(int errcode, char *errmsg, int maxLen)
@@ -516,7 +526,7 @@ int DLLEXPORT ENgetvertexcount(int index, int *count)
{ {
return EN_getvertexcount(_defaultProject, index, count); return EN_getvertexcount(_defaultProject, index, count);
} }
int DLLEXPORT ENgetvertex(int index, int vertex, double *x, double *y) int DLLEXPORT ENgetvertex(int index, int vertex, double *x, double *y)
{ {
return EN_getvertex(_defaultProject, index, vertex, x, y); return EN_getvertex(_defaultProject, index, vertex, x, y);
@@ -530,7 +540,7 @@ int DLLEXPORT ENsetvertex(int index, int vertex, double x, double y)
int DLLEXPORT ENsetvertices(int index, double *x, double *y, int count) int DLLEXPORT ENsetvertices(int index, double *x, double *y, int count)
{ {
return EN_setvertices(_defaultProject, index, x, y, count); return EN_setvertices(_defaultProject, index, x, y, count);
} }
/******************************************************************** /********************************************************************
@@ -714,10 +724,10 @@ int DLLEXPORT ENsetcurve(int index, EN_API_FLOAT_TYPE *xValues,
double *xx = NULL; double *xx = NULL;
double *yy = NULL; double *yy = NULL;
int i, errcode = 0; int i, errcode = 0;
if (xValues == NULL || yValues == NULL) return 206; if (xValues == NULL || yValues == NULL) return 206;
if (nPoints < 1) return 202; if (nPoints < 1) return 202;
xx = (double *)calloc(nPoints, sizeof(double)); xx = (double *)calloc(nPoints, sizeof(double));
yy = (double *)calloc(nPoints, sizeof(double)); yy = (double *)calloc(nPoints, sizeof(double));
if (xx && yy) if (xx && yy)

View File

@@ -281,6 +281,8 @@ void initpointers(Project *pr)
pr->hydraul.smatrix.NZSUB = NULL; pr->hydraul.smatrix.NZSUB = NULL;
pr->hydraul.smatrix.LNZ = NULL; pr->hydraul.smatrix.LNZ = NULL;
pr->report.reportCallback = NULL;
initrules(pr); initrules(pr);
} }

View File

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

View File

@@ -632,7 +632,10 @@ typedef struct {
Rpt2Fname[MAXFNAME+1], // Secondary report file name Rpt2Fname[MAXFNAME+1], // Secondary report file name
DateStamp[26]; // Current date & time DateStamp[26]; // Current date & time
SField Field[MAXVAR]; // Output reporting fields SField Field[MAXVAR]; // Output reporting fields
void (*reportCallback)(void*,void*,char*); // user-supplied reporting callback
void *reportCallbackUserData; // user-supplied reporting context
} Report; } Report;