Add EN_openX function
EN_openX allows an EPANET input file to be opened even if it has errors. This required re-arranging code, mainly in input3.c, so that default values are assigned to an object before its input line is parsed.
This commit is contained in:
@@ -5,7 +5,7 @@ Attribute VB_Name = "Module1"
|
|||||||
'Declarations of functions in the EPANET PROGRAMMERs TOOLKIT
|
'Declarations of functions in the EPANET PROGRAMMERs TOOLKIT
|
||||||
'(EPANET2.DLL)
|
'(EPANET2.DLL)
|
||||||
|
|
||||||
'Last updated on 07/18/2023
|
'Last updated on 09/28/2023
|
||||||
|
|
||||||
' These are codes used by the DLL functions
|
' These are codes used by the DLL functions
|
||||||
Public Const EN_ELEVATION = 0 ' Node parameters
|
Public Const EN_ELEVATION = 0 ' Node parameters
|
||||||
@@ -280,6 +280,7 @@ Public Const EN_SET_OPEN As Double = 1.0E10
|
|||||||
Declare Function ENepanet Lib "epanet2.dll" (ByVal inpFile As String, ByVal rptFile As String, ByVal outFile As String, ByVal pviewprog As Any) As Long
|
Declare Function ENepanet Lib "epanet2.dll" (ByVal inpFile As String, ByVal rptFile As String, ByVal outFile As String, ByVal pviewprog As Any) As Long
|
||||||
Declare Function ENinit Lib "epanet2.dll" (ByVal rptFile As String, ByVal outFile As String, ByVal unitsType As Long, ByVal headlossType As Long) As Long
|
Declare Function ENinit Lib "epanet2.dll" (ByVal rptFile As String, ByVal outFile As String, ByVal unitsType As Long, ByVal headlossType As Long) As Long
|
||||||
Declare Function ENopen Lib "epanet2.dll" (ByVal inpFile As String, ByVal rptFile As String, ByVal outFile As String) As Long
|
Declare Function ENopen Lib "epanet2.dll" (ByVal inpFile As String, ByVal rptFile As String, ByVal outFile As String) As Long
|
||||||
|
Declare Function ENopenX Lib "epanet2.dll" (ByVal inpFile As String, ByVal rptFile As String, ByVal outFile As String) As Long
|
||||||
Declare Function ENgettitle Lib "epanet2.dll" (ByVal line1 As String, ByVal line2 As String, ByVal line3 As String) As Long
|
Declare Function ENgettitle Lib "epanet2.dll" (ByVal line1 As String, ByVal line2 As String, ByVal line3 As String) As Long
|
||||||
Declare Function ENsettitle Lib "epanet2.dll" (ByVal titleline1 As String, ByVal titleline2 As String, ByVal titleline3 As String) As Long
|
Declare Function ENsettitle Lib "epanet2.dll" (ByVal titleline1 As String, ByVal titleline2 As String, ByVal titleline3 As String) As Long
|
||||||
Declare Function ENsaveinpfile Lib "epanet2.dll" (ByVal filename As String) As Long
|
Declare Function ENsaveinpfile Lib "epanet2.dll" (ByVal filename As String) As Long
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ using System.Runtime.CompilerServices;
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
//epanet2.cs[By Oscar Vegas]
|
//epanet2.cs[By Oscar Vegas]
|
||||||
//Last updated on 07/18/2023
|
//Last updated on 09/28/2023
|
||||||
|
|
||||||
//Declarations of functions in the EPANET PROGRAMMERs TOOLKIT
|
//Declarations of functions in the EPANET PROGRAMMERs TOOLKIT
|
||||||
//(EPANET2.DLL) for use with C#
|
//(EPANET2.DLL) for use with C#
|
||||||
@@ -286,6 +286,9 @@ namespace EpanetCSharpLibrary
|
|||||||
[DllImport(EPANETDLL, EntryPoint = "ENopen")]
|
[DllImport(EPANETDLL, EntryPoint = "ENopen")]
|
||||||
public static extern int ENopen(string inpFile, string rptFile, string outFile);
|
public static extern int ENopen(string inpFile, string rptFile, string outFile);
|
||||||
|
|
||||||
|
[DllImport(EPANETDLL, EntryPoint = "ENopenX")]
|
||||||
|
public static extern int ENopenX(string inpFile, string rptFile, string outFile);
|
||||||
|
|
||||||
[DllImport(EPANETDLL, EntryPoint = "ENgettitle")]
|
[DllImport(EPANETDLL, EntryPoint = "ENgettitle")]
|
||||||
public static extern int ENgettitle(string titleline1, string titleline2, string titleline3);
|
public static extern int ENgettitle(string titleline1, string titleline2, string titleline3);
|
||||||
|
|
||||||
|
|||||||
@@ -132,3 +132,4 @@ EXPORTS
|
|||||||
ENusehydfile = _ENusehydfile@4
|
ENusehydfile = _ENusehydfile@4
|
||||||
ENwriteline = _ENwriteline@4
|
ENwriteline = _ENwriteline@4
|
||||||
ENtimetonextevent = _ENtimetonextevent@12
|
ENtimetonextevent = _ENtimetonextevent@12
|
||||||
|
ENopenX = _ENopenX@12
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
Authors: see AUTHORS
|
Authors: see AUTHORS
|
||||||
Copyright: see AUTHORS
|
Copyright: see AUTHORS
|
||||||
License: see LICENSE
|
License: see LICENSE
|
||||||
Last Updated: 02/01/2020
|
Last Updated: 09/28/2023
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -73,6 +73,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 ENopenX(const char *inpFile, const char *rptFile,
|
||||||
|
const char *outFile);
|
||||||
|
|
||||||
int DLLEXPORT ENgettitle(char *line1, char *line2, char *line3);
|
int DLLEXPORT ENgettitle(char *line1, char *line2, char *line3);
|
||||||
|
|
||||||
int DLLEXPORT ENsettitle(const char *line1, const char *line2, const char *line3);
|
int DLLEXPORT ENsettitle(const char *line1, const char *line2, const char *line3);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ unit epanet2;
|
|||||||
{ Declarations of imported procedures from the EPANET PROGRAMMERs TOOLKIT }
|
{ Declarations of imported procedures from the EPANET PROGRAMMERs TOOLKIT }
|
||||||
{ (EPANET2.DLL) }
|
{ (EPANET2.DLL) }
|
||||||
|
|
||||||
{Last updated on 09/11/2023}
|
{Last updated on 09/28/2023}
|
||||||
|
|
||||||
interface
|
interface
|
||||||
|
|
||||||
@@ -281,6 +281,7 @@ const
|
|||||||
function ENepanet(F1: PAnsiChar; F2: PAnsiChar; F3: PAnsiChar; F4: Pointer): Integer; stdcall; external EpanetLib;
|
function ENepanet(F1: PAnsiChar; F2: PAnsiChar; F3: PAnsiChar; F4: Pointer): Integer; stdcall; external EpanetLib;
|
||||||
function ENinit(F2: PAnsiChar; F3: PAnsiChar; UnitsType: Integer; HeadlossType: Integer): Integer; stdcall; external EpanetLib;
|
function ENinit(F2: PAnsiChar; F3: PAnsiChar; UnitsType: Integer; HeadlossType: Integer): Integer; stdcall; external EpanetLib;
|
||||||
function ENopen(F1: PAnsiChar; F2: PAnsiChar; F3: PAnsiChar): Integer; stdcall; external EpanetLib;
|
function ENopen(F1: PAnsiChar; F2: PAnsiChar; F3: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||||
|
function ENopenX(F1: PAnsiChar; F2: PAnsiChar; F3: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||||
function ENgetcount(Code: Integer; var Count: Integer): Integer; stdcall; external EpanetLib;
|
function ENgetcount(Code: Integer; var Count: Integer): Integer; stdcall; external EpanetLib;
|
||||||
function ENgettitle(Line1: PAnsiChar; Line2: PAnsiChar; Line3: PAnsiChar): Integer; stdcall; external EpanetLib;
|
function ENgettitle(Line1: PAnsiChar; Line2: PAnsiChar; Line3: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||||
function ENsettitle(Line1: PAnsiChar; Line2: PAnsiChar; Line3: PAnsiChar): Integer; stdcall; external EpanetLib;
|
function ENsettitle(Line1: PAnsiChar; Line2: PAnsiChar; Line3: PAnsiChar): Integer; stdcall; external EpanetLib;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
'Declarations of functions in the EPANET PROGRAMMERs TOOLKIT
|
'Declarations of functions in the EPANET PROGRAMMERs TOOLKIT
|
||||||
'(EPANET2.DLL) for use with VB.Net.
|
'(EPANET2.DLL) for use with VB.Net.
|
||||||
|
|
||||||
'Last updated on 07/18/2023
|
'Last updated on 09/28/2023
|
||||||
|
|
||||||
Imports System.Runtime.InteropServices
|
Imports System.Runtime.InteropServices
|
||||||
Imports System.Text
|
Imports System.Text
|
||||||
@@ -268,6 +268,7 @@ Public Const EN_SET_OPEN As Double = 1.0E10
|
|||||||
Declare Function ENepanet Lib "epanet2.dll" (ByVal inpFile As String, ByVal rptFile As String, ByVal outFile As String, ByVal pviewprog As Any) As Int32
|
Declare Function ENepanet Lib "epanet2.dll" (ByVal inpFile As String, ByVal rptFile As String, ByVal outFile As String, ByVal pviewprog As Any) As Int32
|
||||||
Declare Function ENinit Lib "epanet2.dll" (ByVal rptFile As String, ByVal outFile As String, ByVal unitsType As Int32, ByVal headlossType As Int32) As Int32
|
Declare Function ENinit Lib "epanet2.dll" (ByVal rptFile As String, ByVal outFile As String, ByVal unitsType As Int32, ByVal headlossType As Int32) As Int32
|
||||||
Declare Function ENopen Lib "epanet2.dll" (ByVal inpFile As String, ByVal rptFile As String, ByVal outFile As String) As Int32
|
Declare Function ENopen Lib "epanet2.dll" (ByVal inpFile As String, ByVal rptFile As String, ByVal outFile As String) As Int32
|
||||||
|
Declare Function ENopenX Lib "epanet2.dll" (ByVal inpFile As String, ByVal rptFile As String, ByVal outFile As String) As Int32
|
||||||
Declare Function ENgettitle Lib "epanet2.dll" (ByVal titleline1 As String, ByVal titleline2 As String, ByVal titleline3 As String) As Int32
|
Declare Function ENgettitle Lib "epanet2.dll" (ByVal titleline1 As String, ByVal titleline2 As String, ByVal titleline3 As String) As Int32
|
||||||
Declare Function ENsettitle Lib "epanet2.dll" (ByVal titleline1 As String, ByVal titleline2 As String, ByVal titleline3 As String) As Int32
|
Declare Function ENsettitle Lib "epanet2.dll" (ByVal titleline1 As String, ByVal titleline2 As String, ByVal titleline3 As String) As Int32
|
||||||
Declare Function ENsaveinpfile Lib "epanet2.dll" (ByVal filename As String) As Int32
|
Declare Function ENsaveinpfile Lib "epanet2.dll" (ByVal filename As String) As Int32
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
Authors: see AUTHORS
|
Authors: see AUTHORS
|
||||||
Copyright: see AUTHORS
|
Copyright: see AUTHORS
|
||||||
License: see LICENSE
|
License: see LICENSE
|
||||||
Last Updated: 02/01/2020
|
Last Updated: 09/28/2023
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -113,7 +113,7 @@ typedef struct Project *EN_Project;
|
|||||||
int unitsType, int headLossType);
|
int unitsType, int headLossType);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief Opens an EPANET input file & reads in network data.
|
@brief Reads an EPANET input file with no errors allowed.
|
||||||
@param ph an EPANET project handle.
|
@param ph an EPANET project handle.
|
||||||
@param inpFile the name of an existing EPANET-formatted input file.
|
@param inpFile the name of an existing EPANET-formatted input file.
|
||||||
@param rptFile the name of a report file to be created (or "" if not needed).
|
@param rptFile the name of a report file to be created (or "" if not needed).
|
||||||
@@ -121,11 +121,27 @@ typedef struct Project *EN_Project;
|
|||||||
@return an error code.
|
@return an error code.
|
||||||
|
|
||||||
This function should be called immediately after ::EN_createproject if an EPANET-formatted
|
This function should be called immediately after ::EN_createproject if an EPANET-formatted
|
||||||
input file will be used to supply network data.
|
input file will be used to supply network data. If errors are detected then the project is
|
||||||
|
not opened and will not accept toolkit function calls.
|
||||||
*/
|
*/
|
||||||
int DLLEXPORT EN_open(EN_Project ph, const char *inpFile, const char *rptFile,
|
int DLLEXPORT EN_open(EN_Project ph, const char *inpFile, const char *rptFile,
|
||||||
const char *outFile);
|
const char *outFile);
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Reads an EPANET input file with errors allowed.
|
||||||
|
@param ph an EPANET project handle.
|
||||||
|
@param inpFile the name of an existing EPANET-formatted input file.
|
||||||
|
@param rptFile the name of a report file to be created (or "" if not needed).
|
||||||
|
@param outFile the name of a binary output file to be created (or "" if not needed).
|
||||||
|
@return an error code.
|
||||||
|
|
||||||
|
This function should be called immediately after ::EN_createproject if an EPANET-formatted
|
||||||
|
input file will be used to supply network data. If formatting errors are detected (error
|
||||||
|
code = 200) then the project remains open and will accept toolkit function calls.
|
||||||
|
*/
|
||||||
|
int DLLEXPORT EN_openX(EN_Project ph, const char *inpFile, const char *rptFile,
|
||||||
|
const char *outFile);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief Retrieves the title lines of the project
|
@brief Retrieves the title lines of the project
|
||||||
@param ph an EPANET project handle.
|
@param ph an EPANET project handle.
|
||||||
|
|||||||
134
src/epanet.c
134
src/epanet.c
@@ -7,7 +7,7 @@
|
|||||||
Authors: see AUTHORS
|
Authors: see AUTHORS
|
||||||
Copyright: see AUTHORS
|
Copyright: see AUTHORS
|
||||||
License: see LICENSE
|
License: see LICENSE
|
||||||
Last Updated: 07/17/2023
|
Last Updated: 09/28/2023
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -179,61 +179,30 @@ int DLLEXPORT EN_open(EN_Project p, const char *inpFile, const char *rptFile,
|
|||||||
** outFile = name of binary output file
|
** outFile = name of binary output file
|
||||||
** Output: none
|
** Output: none
|
||||||
** Returns: error code
|
** Returns: error code
|
||||||
** Purpose: opens an EPANET input file & reads in network data
|
** Purpose: reads an EPANET input file with no errors allowed.
|
||||||
**----------------------------------------------------------------
|
**----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
int errcode = 0;
|
|
||||||
|
|
||||||
// Set system flags
|
|
||||||
p->Openflag = FALSE;
|
|
||||||
p->hydraul.OpenHflag = FALSE;
|
|
||||||
p->quality.OpenQflag = FALSE;
|
|
||||||
p->outfile.SaveHflag = FALSE;
|
|
||||||
p->outfile.SaveQflag = FALSE;
|
|
||||||
p->Warnflag = FALSE;
|
|
||||||
p->report.Messageflag = TRUE;
|
|
||||||
p->report.Rptflag = 1;
|
|
||||||
|
|
||||||
// Initialize data arrays to NULL
|
|
||||||
initpointers(p);
|
|
||||||
|
|
||||||
// Open input & report files
|
|
||||||
ERRCODE(openfiles(p, inpFile, rptFile, outFile));
|
|
||||||
if (errcode > 0)
|
|
||||||
{
|
|
||||||
errmsg(p, errcode);
|
|
||||||
return errcode;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate memory for project's data arrays
|
|
||||||
writewin(p->viewprog, FMT100);
|
writewin(p->viewprog, FMT100);
|
||||||
ERRCODE(netsize(p));
|
return openproject(p, inpFile, rptFile, outFile, FALSE);
|
||||||
ERRCODE(allocdata(p));
|
}
|
||||||
|
|
||||||
// Read input data
|
int DLLEXPORT EN_openX(EN_Project p, const char *inpFile,
|
||||||
ERRCODE(getdata(p));
|
const char *rptFile, const char *outFile)
|
||||||
|
/*----------------------------------------------------------------
|
||||||
// Close input file
|
** Input: inpFile = name of input file
|
||||||
if (p->parser.InFile != NULL)
|
** rptFile = name of report file
|
||||||
|
** outFile = name of binary output file
|
||||||
|
** Output: none
|
||||||
|
** Returns: error code
|
||||||
|
** Purpose: reads an EPANET input file with errors allowed.
|
||||||
|
**----------------------------------------------------------------
|
||||||
|
*/
|
||||||
{
|
{
|
||||||
fclose(p->parser.InFile);
|
writewin(p->viewprog, FMT100);
|
||||||
p->parser.InFile = NULL;
|
return openproject(p, inpFile, rptFile, outFile, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If using previously saved hydraulics file then open it
|
|
||||||
if (p->outfile.Hydflag == USE) ERRCODE(openhydfile(p));
|
|
||||||
|
|
||||||
// Write input summary to report file
|
|
||||||
if (!errcode)
|
|
||||||
{
|
|
||||||
if (p->report.Summaryflag) writesummary(p);
|
|
||||||
writetime(p, FMT104);
|
|
||||||
p->Openflag = TRUE;
|
|
||||||
}
|
|
||||||
else errmsg(p, errcode);
|
|
||||||
return errcode;
|
|
||||||
}
|
|
||||||
|
|
||||||
int DLLEXPORT EN_gettitle(EN_Project p, char *line1, char *line2, char *line3)
|
int DLLEXPORT EN_gettitle(EN_Project p, char *line1, char *line2, char *line3)
|
||||||
/*----------------------------------------------------------------
|
/*----------------------------------------------------------------
|
||||||
@@ -359,7 +328,6 @@ int DLLEXPORT EN_close(EN_Project p)
|
|||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
// Free all project data
|
// Free all project data
|
||||||
if (p->Openflag) writetime(p, FMT105);
|
|
||||||
freedata(p);
|
freedata(p);
|
||||||
|
|
||||||
// Close output file
|
// Close output file
|
||||||
@@ -495,7 +463,11 @@ int DLLEXPORT EN_openH(EN_Project p)
|
|||||||
|
|
||||||
// Open hydraulics solver
|
// Open hydraulics solver
|
||||||
ERRCODE(openhyd(p));
|
ERRCODE(openhyd(p));
|
||||||
if (!errcode) p->hydraul.OpenHflag = TRUE;
|
if (!errcode)
|
||||||
|
{
|
||||||
|
p->hydraul.OpenHflag = TRUE;
|
||||||
|
writetime(p, FMT104);
|
||||||
|
}
|
||||||
else errmsg(p, errcode);
|
else errmsg(p, errcode);
|
||||||
return errcode;
|
return errcode;
|
||||||
}
|
}
|
||||||
@@ -834,6 +806,7 @@ int DLLEXPORT EN_closeQ(EN_Project p)
|
|||||||
closequal(p);
|
closequal(p);
|
||||||
p->quality.OpenQflag = FALSE;
|
p->quality.OpenQflag = FALSE;
|
||||||
closeoutfile(p);
|
closeoutfile(p);
|
||||||
|
writetime(p, FMT105);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1929,7 +1902,7 @@ int DLLEXPORT EN_addnode(EN_Project p, const char *id, int nodeType, int *index)
|
|||||||
if (control->Node > net->Njuncs - 1) control->Node += 1;
|
if (control->Node > net->Njuncs - 1) control->Node += 1;
|
||||||
}
|
}
|
||||||
// adjust indices of tanks/reservoirs in Rule premises (see RULES.C)
|
// adjust indices of tanks/reservoirs in Rule premises (see RULES.C)
|
||||||
adjusttankrules(p);
|
adjusttankrules(p, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actions taken when a new Tank/Reservoir is added
|
// Actions taken when a new Tank/Reservoir is added
|
||||||
@@ -4086,12 +4059,7 @@ int DLLEXPORT EN_setlinkvalue(EN_Project p, int index, int property, double valu
|
|||||||
pumpIndex = findpump(&p->network, index);
|
pumpIndex = findpump(&p->network, index);
|
||||||
net->Pump[pumpIndex].Ptype = CONST_HP;
|
net->Pump[pumpIndex].Ptype = CONST_HP;
|
||||||
net->Pump[pumpIndex].Hcurve = 0;
|
net->Pump[pumpIndex].Hcurve = 0;
|
||||||
net->Link[index].Km = value;
|
net->Link[index].Km = value / Ucf[POWER];
|
||||||
updatepumpparams(p, pumpIndex);
|
|
||||||
net->Pump[pumpIndex].R /= Ucf[POWER];
|
|
||||||
net->Pump[pumpIndex].Q0 /= Ucf[FLOW];
|
|
||||||
net->Pump[pumpIndex].Qmax /= Ucf[FLOW];
|
|
||||||
net->Pump[pumpIndex].Hmax /= Ucf[HEAD];
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -4380,10 +4348,7 @@ int DLLEXPORT EN_setheadcurveindex(EN_Project p, int linkIndex, int curveIndex)
|
|||||||
{
|
{
|
||||||
Network *net = &p->network;
|
Network *net = &p->network;
|
||||||
|
|
||||||
double *Ucf = p->Ucf;
|
|
||||||
int pumpIndex;
|
int pumpIndex;
|
||||||
int oldCurveIndex;
|
|
||||||
int newCurveType;
|
|
||||||
int err = 0;
|
int err = 0;
|
||||||
Spump *pump;
|
Spump *pump;
|
||||||
|
|
||||||
@@ -4393,43 +4358,12 @@ int DLLEXPORT EN_setheadcurveindex(EN_Project p, int linkIndex, int curveIndex)
|
|||||||
if (PUMP != net->Link[linkIndex].Type) return 0;
|
if (PUMP != net->Link[linkIndex].Type) return 0;
|
||||||
if (curveIndex < 0 || curveIndex > net->Ncurves) return 206;
|
if (curveIndex < 0 || curveIndex > net->Ncurves) return 206;
|
||||||
|
|
||||||
// Save values that need to be restored in case new curve is invalid
|
|
||||||
pumpIndex = findpump(net, linkIndex);
|
|
||||||
pump = &p->network.Pump[pumpIndex];
|
|
||||||
oldCurveIndex = pump->Hcurve;
|
|
||||||
newCurveType = p->network.Curve[curveIndex].Type;
|
|
||||||
|
|
||||||
// Assign the new curve to the pump
|
// Assign the new curve to the pump
|
||||||
pump->Ptype = NOCURVE;
|
pumpIndex = findpump(net, linkIndex);
|
||||||
|
pump = &net->Pump[pumpIndex];
|
||||||
pump->Hcurve = curveIndex;
|
pump->Hcurve = curveIndex;
|
||||||
if (curveIndex == 0) return 0;
|
net->Link[linkIndex].Km = 0.0;
|
||||||
|
return 0;
|
||||||
// Update the pump's head curve parameters (which also changes
|
|
||||||
// the new curve's Type to PUMP_CURVE)
|
|
||||||
err = updatepumpparams(p, pumpIndex);
|
|
||||||
|
|
||||||
// If the parameter updating failed (new curve was not a valid pump curve)
|
|
||||||
// restore the pump's original curve and its parameters
|
|
||||||
if (err > 0)
|
|
||||||
{
|
|
||||||
p->network.Curve[curveIndex].Type = newCurveType;
|
|
||||||
pump->Ptype = NOCURVE;
|
|
||||||
pump->Hcurve = oldCurveIndex;
|
|
||||||
if (oldCurveIndex == 0) return err;
|
|
||||||
updatepumpparams(p, pumpIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert the units of the updated pump parameters to feet and cfs
|
|
||||||
if (pump->Ptype == POWER_FUNC)
|
|
||||||
{
|
|
||||||
pump->H0 /= Ucf[HEAD];
|
|
||||||
pump->R *= (pow(Ucf[FLOW], pump->N) / Ucf[HEAD]);
|
|
||||||
}
|
|
||||||
pump->Q0 /= Ucf[FLOW];
|
|
||||||
pump->Qmax /= Ucf[FLOW];
|
|
||||||
pump->Hmax /= Ucf[HEAD];
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
@@ -4907,7 +4841,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_VALVE_CURVE) return 251;
|
||||||
net->Curve[index].Type = type;
|
net->Curve[index].Type = type;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -4981,9 +4915,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;
|
||||||
|
return 0;
|
||||||
// Adjust parameters for pumps using curve as a head curve
|
|
||||||
return adjustpumpparams(p, curveIndex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int DLLEXPORT EN_getcurve(EN_Project p, int index, char *id, int *nPoints,
|
int DLLEXPORT EN_getcurve(EN_Project p, int index, char *id, int *nPoints,
|
||||||
@@ -5055,9 +4987,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];
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
// Adjust parameters for pumps using curve as a head curve
|
|
||||||
return adjustpumpparams(p, index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
Authors: see AUTHORS
|
Authors: see AUTHORS
|
||||||
Copyright: see AUTHORS
|
Copyright: see AUTHORS
|
||||||
License: see LICENSE
|
License: see LICENSE
|
||||||
Last Updated: 02/01/2020
|
Last Updated: 09/28/2023
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -99,6 +99,14 @@ int DLLEXPORT ENopen(const char *inpFile, const char *rptFile, const char *outFi
|
|||||||
return errcode;
|
return errcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int DLLEXPORT ENopenX(const char *inpFile, const char *rptFile, const char *outFile)
|
||||||
|
{
|
||||||
|
int errcode = 0;
|
||||||
|
createtmpfiles();
|
||||||
|
errcode = EN_openX(_defaultProject, inpFile, rptFile, outFile);
|
||||||
|
return errcode;
|
||||||
|
}
|
||||||
|
|
||||||
int DLLEXPORT ENgettitle(char *line1, char *line2, char *line3)
|
int DLLEXPORT ENgettitle(char *line1, char *line2, char *line3)
|
||||||
{
|
{
|
||||||
return EN_gettitle(_defaultProject, line1, line2, line3) ;
|
return EN_gettitle(_defaultProject, line1, line2, line3) ;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ DAT(120,"cannot solve water quality transport equations")
|
|||||||
// These errors apply only to an input file
|
// These errors apply only to an input file
|
||||||
DAT(200,"one or more errors in input file")
|
DAT(200,"one or more errors in input file")
|
||||||
DAT(201,"syntax error")
|
DAT(201,"syntax error")
|
||||||
|
DAT(299,"invalid section keyword")
|
||||||
|
|
||||||
// These errors apply to both an input file and to API functions
|
// These errors apply to both an input file and to API functions
|
||||||
DAT(202,"illegal numeric value")
|
DAT(202,"illegal numeric value")
|
||||||
@@ -43,6 +44,8 @@ DAT(225,"invalid lower/upper levels for tank")
|
|||||||
DAT(226,"no head curve or power rating for pump")
|
DAT(226,"no head curve or power rating for pump")
|
||||||
DAT(227,"invalid head curve for pump")
|
DAT(227,"invalid head curve for pump")
|
||||||
DAT(230,"nonincreasing x-values for curve")
|
DAT(230,"nonincreasing x-values for curve")
|
||||||
|
DAT(231,"no data provided for curve")
|
||||||
|
DAT(232,"no data provided for pattern")
|
||||||
DAT(233,"network has unconnected nodes")
|
DAT(233,"network has unconnected nodes")
|
||||||
DAT(234,"network has an unconnected node with ID: ")
|
DAT(234,"network has an unconnected node with ID: ")
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
Authors: see AUTHORS
|
Authors: see AUTHORS
|
||||||
Copyright: see AUTHORS
|
Copyright: see AUTHORS
|
||||||
License: see LICENSE
|
License: see LICENSE
|
||||||
Last Updated: 04/29/2023
|
Last Updated: 09/28/2023
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
#ifndef FUNCS_H
|
#ifndef FUNCS_H
|
||||||
@@ -19,6 +19,7 @@ void initpointers(Project *);
|
|||||||
int allocdata(Project *);
|
int allocdata(Project *);
|
||||||
void freedata(Project *);
|
void freedata(Project *);
|
||||||
|
|
||||||
|
int openproject(Project *, const char *, const char *, const char *, int);
|
||||||
int openfiles(Project *, const char *, const char *,const char *);
|
int openfiles(Project *, const char *, const char *,const char *);
|
||||||
int openhydfile(Project *);
|
int openhydfile(Project *);
|
||||||
int openoutfile(Project *);
|
int openoutfile(Project *);
|
||||||
@@ -48,7 +49,6 @@ void freelinkvertices(Slink *);
|
|||||||
|
|
||||||
void adjustpatterns(Network *, int);
|
void adjustpatterns(Network *, int);
|
||||||
void adjustcurves(Network *, int);
|
void adjustcurves(Network *, int);
|
||||||
int adjustpumpparams(Project *, int);
|
|
||||||
int resizecurve(Scurve *, int);
|
int resizecurve(Scurve *, int);
|
||||||
int setcontrol(Project *, int, int, double, int, double, Scontrol *);
|
int setcontrol(Project *, int, int, double, int, double, Scontrol *);
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@ int getdata(Project *);
|
|||||||
void setdefaults(Project *);
|
void setdefaults(Project *);
|
||||||
void initreport(Report *);
|
void initreport(Report *);
|
||||||
void adjustdata(Project *);
|
void adjustdata(Project *);
|
||||||
int inittanks(Project *);
|
void inittanks(Project *);
|
||||||
void initunits(Project *);
|
void initunits(Project *);
|
||||||
void convertunits(Project *);
|
void convertunits(Project *);
|
||||||
|
|
||||||
@@ -78,7 +78,6 @@ void convertunits(Project *);
|
|||||||
|
|
||||||
int netsize(Project *);
|
int netsize(Project *);
|
||||||
int readdata(Project *);
|
int readdata(Project *);
|
||||||
int updatepumpparams(Project *, int);
|
|
||||||
int findmatch(char *, char *[]);
|
int findmatch(char *, char *[]);
|
||||||
int match(const char *, const char *);
|
int match(const char *, const char *);
|
||||||
int gettokens(char *, char **, int, char *);
|
int gettokens(char *, char **, int, char *);
|
||||||
@@ -120,7 +119,7 @@ void freerules(Project *);
|
|||||||
int ruledata(Project *);
|
int ruledata(Project *);
|
||||||
void ruleerrmsg(Project *);
|
void ruleerrmsg(Project *);
|
||||||
void adjustrules(Project *, int, int);
|
void adjustrules(Project *, int, int);
|
||||||
void adjusttankrules(Project *);
|
void adjusttankrules(Project *, int);
|
||||||
Spremise *getpremise(Spremise *, int);
|
Spremise *getpremise(Spremise *, int);
|
||||||
Saction *getaction(Saction *, int);
|
Saction *getaction(Saction *, int);
|
||||||
int writerule(Project *, FILE *, int);
|
int writerule(Project *, FILE *, int);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
Authors: see AUTHORS
|
Authors: see AUTHORS
|
||||||
Copyright: see AUTHORS
|
Copyright: see AUTHORS
|
||||||
License: see LICENSE
|
License: see LICENSE
|
||||||
Last Updated: 08/02/2023
|
Last Updated: 09/28/2023
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
const double QZERO = 1.e-6; // Equivalent to zero flow in cfs
|
const double QZERO = 1.e-6; // Equivalent to zero flow in cfs
|
||||||
|
|
||||||
// Imported functions
|
// Imported functions
|
||||||
|
extern int validateproject(Project *);
|
||||||
extern int createsparse(Project *);
|
extern int createsparse(Project *);
|
||||||
extern void freesparse(Project *);
|
extern void freesparse(Project *);
|
||||||
extern int hydsolve(Project *, int *, double *);
|
extern int hydsolve(Project *, int *, double *);
|
||||||
@@ -53,9 +54,9 @@ int openhyd(Project *pr)
|
|||||||
int errcode = 0;
|
int errcode = 0;
|
||||||
Slink *link;
|
Slink *link;
|
||||||
|
|
||||||
// Check for too few nodes & no fixed grade nodes
|
// Check for valid project data (see VALIDATE.C)
|
||||||
if (pr->network.Nnodes < 2) errcode = 223;
|
errcode = validateproject(pr);
|
||||||
else if (pr->network.Ntanks == 0) errcode = 224;
|
if (errcode > 0) return errcode;
|
||||||
|
|
||||||
// Allocate memory for sparse matrix structures (see SMATRIX.C)
|
// Allocate memory for sparse matrix structures (see SMATRIX.C)
|
||||||
ERRCODE(createsparse(pr));
|
ERRCODE(createsparse(pr));
|
||||||
@@ -72,6 +73,7 @@ int openhyd(Project *pr)
|
|||||||
link = &pr->network.Link[i];
|
link = &pr->network.Link[i];
|
||||||
initlinkflow(pr, i, link->Status, link->Kc);
|
initlinkflow(pr, i, link->Status, link->Kc);
|
||||||
}
|
}
|
||||||
|
else closehyd(pr);
|
||||||
return errcode;
|
return errcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1144,3 +1146,4 @@ void resetpumpflow(Project *pr, int i)
|
|||||||
if (pump->Ptype == CONST_HP)
|
if (pump->Ptype == CONST_HP)
|
||||||
pr->hydraul.LinkFlow[i] = pump->Q0;
|
pr->hydraul.LinkFlow[i] = pump->Q0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
74
src/input1.c
74
src/input1.c
@@ -7,7 +7,7 @@ Description: retrieves network data from an EPANET input file
|
|||||||
Authors: see AUTHORS
|
Authors: see AUTHORS
|
||||||
Copyright: see AUTHORS
|
Copyright: see AUTHORS
|
||||||
License: see LICENSE
|
License: see LICENSE
|
||||||
Last Updated: 02/05/2023
|
Last Updated: 09/28/2023
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -40,6 +40,8 @@ Last Updated: 02/05/2023
|
|||||||
// Defined in ENUMSTXT.H
|
// Defined in ENUMSTXT.H
|
||||||
extern char *Fldname[];
|
extern char *Fldname[];
|
||||||
extern char *RptFlowUnitsTxt[];
|
extern char *RptFlowUnitsTxt[];
|
||||||
|
extern void reindextanks(Project *pr);
|
||||||
|
|
||||||
|
|
||||||
int getdata(Project *pr)
|
int getdata(Project *pr)
|
||||||
/*
|
/*
|
||||||
@@ -58,13 +60,18 @@ int getdata(Project *pr)
|
|||||||
|
|
||||||
// Read in network data
|
// Read in network data
|
||||||
rewind(pr->parser.InFile);
|
rewind(pr->parser.InFile);
|
||||||
ERRCODE(readdata(pr));
|
errcode = readdata(pr);
|
||||||
|
|
||||||
// Adjust data and convert it to internal units
|
// Adjust data and convert it to internal units
|
||||||
if (!errcode) adjustdata(pr);
|
// (error code 200 means there are non-fatal errors in input file)
|
||||||
if (!errcode) initunits(pr);
|
if (errcode == 0 || errcode == 200)
|
||||||
ERRCODE(inittanks(pr));
|
{
|
||||||
if (!errcode) convertunits(pr);
|
reindextanks(pr);
|
||||||
|
adjustdata(pr);
|
||||||
|
inittanks(pr);
|
||||||
|
initunits(pr);
|
||||||
|
convertunits(pr);
|
||||||
|
}
|
||||||
return errcode;
|
return errcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,11 +335,11 @@ void adjustdata(Project *pr)
|
|||||||
if (qual->Qualflag == NONE) rpt->Field[QUALITY].Enabled = FALSE;
|
if (qual->Qualflag == NONE) rpt->Field[QUALITY].Enabled = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int inittanks(Project *pr)
|
void inittanks(Project *pr)
|
||||||
/*
|
/*
|
||||||
**---------------------------------------------------------------
|
**---------------------------------------------------------------
|
||||||
** Input: none
|
** Input: none
|
||||||
** Output: returns error code
|
** Output: none
|
||||||
** Purpose: initializes volumes in non-cylindrical tanks
|
** Purpose: initializes volumes in non-cylindrical tanks
|
||||||
**---------------------------------------------------------------
|
**---------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -341,7 +348,7 @@ int inittanks(Project *pr)
|
|||||||
|
|
||||||
int i, j, n = 0;
|
int i, j, n = 0;
|
||||||
double a;
|
double a;
|
||||||
int errcode = 0, levelerr;
|
int errcode = 0;
|
||||||
char errmsg[MAXMSG+1] = "";
|
char errmsg[MAXMSG+1] = "";
|
||||||
Stank *tank;
|
Stank *tank;
|
||||||
Scurve *curve;
|
Scurve *curve;
|
||||||
@@ -351,26 +358,13 @@ int inittanks(Project *pr)
|
|||||||
tank = &net->Tank[j];
|
tank = &net->Tank[j];
|
||||||
if (tank->A == 0.0) continue; // Skip reservoirs
|
if (tank->A == 0.0) continue; // Skip reservoirs
|
||||||
|
|
||||||
// Check for valid lower/upper tank levels
|
// See if tank has a volume curve
|
||||||
levelerr = 0;
|
|
||||||
if (tank->H0 > tank->Hmax ||
|
|
||||||
tank->Hmin > tank->Hmax ||
|
|
||||||
tank->H0 < tank->Hmin
|
|
||||||
) levelerr = 1;
|
|
||||||
|
|
||||||
// Check that tank heights are within volume curve
|
|
||||||
i = tank->Vcurve;
|
i = tank->Vcurve;
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
{
|
{
|
||||||
curve = &net->Curve[i];
|
curve = &net->Curve[i];
|
||||||
n = curve->Npts - 1;
|
n = curve->Npts - 1;
|
||||||
if (tank->Hmin < curve->X[0] || tank->Hmax > curve->X[n])
|
|
||||||
{
|
|
||||||
levelerr = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Find min., max., and initial volumes from curve
|
// Find min., max., and initial volumes from curve
|
||||||
tank->Vmin = interp(curve->Npts, curve->X, curve->Y, tank->Hmin);
|
tank->Vmin = interp(curve->Npts, curve->X, curve->Y, tank->Hmin);
|
||||||
tank->Vmax = interp(curve->Npts, curve->X, curve->Y, tank->Hmax);
|
tank->Vmax = interp(curve->Npts, curve->X, curve->Y, tank->Hmax);
|
||||||
@@ -381,17 +375,6 @@ int inittanks(Project *pr)
|
|||||||
tank->A = sqrt(4.0 * a / PI);
|
tank->A = sqrt(4.0 * a / PI);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Report error in levels if found
|
|
||||||
if (levelerr)
|
|
||||||
{
|
|
||||||
sprintf(pr->Msg, "Error 225: %s node %s", geterrmsg(225, errmsg),
|
|
||||||
net->Node[tank->Node].ID);
|
|
||||||
writeline(pr, pr->Msg);
|
|
||||||
errcode = 200;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return errcode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void initunits(Project *pr)
|
void initunits(Project *pr)
|
||||||
@@ -530,7 +513,6 @@ void convertunits(Project *pr)
|
|||||||
Snode *node;
|
Snode *node;
|
||||||
Stank *tank;
|
Stank *tank;
|
||||||
Slink *link;
|
Slink *link;
|
||||||
Spump *pump;
|
|
||||||
Scontrol *control;
|
Scontrol *control;
|
||||||
|
|
||||||
// Convert nodal elevations & initial WQ
|
// Convert nodal elevations & initial WQ
|
||||||
@@ -615,29 +597,9 @@ void convertunits(Project *pr)
|
|||||||
|
|
||||||
else if (link->Type == PUMP)
|
else if (link->Type == PUMP)
|
||||||
{
|
{
|
||||||
// Convert units for pump curve parameters
|
link->Km /= pr->Ucf[POWER];
|
||||||
i = findpump(net, k);
|
|
||||||
pump = &net->Pump[i];
|
|
||||||
if (pump->Ptype == CONST_HP)
|
|
||||||
{
|
|
||||||
// For constant hp pump, convert kw to hp
|
|
||||||
if (parser->Unitsflag == SI) pump->R /= pr->Ucf[POWER];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// For power curve pumps, convert shutoff head and flow coeff.
|
|
||||||
if (pump->Ptype == POWER_FUNC)
|
|
||||||
{
|
|
||||||
pump->H0 /= pr->Ucf[HEAD];
|
|
||||||
pump->R *= (pow(pr->Ucf[FLOW], pump->N) / pr->Ucf[HEAD]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert flow range & max. head units
|
|
||||||
pump->Q0 /= pr->Ucf[FLOW];
|
|
||||||
pump->Qmax /= pr->Ucf[FLOW];
|
|
||||||
pump->Hmax /= pr->Ucf[HEAD];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// For flow control valves, convert flow setting
|
// For flow control valves, convert flow setting
|
||||||
|
|||||||
215
src/input2.c
215
src/input2.c
@@ -7,7 +7,7 @@ Description: reads and interprets network data from an EPANET input file
|
|||||||
Authors: see AUTHORS
|
Authors: see AUTHORS
|
||||||
Copyright: see AUTHORS
|
Copyright: see AUTHORS
|
||||||
License: see LICENSE
|
License: see LICENSE
|
||||||
Last Updated: 02/03/2020
|
Last Updated: 09/28/2023
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -21,17 +21,13 @@ Last Updated: 02/03/2020
|
|||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
#include "text.h"
|
#include "text.h"
|
||||||
|
|
||||||
#define MAXERRS 10 // Max. input errors reported
|
|
||||||
|
|
||||||
extern char *SectTxt[]; // Input section keywords (see ENUMSTXT.H)
|
extern char *SectTxt[]; // Input section keywords (see ENUMSTXT.H)
|
||||||
|
|
||||||
// Exported functions
|
// Exported functions
|
||||||
int addnodeID(Network *n, int, char *);
|
int addnodeID(Network *, int, char *);
|
||||||
int addlinkID(Network *n, int, char *);
|
int addlinkID(Network *, int, char *);
|
||||||
|
int getunitsoption(Project *, char *);
|
||||||
// Imported functions
|
int getheadlossoption(Project *, char *);
|
||||||
extern int powercurve(double, double, double, double, double, double *,
|
|
||||||
double *, double *);
|
|
||||||
|
|
||||||
// Local functions
|
// Local functions
|
||||||
static int newline(Project *, int, char *);
|
static int newline(Project *, int, char *);
|
||||||
@@ -100,7 +96,11 @@ int netsize(Project *pr)
|
|||||||
if (sect == _END) break;
|
if (sect == _END) break;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else continue;
|
else
|
||||||
|
{
|
||||||
|
sect = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add to count of current object
|
// Add to count of current object
|
||||||
@@ -122,6 +122,12 @@ int netsize(Project *pr)
|
|||||||
errcode = addcurve(&pr->network, tok);
|
errcode = addcurve(&pr->network, tok);
|
||||||
parser->MaxCurves = pr->network.Ncurves;
|
parser->MaxCurves = pr->network.Ncurves;
|
||||||
break;
|
break;
|
||||||
|
case _OPTIONS:
|
||||||
|
if (match(tok, w_UNITS))
|
||||||
|
getunitsoption(pr, strtok(line, SEPSTR));
|
||||||
|
else if (match(tok, w_HEADLOSS))
|
||||||
|
getheadlossoption(pr, strtok(line, SEPSTR));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (errcode) break;
|
if (errcode) break;
|
||||||
}
|
}
|
||||||
@@ -226,9 +232,11 @@ int readdata(Project *pr)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
inperrmsg(pr, 201, sect, line);
|
sect = -1;
|
||||||
|
parser->ErrTok = 0;
|
||||||
errsum++;
|
errsum++;
|
||||||
break;
|
inperrmsg(pr, 299, sect, line);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,23 +252,13 @@ int readdata(Project *pr)
|
|||||||
errsum++;
|
errsum++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else continue;
|
||||||
{
|
|
||||||
errcode = 200;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop if reach end of file or max. error count
|
|
||||||
if (errsum == MAXERRS) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for errors
|
// Check for errors
|
||||||
if (errsum > 0) errcode = 200;
|
if (errsum > 0) errcode = 200;
|
||||||
|
|
||||||
// Determine pump curve parameters
|
|
||||||
if (!errcode) errcode = getpumpparams(pr);
|
|
||||||
|
|
||||||
// Free input buffer
|
// Free input buffer
|
||||||
free(parser->X);
|
free(parser->X);
|
||||||
return errcode;
|
return errcode;
|
||||||
@@ -307,6 +305,7 @@ int newline(Project *pr, int sect, char *line)
|
|||||||
if (ruledata(pr) > 0)
|
if (ruledata(pr) > 0)
|
||||||
{
|
{
|
||||||
ruleerrmsg(pr);
|
ruleerrmsg(pr);
|
||||||
|
deleterule(pr, pr->network.Nrules);
|
||||||
return 200;
|
return 200;
|
||||||
}
|
}
|
||||||
else return 0;
|
else return 0;
|
||||||
@@ -333,127 +332,6 @@ int newline(Project *pr, int sect, char *line)
|
|||||||
return 201;
|
return 201;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getpumpparams(Project *pr)
|
|
||||||
/*
|
|
||||||
**-------------------------------------------------------------
|
|
||||||
** Input: none
|
|
||||||
** Output: returns error code
|
|
||||||
** Purpose: computes pump curve coefficients for all pumps
|
|
||||||
**--------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
Network *net = &pr->network;
|
|
||||||
int i, k, errcode = 0;
|
|
||||||
char errmsg[MAXMSG+1];
|
|
||||||
|
|
||||||
for (i = 1; i <= net->Npumps; i++)
|
|
||||||
{
|
|
||||||
errcode = updatepumpparams(pr, i);
|
|
||||||
if (errcode)
|
|
||||||
{
|
|
||||||
k = net->Pump[i].Link;
|
|
||||||
sprintf(pr->Msg, "Error %d: %s %s",
|
|
||||||
errcode, geterrmsg(errcode, errmsg), net->Link[k].ID);
|
|
||||||
writeline(pr, pr->Msg);
|
|
||||||
return 200;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int updatepumpparams(Project *pr, int pumpindex)
|
|
||||||
/*
|
|
||||||
**-------------------------------------------------------------
|
|
||||||
** Input: pumpindex = index of a pump
|
|
||||||
** Output: returns error code
|
|
||||||
** Purpose: computes & checks a pump's head curve coefficients
|
|
||||||
**--------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
Network *net = &pr->network;
|
|
||||||
Spump *pump;
|
|
||||||
Scurve *curve;
|
|
||||||
|
|
||||||
int m;
|
|
||||||
int curveindex;
|
|
||||||
int npts = 0;
|
|
||||||
int errcode = 0;
|
|
||||||
double a, b, c, h0 = 0.0, h1 = 0.0, h2 = 0.0, q1 = 0.0, q2 = 0.0;
|
|
||||||
|
|
||||||
pump = &net->Pump[pumpindex];
|
|
||||||
if (pump->Ptype == CONST_HP) // Constant Hp pump
|
|
||||||
{
|
|
||||||
pump->H0 = 0.0;
|
|
||||||
pump->R = -8.814 * net->Link[pump->Link].Km;
|
|
||||||
pump->N = -1.0;
|
|
||||||
pump->Hmax = BIG; // No head limit
|
|
||||||
pump->Qmax = BIG; // No flow limit
|
|
||||||
pump->Q0 = 1.0; // Init. flow = 1 cfs
|
|
||||||
return errcode;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (pump->Ptype == NOCURVE) // Pump curve specified
|
|
||||||
{
|
|
||||||
curveindex = pump->Hcurve;
|
|
||||||
if (curveindex == 0) return 226;
|
|
||||||
curve = &net->Curve[curveindex];
|
|
||||||
curve->Type = PUMP_CURVE;
|
|
||||||
npts = curve->Npts;
|
|
||||||
|
|
||||||
// Generic power function curve
|
|
||||||
if (npts == 1)
|
|
||||||
{
|
|
||||||
pump->Ptype = POWER_FUNC;
|
|
||||||
q1 = curve->X[0];
|
|
||||||
h1 = curve->Y[0];
|
|
||||||
h0 = 1.33334 * h1;
|
|
||||||
q2 = 2.0 * q1;
|
|
||||||
h2 = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3 point curve with shutoff head
|
|
||||||
else if (npts == 3 && curve->X[0] == 0.0)
|
|
||||||
{
|
|
||||||
pump->Ptype = POWER_FUNC;
|
|
||||||
h0 = curve->Y[0];
|
|
||||||
q1 = curve->X[1];
|
|
||||||
h1 = curve->Y[1];
|
|
||||||
q2 = curve->X[2];
|
|
||||||
h2 = curve->Y[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Custom pump curve
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pump->Ptype = CUSTOM;
|
|
||||||
for (m = 1; m < npts; m++)
|
|
||||||
{
|
|
||||||
if (curve->Y[m] >= curve->Y[m - 1]) return 227;
|
|
||||||
}
|
|
||||||
pump->Qmax = curve->X[npts - 1];
|
|
||||||
pump->Q0 = (curve->X[0] + pump->Qmax) / 2.0;
|
|
||||||
pump->Hmax = curve->Y[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute shape factors & limits of power function curves
|
|
||||||
if (pump->Ptype == POWER_FUNC)
|
|
||||||
{
|
|
||||||
if (!powercurve(h0, h1, h2, q1, q2, &a, &b, &c)) return 227;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pump->H0 = -a;
|
|
||||||
pump->R = -b;
|
|
||||||
pump->N = c;
|
|
||||||
pump->Q0 = q1;
|
|
||||||
pump->Qmax = pow((-a / b), (1.0 / c));
|
|
||||||
pump->Hmax = h0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int addnodeID(Network *net, int n, char *id)
|
int addnodeID(Network *net, int n, char *id)
|
||||||
/*
|
/*
|
||||||
**-------------------------------------------------------------
|
**-------------------------------------------------------------
|
||||||
@@ -564,6 +442,51 @@ int addcurve(Network *network, char *id)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getunitsoption(Project *pr, char *units)
|
||||||
|
/*
|
||||||
|
**-------------------------------------------------------------
|
||||||
|
** Input: units = name of flow units to be used
|
||||||
|
** Output: returns 1 if successful, 0 if not
|
||||||
|
** Purpose: sets the flows units to be used by a project.
|
||||||
|
**--------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
Parser *parser = &pr->parser;
|
||||||
|
if (match(units, w_CFS)) parser->Flowflag = CFS;
|
||||||
|
else if (match(units, w_GPM)) parser->Flowflag = GPM;
|
||||||
|
else if (match(units, w_AFD)) parser->Flowflag = AFD;
|
||||||
|
else if (match(units, w_MGD)) parser->Flowflag = MGD;
|
||||||
|
else if (match(units, w_IMGD)) parser->Flowflag = IMGD;
|
||||||
|
else if (match(units, w_LPS)) parser->Flowflag = LPS;
|
||||||
|
else if (match(units, w_LPM)) parser->Flowflag = LPM;
|
||||||
|
else if (match(units, w_CMH)) parser->Flowflag = CMH;
|
||||||
|
else if (match(units, w_CMD)) parser->Flowflag = CMD;
|
||||||
|
else if (match(units, w_MLD)) parser->Flowflag = MLD;
|
||||||
|
else if (match(units, w_CMS)) parser->Flowflag = CMS;
|
||||||
|
else if (match(units, w_SI)) parser->Flowflag = LPS;
|
||||||
|
else return 0;
|
||||||
|
if (parser->Flowflag >= LPS) parser->Unitsflag = SI;
|
||||||
|
else parser->Unitsflag = US;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getheadlossoption(Project *pr, char *formula)
|
||||||
|
/*
|
||||||
|
**-------------------------------------------------------------
|
||||||
|
** Input: formula = name of head loss formula to be used
|
||||||
|
** Output: returns 1 if successful, 0 if not
|
||||||
|
** Purpose: sets the head loss formula to be used by a project.
|
||||||
|
**--------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
Hydraul *hyd = &pr->hydraul;
|
||||||
|
if (match(formula, w_HW)) hyd->Formflag = HW;
|
||||||
|
else if (match(formula, w_DW)) hyd->Formflag = DW;
|
||||||
|
else if (match(formula, w_CM)) hyd->Formflag = CM;
|
||||||
|
else return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int findmatch(char *line, char *keyword[])
|
int findmatch(char *line, char *keyword[])
|
||||||
/*
|
/*
|
||||||
**--------------------------------------------------------------
|
**--------------------------------------------------------------
|
||||||
@@ -799,6 +722,10 @@ void inperrmsg(Project *pr, int err, int sect, char *line)
|
|||||||
else strcpy(tok, "");
|
else strcpy(tok, "");
|
||||||
|
|
||||||
// write error message to report file
|
// write error message to report file
|
||||||
|
if (err == 299)
|
||||||
|
sprintf(pr->Msg, "Error %d: %s %s: section contents ignored.",
|
||||||
|
err, geterrmsg(err, errStr), tok);
|
||||||
|
else
|
||||||
sprintf(pr->Msg, "Error %d: %s %s in %s section:",
|
sprintf(pr->Msg, "Error %d: %s %s in %s section:",
|
||||||
err, geterrmsg(err, errStr), tok, SectTxt[sect]);
|
err, geterrmsg(err, errStr), tok, SectTxt[sect]);
|
||||||
writeline(pr, pr->Msg);
|
writeline(pr, pr->Msg);
|
||||||
|
|||||||
613
src/input3.c
613
src/input3.c
@@ -7,7 +7,7 @@ Description: parses network data from a line of an EPANET input file
|
|||||||
Authors: see AUTHORS
|
Authors: see AUTHORS
|
||||||
Copyright: see AUTHORS
|
Copyright: see AUTHORS
|
||||||
License: see LICENSE
|
License: see LICENSE
|
||||||
Last Updated: 09/11/2023
|
Last Updated: 09/28/2023
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -27,15 +27,15 @@ extern char *Fldname[];
|
|||||||
extern char *DemandModelTxt[];
|
extern char *DemandModelTxt[];
|
||||||
extern char *BackflowTxt[];
|
extern char *BackflowTxt[];
|
||||||
|
|
||||||
// Exported functions
|
|
||||||
int powercurve(double, double, double, double, double, double *, double *,
|
|
||||||
double *);
|
|
||||||
|
|
||||||
// Imported Functions
|
// Imported Functions
|
||||||
extern int addnodeID(Network *, int, char *);
|
extern int addnodeID(Network *, int, char *);
|
||||||
extern int addlinkID(Network *, int, char *);
|
extern int addlinkID(Network *, int, char *);
|
||||||
|
extern int getunitsoption(Project *, char *);
|
||||||
|
extern int getheadlossoption(Project *, char *);
|
||||||
|
|
||||||
// Local functions
|
// Local functions
|
||||||
|
static double gettokvalue(Project *, double, int, int *, int *);
|
||||||
|
static int getlinknodes(Project *, int *, int *);
|
||||||
static int optionchoice(Project *, int);
|
static int optionchoice(Project *, int);
|
||||||
static int optionvalue(Project *, int);
|
static int optionvalue(Project *, int);
|
||||||
static int getpumpcurve(Project *, int);
|
static int getpumpcurve(Project *, int);
|
||||||
@@ -77,31 +77,52 @@ int juncdata(Project *pr)
|
|||||||
int p = 0; // time pattern index
|
int p = 0; // time pattern index
|
||||||
int n; // number of tokens
|
int n; // number of tokens
|
||||||
int njuncs; // number of network junction nodes
|
int njuncs; // number of network junction nodes
|
||||||
double el, // elevation
|
double el = 0.0, // elevation
|
||||||
y = 0.0; // base demand
|
d = 0.0, // base demand
|
||||||
|
x;
|
||||||
Snode *node;
|
Snode *node;
|
||||||
int err = 0;
|
int errcode = 0;
|
||||||
|
int errtok = -1;
|
||||||
|
|
||||||
// Add new junction to data base
|
// Add new junction to data base
|
||||||
n = parser->Ntokens;
|
|
||||||
if (net->Nnodes == parser->MaxNodes) return 200;
|
if (net->Nnodes == parser->MaxNodes) return 200;
|
||||||
|
errcode = addnodeID(net, net->Njuncs + 1, parser->Tok[0]);
|
||||||
|
if (errcode > 0) return setError(parser, 0, errcode);
|
||||||
net->Njuncs++;
|
net->Njuncs++;
|
||||||
net->Nnodes++;
|
net->Nnodes++;
|
||||||
njuncs = net->Njuncs;
|
|
||||||
err = addnodeID(net, net->Njuncs, parser->Tok[0]);
|
|
||||||
if (err) return setError(parser, 0, err);
|
|
||||||
|
|
||||||
// Check for valid data
|
// Check for valid data
|
||||||
if (n < 2) return 201;
|
n = parser->Ntokens;
|
||||||
if (!getfloat(parser->Tok[1], &el)) return setError(parser, 1, 202);
|
if (n > 1)
|
||||||
if (n >= 3 && !getfloat(parser->Tok[2], &y)) return setError(parser, 2, 202);
|
{
|
||||||
if (n >= 4)
|
if (!getfloat(parser->Tok[1], &x))
|
||||||
|
{
|
||||||
|
errcode = 202;
|
||||||
|
errtok = 1;
|
||||||
|
}
|
||||||
|
else el = x;
|
||||||
|
}
|
||||||
|
if (!errcode && n > 2)
|
||||||
|
{
|
||||||
|
if (!getfloat(parser->Tok[2], &x))
|
||||||
|
{
|
||||||
|
errcode = 202;
|
||||||
|
errtok = 2;
|
||||||
|
}
|
||||||
|
else d = x;
|
||||||
|
}
|
||||||
|
if (!errcode && n > 3)
|
||||||
{
|
{
|
||||||
p = findpattern(net, parser->Tok[3]);
|
p = findpattern(net, parser->Tok[3]);
|
||||||
if (p < 0) return setError(parser, 3, 205);
|
if (p < 0)
|
||||||
|
{
|
||||||
|
errcode = 205;
|
||||||
|
errtok = 3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save junction data
|
// Save junction data
|
||||||
|
njuncs = net->Njuncs;
|
||||||
node = &net->Node[njuncs];
|
node = &net->Node[njuncs];
|
||||||
node->X = MISSING;
|
node->X = MISSING;
|
||||||
node->Y = MISSING;
|
node->Y = MISSING;
|
||||||
@@ -116,8 +137,11 @@ int juncdata(Project *pr)
|
|||||||
|
|
||||||
// Create a demand for the junction and use NodeDemand as an indicator
|
// Create a demand for the junction and use NodeDemand as an indicator
|
||||||
// to be used when processing demands from the [DEMANDS] section
|
// to be used when processing demands from the [DEMANDS] section
|
||||||
if (!adddemand(node, y, p, NULL)) return 101;
|
if (!adddemand(node, d, p, NULL)) return 101;
|
||||||
hyd->NodeDemand[njuncs] = y;
|
hyd->NodeDemand[njuncs] = d;
|
||||||
|
|
||||||
|
// Return error code
|
||||||
|
if (errcode > 0) return setError(parser, errtok, errcode);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,7 +155,6 @@ int tankdata(Project *pr)
|
|||||||
** [RESERVOIRS]
|
** [RESERVOIRS]
|
||||||
** id elev (pattern)
|
** id elev (pattern)
|
||||||
** [TANKS]
|
** [TANKS]
|
||||||
** id elev (pattern)
|
|
||||||
** id elev initlevel minlevel maxlevel diam (minvol vcurve)
|
** id elev initlevel minlevel maxlevel diam (minvol vcurve)
|
||||||
**--------------------------------------------------------------
|
**--------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@@ -155,68 +178,84 @@ int tankdata(Project *pr)
|
|||||||
Snode *node;
|
Snode *node;
|
||||||
Stank *tank;
|
Stank *tank;
|
||||||
|
|
||||||
int err = 0;
|
int errcode = 0;
|
||||||
|
int errtok = -1;
|
||||||
|
double x;
|
||||||
|
|
||||||
// Add new tank to data base
|
// Add new tank to data base
|
||||||
n = parser->Ntokens;
|
|
||||||
if (net->Ntanks == parser->MaxTanks ||
|
if (net->Ntanks == parser->MaxTanks ||
|
||||||
net->Nnodes == parser->MaxNodes) return 200;
|
net->Nnodes == parser->MaxNodes) return 200;
|
||||||
|
i = parser->MaxJuncs + net->Ntanks + 1;
|
||||||
|
errcode = addnodeID(net, i, parser->Tok[0]);
|
||||||
|
if (errcode) return setError(parser, 0, errcode);
|
||||||
net->Ntanks++;
|
net->Ntanks++;
|
||||||
net->Nnodes++;
|
net->Nnodes++;
|
||||||
|
|
||||||
i = parser->MaxJuncs + net->Ntanks;
|
|
||||||
err = addnodeID(net, i, parser->Tok[0]);
|
|
||||||
if (err) return setError(parser, 0, err);
|
|
||||||
|
|
||||||
// Check for valid data
|
// Check for valid data
|
||||||
if (n < 2) return 201;
|
n = parser->Ntokens;
|
||||||
if (!getfloat(parser->Tok[1], &el)) return setError(parser, 1, 202);
|
if (n < 2) errcode = 201;
|
||||||
|
if (!errcode && !getfloat(parser->Tok[1], &x))
|
||||||
|
{
|
||||||
|
errcode = 202;
|
||||||
|
errtok = 1;
|
||||||
|
}
|
||||||
|
else el = x;
|
||||||
|
|
||||||
// Tank is reservoir
|
// Node is a reservoir
|
||||||
if (n <= 3)
|
if (n <= 3)
|
||||||
{
|
{
|
||||||
// Head pattern supplied
|
// Head pattern supplied
|
||||||
if (n == 3)
|
if (n == 3 && !errcode)
|
||||||
{
|
{
|
||||||
pattern = findpattern(net, parser->Tok[2]);
|
pattern = findpattern(net, parser->Tok[2]);
|
||||||
if (pattern < 0) return setError(parser, 2, 205);
|
if (pattern < 0)
|
||||||
|
{
|
||||||
|
errcode = 205;
|
||||||
|
errtok = 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (n < 6) return 201;
|
|
||||||
|
|
||||||
// Tank is a storage tank
|
// Node is a storage tank
|
||||||
|
else if (!errcode)
|
||||||
|
{
|
||||||
|
if (n < 6) errcode = 201;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!getfloat(parser->Tok[2], &initlevel)) return setError(parser, 2, 202);
|
// Read required data
|
||||||
if (!getfloat(parser->Tok[3], &minlevel)) return setError(parser, 3, 202);
|
initlevel = gettokvalue(pr, initlevel, 2, &errcode, &errtok);
|
||||||
if (!getfloat(parser->Tok[4], &maxlevel)) return setError(parser, 4, 202);
|
minlevel = gettokvalue(pr, minlevel, 3, &errcode, &errtok);
|
||||||
if (!getfloat(parser->Tok[5], &diam)) return setError(parser, 5, 202);
|
maxlevel = gettokvalue(pr, maxlevel, 4, &errcode, &errtok);
|
||||||
if (n >= 7 && !getfloat(parser->Tok[6], &minvol)) return setError(parser, 6, 202);
|
diam = gettokvalue(pr, diam, 5, &errcode, &errtok);
|
||||||
|
if (n >= 7) minvol = gettokvalue(pr, minvol, 6, &errcode, &errtok);
|
||||||
|
|
||||||
// If volume curve supplied check it exists
|
// If volume curve supplied check it exists
|
||||||
if (n >= 8)
|
if (!errcode && n >= 8)
|
||||||
{
|
{
|
||||||
if (strlen(parser->Tok[7]) > 0 && *(parser->Tok[7]) != '*')
|
if (strlen(parser->Tok[7]) > 0 && *(parser->Tok[7]) != '*')
|
||||||
{
|
{
|
||||||
curve = findcurve(net, parser->Tok[7]);
|
curve = findcurve(net, parser->Tok[7]);
|
||||||
if (curve == 0) return setError(parser, 7, 206);
|
if (curve == 0)
|
||||||
net->Curve[curve].Type = VOLUME_CURVE;
|
{
|
||||||
|
errcode = 206;
|
||||||
|
errtok = 7;
|
||||||
|
}
|
||||||
|
else net->Curve[curve].Type = VOLUME_CURVE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse overflow indicator if present
|
// Read overflow indicator if present
|
||||||
if (n >= 9)
|
if (!errcode && n >= 9)
|
||||||
{
|
{
|
||||||
if (match(parser->Tok[8], w_YES)) overflow = TRUE;
|
if (match(parser->Tok[8], w_YES)) overflow = TRUE;
|
||||||
else if (match(parser->Tok[8], w_NO)) overflow = FALSE;
|
else if (match(parser->Tok[8], w_NO)) overflow = FALSE;
|
||||||
else return setError(parser, 8, 213);
|
else
|
||||||
|
{
|
||||||
|
errcode = 213;
|
||||||
|
errtok = 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (initlevel < 0.0) return setError(parser, 2, 209);
|
|
||||||
if (minlevel < 0.0) return setError(parser, 3, 209);
|
|
||||||
if (maxlevel < 0.0) return setError(parser, 4, 209);
|
|
||||||
if (diam < 0.0) return setError(parser, 5, 209);
|
|
||||||
if (minvol < 0.0) return setError(parser, 6, 209);
|
|
||||||
}
|
}
|
||||||
node = &net->Node[i];
|
node = &net->Node[i];
|
||||||
tank = &net->Tank[net->Ntanks];
|
tank = &net->Tank[net->Ntanks];
|
||||||
@@ -254,9 +293,38 @@ int tankdata(Project *pr)
|
|||||||
tank->Vcurve = curve;
|
tank->Vcurve = curve;
|
||||||
tank->MixModel = MIX1; // Completely mixed
|
tank->MixModel = MIX1; // Completely mixed
|
||||||
tank->V1frac = 1.0; // Mixing compartment size fraction
|
tank->V1frac = 1.0; // Mixing compartment size fraction
|
||||||
|
|
||||||
|
// Return error code
|
||||||
|
if (errcode > 0) return setError(parser, errtok, errcode);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double gettokvalue(Project *pr, double x, int itok, int *errcode, int *errtok)
|
||||||
|
/*
|
||||||
|
**--------------------------------------------------------------
|
||||||
|
** Input: x = default numerical value
|
||||||
|
** itok = index into an array of string tokens
|
||||||
|
** Output: errcode = an error code or 0 if successful
|
||||||
|
** errtok = itok if an error occurs
|
||||||
|
** returns a numerical data value
|
||||||
|
** Purpose: converts a string token into a numerical value.
|
||||||
|
**--------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
Parser *parser = &pr->parser;
|
||||||
|
double result;
|
||||||
|
|
||||||
|
if (*errcode) return x;
|
||||||
|
if (!getfloat(parser->Tok[itok], &result)) *errcode = 202;
|
||||||
|
else if (result < 0.0) *errcode = 209;
|
||||||
|
if (*errcode > 0)
|
||||||
|
{
|
||||||
|
result = x;
|
||||||
|
*errtok = itok;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
int pipedata(Project *pr)
|
int pipedata(Project *pr)
|
||||||
/*
|
/*
|
||||||
**--------------------------------------------------------------
|
**--------------------------------------------------------------
|
||||||
@@ -275,71 +343,101 @@ int pipedata(Project *pr)
|
|||||||
int j1, // Start-node index
|
int j1, // Start-node index
|
||||||
j2, // End-node index
|
j2, // End-node index
|
||||||
n; // # data items
|
n; // # data items
|
||||||
double length, // Pipe length
|
double x;
|
||||||
diam, // Pipe diameter
|
|
||||||
rcoeff, // Roughness coeff.
|
|
||||||
lcoeff = 0.0; // Minor loss coeff
|
|
||||||
LinkType type = PIPE; // Link type
|
|
||||||
StatusType status = OPEN; // Link status
|
|
||||||
Slink *link;
|
Slink *link;
|
||||||
int err = 0;
|
int errcode = 0;
|
||||||
|
|
||||||
// Add new pipe to data base
|
// Check that end nodes exist
|
||||||
n = parser->Ntokens;
|
|
||||||
if (net->Nlinks == parser->MaxLinks) return 200;
|
if (net->Nlinks == parser->MaxLinks) return 200;
|
||||||
net->Npipes++;
|
n = parser->Ntokens;
|
||||||
net->Nlinks++;
|
if (n < 3) return setError(parser, -1, errcode);
|
||||||
err = addlinkID(net, net->Nlinks, parser->Tok[0]);
|
|
||||||
if (err) return setError(parser, 0, err);
|
|
||||||
|
|
||||||
// Check for valid data
|
|
||||||
if (n < 6) return 201;
|
|
||||||
if ((j1 = findnode(net, parser->Tok[1])) == 0) return setError(parser, 1, 203);
|
if ((j1 = findnode(net, parser->Tok[1])) == 0) return setError(parser, 1, 203);
|
||||||
if ((j2 = findnode(net, parser->Tok[2])) == 0) return setError(parser, 2, 203);
|
if ((j2 = findnode(net, parser->Tok[2])) == 0) return setError(parser, 2, 203);
|
||||||
if (j1 == j2) return setError(parser, 0, 222);
|
if (j1 == j2) return setError(parser, 0, 222);
|
||||||
|
|
||||||
if (!getfloat(parser->Tok[3], &length)) return setError(parser, 3, 202);
|
// Add new pipe to data base
|
||||||
if (length <= 0.0) return setError(parser, 3, 211);
|
errcode = addlinkID(net, net->Nlinks+1, parser->Tok[0]);
|
||||||
if (!getfloat(parser->Tok[4], &diam)) return setError(parser, 4, 202);
|
if (errcode) return setError(parser, 0, errcode);
|
||||||
if (diam <= 0.0) return setError(parser, 4, 211);
|
net->Npipes++;
|
||||||
if (!getfloat(parser->Tok[5], &rcoeff)) return setError(parser, 5, 202);
|
net->Nlinks++;
|
||||||
if (rcoeff <= 0.0) return setError(parser, 5, 211);
|
|
||||||
|
|
||||||
// Either a loss coeff. or a status is supplied
|
// Assign default data to pipe
|
||||||
if (n == 7)
|
|
||||||
{
|
|
||||||
if (match(parser->Tok[6], w_CV)) type = CVPIPE;
|
|
||||||
else if (match(parser->Tok[6], w_CLOSED)) status = CLOSED;
|
|
||||||
else if (match(parser->Tok[6], w_OPEN)) status = OPEN;
|
|
||||||
else if (!getfloat(parser->Tok[6], &lcoeff)) return setError(parser, 6, 202);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Both a loss coeff. and a status is supplied
|
|
||||||
if (n == 8)
|
|
||||||
{
|
|
||||||
if (!getfloat(parser->Tok[6], &lcoeff)) return setError(parser, 6, 202);
|
|
||||||
if (match(parser->Tok[7], w_CV)) type = CVPIPE;
|
|
||||||
else if (match(parser->Tok[7], w_CLOSED)) status = CLOSED;
|
|
||||||
else if (match(parser->Tok[7], w_OPEN)) status = OPEN;
|
|
||||||
else return setError(parser, 7, 213);
|
|
||||||
}
|
|
||||||
if (lcoeff < 0.0) return setError(parser, 6, 211);
|
|
||||||
|
|
||||||
// Save pipe data
|
|
||||||
link = &net->Link[net->Nlinks];
|
link = &net->Link[net->Nlinks];
|
||||||
link->N1 = j1;
|
link->N1 = j1;
|
||||||
link->N2 = j2;
|
link->N2 = j2;
|
||||||
link->Len = length;
|
|
||||||
link->Diam = diam;
|
if (parser->Unitsflag == SI)
|
||||||
link->Kc = rcoeff;
|
{
|
||||||
link->Km = lcoeff;
|
link->Len = 100.0;
|
||||||
|
link->Diam = 254.0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
link->Len = 330.0;
|
||||||
|
link->Diam = 10.0;
|
||||||
|
}
|
||||||
|
switch (pr->hydraul.Formflag)
|
||||||
|
{
|
||||||
|
case HW: link->Kc = 130; break;
|
||||||
|
case DW: link->Kc = 0.0005; break;
|
||||||
|
case CM: link->Kc = 0.01; break;
|
||||||
|
default: link->Kc = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
link->Km = 0.0;
|
||||||
link->Kb = MISSING;
|
link->Kb = MISSING;
|
||||||
link->Kw = MISSING;
|
link->Kw = MISSING;
|
||||||
link->Type = type;
|
link->Type = PIPE;
|
||||||
link->Status = status;
|
link->Status = OPEN;
|
||||||
link->Rpt = 0;
|
link->Rpt = 0;
|
||||||
link->ResultIndex = 0;
|
link->ResultIndex = 0;
|
||||||
link->Comment = xstrcpy(&link->Comment, parser->Comment, MAXMSG);
|
link->Comment = xstrcpy(&link->Comment, parser->Comment, MAXMSG);
|
||||||
|
|
||||||
|
// Parse data values from input tokens
|
||||||
|
if (n > 3)
|
||||||
|
{
|
||||||
|
if (!getfloat(parser->Tok[3], &x) || x <= 0.0)
|
||||||
|
return setError(parser, 3, 202);
|
||||||
|
link->Len = x;
|
||||||
|
}
|
||||||
|
if (n > 4)
|
||||||
|
{
|
||||||
|
if (!getfloat(parser->Tok[4], &x) || x <= 0.0)
|
||||||
|
return setError(parser, 4, 202);
|
||||||
|
link->Diam = x;
|
||||||
|
}
|
||||||
|
if (n > 5)
|
||||||
|
{
|
||||||
|
if (!getfloat(parser->Tok[5], &x) || x <= 0.0)
|
||||||
|
return setError(parser, 5, 202);
|
||||||
|
link->Kc = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Either a loss coeff. or a status is supplied
|
||||||
|
if (n > 6)
|
||||||
|
{
|
||||||
|
if (match(parser->Tok[6], w_CV)) link->Type = CVPIPE;
|
||||||
|
else if (match(parser->Tok[6], w_CLOSED)) link->Status = CLOSED;
|
||||||
|
else if (match(parser->Tok[6], w_OPEN)) link->Status = OPEN;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!getfloat(parser->Tok[6], &x) || x < 0.0)
|
||||||
|
return setError(parser, 6, 202);
|
||||||
|
link->Km = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Both a loss coeff. and a status is supplied
|
||||||
|
if (n > 7)
|
||||||
|
{
|
||||||
|
if (!getfloat(parser->Tok[6], &x) || x < 0.0)
|
||||||
|
return setError(parser, 6, 202);
|
||||||
|
link->Km = x;
|
||||||
|
if (match(parser->Tok[7], w_CV)) link->Type = CVPIPE;
|
||||||
|
else if (match(parser->Tok[7], w_CLOSED)) link->Status = CLOSED;
|
||||||
|
else if (match(parser->Tok[7], w_OPEN)) link->Status = OPEN;
|
||||||
|
else return setError(parser, 7, 213);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -351,11 +449,6 @@ int pumpdata(Project *pr)
|
|||||||
** Purpose: processes pump data
|
** Purpose: processes pump data
|
||||||
** Formats:
|
** Formats:
|
||||||
** [PUMP]
|
** [PUMP]
|
||||||
** (Version 1.x Format):
|
|
||||||
** id node1 node2 power
|
|
||||||
** id node1 node2 h1 q1
|
|
||||||
** id node1 node2 h0 h1 q1 h2 q2
|
|
||||||
** (Version 2 Format):
|
|
||||||
** id node1 node2 KEYWORD value {KEYWORD value ...}
|
** id node1 node2 KEYWORD value {KEYWORD value ...}
|
||||||
** where KEYWORD = [POWER,HEAD,PATTERN,SPEED]
|
** where KEYWORD = [POWER,HEAD,PATTERN,SPEED]
|
||||||
**--------------------------------------------------------------
|
**--------------------------------------------------------------
|
||||||
@@ -364,7 +457,7 @@ int pumpdata(Project *pr)
|
|||||||
Network *net = &pr->network;
|
Network *net = &pr->network;
|
||||||
Parser *parser = &pr->parser;
|
Parser *parser = &pr->parser;
|
||||||
|
|
||||||
int j, m, // Token array indexes
|
int m, // Token array indexes
|
||||||
j1, // Start-node index
|
j1, // Start-node index
|
||||||
j2, // End-node index
|
j2, // End-node index
|
||||||
n, // # data items
|
n, // # data items
|
||||||
@@ -372,24 +465,24 @@ int pumpdata(Project *pr)
|
|||||||
double y;
|
double y;
|
||||||
Slink *link;
|
Slink *link;
|
||||||
Spump *pump;
|
Spump *pump;
|
||||||
int err = 0;
|
int errcode = 0;
|
||||||
|
|
||||||
/* Add new pump to data base */
|
// Check that end nodes exist
|
||||||
n = parser->Ntokens;
|
|
||||||
if (net->Nlinks == parser->MaxLinks ||
|
if (net->Nlinks == parser->MaxLinks ||
|
||||||
net->Npumps == parser->MaxPumps) return 200;
|
net->Npumps == parser->MaxPumps) return 200;
|
||||||
net->Nlinks++;
|
n = parser->Ntokens;
|
||||||
net->Npumps++;
|
if (n < 3) return setError(parser, -1, errcode);
|
||||||
err = addlinkID(net, net->Nlinks, parser->Tok[0]);
|
|
||||||
if (err) return setError(parser, 0, err);
|
|
||||||
|
|
||||||
// Check for valid data
|
|
||||||
if (n < 3) return 201;
|
|
||||||
if ((j1 = findnode(net, parser->Tok[1])) == 0) return setError(parser, 1, 203);
|
if ((j1 = findnode(net, parser->Tok[1])) == 0) return setError(parser, 1, 203);
|
||||||
if ((j2 = findnode(net, parser->Tok[2])) == 0) return setError(parser, 2, 203);
|
if ((j2 = findnode(net, parser->Tok[2])) == 0) return setError(parser, 2, 203);
|
||||||
if (j1 == j2) return setError(parser, 0, 222);
|
if (j1 == j2) return setError(parser, 0, 222);
|
||||||
|
|
||||||
// Save pump data
|
// Add new pump to data base
|
||||||
|
errcode = addlinkID(net, net->Nlinks+1, parser->Tok[0]);
|
||||||
|
if (errcode) return setError(parser, 0, errcode);
|
||||||
|
net->Nlinks++;
|
||||||
|
net->Npumps++;
|
||||||
|
|
||||||
|
// Assign default data to pump
|
||||||
link = &net->Link[net->Nlinks];
|
link = &net->Link[net->Nlinks];
|
||||||
pump = &net->Pump[net->Npumps];
|
pump = &net->Pump[net->Npumps];
|
||||||
|
|
||||||
@@ -415,28 +508,14 @@ int pumpdata(Project *pr)
|
|||||||
pump->Epat = 0;
|
pump->Epat = 0;
|
||||||
if (n < 4) return 0;
|
if (n < 4) return 0;
|
||||||
|
|
||||||
// If 4-th token is a number then input follows Version 1.x format
|
// Retrieve keyword/value pairs
|
||||||
// so retrieve pump curve parameters
|
|
||||||
if (getfloat(parser->Tok[3], &parser->X[0]))
|
|
||||||
{
|
|
||||||
m = 1;
|
|
||||||
for (j = 4; j < n; j++)
|
|
||||||
{
|
|
||||||
if (!getfloat(parser->Tok[j], &parser->X[m])) return setError(parser, j, 202);
|
|
||||||
m++;
|
|
||||||
}
|
|
||||||
return (getpumpcurve(pr, m));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise input follows Version 2 format
|
|
||||||
// so retrieve keyword/value pairs
|
|
||||||
m = 4;
|
m = 4;
|
||||||
while (m < n)
|
while (m < n)
|
||||||
{
|
{
|
||||||
if (match(parser->Tok[m - 1], w_POWER)) // Const. HP curve
|
if (match(parser->Tok[m - 1], w_POWER)) // Const. HP curve
|
||||||
{
|
{
|
||||||
y = atof(parser->Tok[m]);
|
if (!getfloat(parser->Tok[m], &y) || y <= 0.0)
|
||||||
if (y <= 0.0) return setError(parser, m, 202);
|
return setError(parser, m, 202);
|
||||||
pump->Ptype = CONST_HP;
|
pump->Ptype = CONST_HP;
|
||||||
link->Km = y;
|
link->Km = y;
|
||||||
}
|
}
|
||||||
@@ -454,11 +533,11 @@ int pumpdata(Project *pr)
|
|||||||
}
|
}
|
||||||
else if (match(parser->Tok[m - 1], w_SPEED)) // Speed setting
|
else if (match(parser->Tok[m - 1], w_SPEED)) // Speed setting
|
||||||
{
|
{
|
||||||
if (!getfloat(parser->Tok[m], &y)) return setError(parser, m, 202);
|
if (!getfloat(parser->Tok[m], &y) || y < 0.0)
|
||||||
if (y < 0.0) return setError(parser, m, 211);
|
return setError(parser, m, 202);
|
||||||
link->Kc = y;
|
link->Kc = y;
|
||||||
}
|
}
|
||||||
else return 201;
|
else return setError(parser, m-1, 201);;
|
||||||
m = m + 2; // Move to next keyword token
|
m = m + 2; // Move to next keyword token
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -485,73 +564,29 @@ int valvedata(Project *pr)
|
|||||||
n; // # data items
|
n; // # data items
|
||||||
char status = ACTIVE, // Valve status
|
char status = ACTIVE, // Valve status
|
||||||
type; // Valve type
|
type; // Valve type
|
||||||
double diam = 0.0, // Valve diameter
|
double x;
|
||||||
setting, // Valve setting
|
|
||||||
lcoeff = 0.0; // Minor loss coeff.
|
|
||||||
Slink *link;
|
Slink *link;
|
||||||
int err = 0,
|
int errcode = 0,
|
||||||
losscurve = 0; // Loss coeff. curve
|
losscurve = 0; // Loss coeff. curve
|
||||||
|
|
||||||
// Add new valve to data base
|
// Check that end nodes exist
|
||||||
n = parser->Ntokens;
|
|
||||||
if (net->Nlinks == parser->MaxLinks ||
|
if (net->Nlinks == parser->MaxLinks ||
|
||||||
net->Nvalves == parser->MaxValves) return 200;
|
net->Nvalves == parser->MaxValves) return 200;
|
||||||
net->Nvalves++;
|
n = parser->Ntokens;
|
||||||
net->Nlinks++;
|
if (n < 5) return setError(parser, -1, errcode);
|
||||||
err = addlinkID(net, net->Nlinks, parser->Tok[0]);
|
if ((j1 = findnode(net, parser->Tok[1])) == 0) return setError(parser, 1, 203);
|
||||||
if (err) return setError(parser, 0, err);
|
if ((j2 = findnode(net, parser->Tok[2])) == 0) return setError(parser, 2, 203);
|
||||||
|
if (j1 == j2) return setError(parser, 0, 222);
|
||||||
|
|
||||||
// Check for valid data
|
// Parse valve type
|
||||||
if (n < 6)
|
if (match(parser->Tok[4], w_PRV)) type = PRV;
|
||||||
return 201;
|
else if (match(parser->Tok[4], w_PSV)) type = PSV;
|
||||||
if ((j1 = findnode(net, parser->Tok[1])) == 0)
|
else if (match(parser->Tok[4], w_PBV)) type = PBV;
|
||||||
return setError(parser, 1, 203);
|
else if (match(parser->Tok[4], w_FCV)) type = FCV;
|
||||||
if ((j2 = findnode(net, parser->Tok[2])) == 0)
|
else if (match(parser->Tok[4], w_TCV)) type = TCV;
|
||||||
return setError(parser, 2, 203);
|
else if (match(parser->Tok[4], w_GPV)) type = GPV;
|
||||||
if (j1 == j2)
|
else if (match(parser->Tok[4], w_PCV)) type = PCV;
|
||||||
return setError(parser, 0, 222);
|
else return setError(parser, 4, 213);
|
||||||
|
|
||||||
if (match(parser->Tok[4], w_PRV))
|
|
||||||
type = PRV;
|
|
||||||
else if (match(parser->Tok[4], w_PSV))
|
|
||||||
type = PSV;
|
|
||||||
else if (match(parser->Tok[4], w_PBV))
|
|
||||||
type = PBV;
|
|
||||||
else if (match(parser->Tok[4], w_FCV))
|
|
||||||
type = FCV;
|
|
||||||
else if (match(parser->Tok[4], w_TCV))
|
|
||||||
type = TCV;
|
|
||||||
else if (match(parser->Tok[4], w_GPV))
|
|
||||||
type = GPV;
|
|
||||||
else if (match(parser->Tok[4], w_PCV))
|
|
||||||
type = PCV;
|
|
||||||
else
|
|
||||||
return setError(parser, 4, 213);
|
|
||||||
|
|
||||||
if (!getfloat(parser->Tok[3], &diam)) return setError(parser, 3, 202);
|
|
||||||
if (diam <= 0.0) return setError(parser, 3, 211);
|
|
||||||
|
|
||||||
// Find headloss curve for GPV
|
|
||||||
if (type == GPV)
|
|
||||||
{
|
|
||||||
c = findcurve(net, parser->Tok[5]);
|
|
||||||
if (c == 0) return setError(parser, 5, 206);
|
|
||||||
setting = c;
|
|
||||||
net->Curve[c].Type = HLOSS_CURVE;
|
|
||||||
status = OPEN;
|
|
||||||
}
|
|
||||||
else if (!getfloat(parser->Tok[5], &setting)) return setError(parser, 5, 202);
|
|
||||||
if (n >= 7 && !getfloat(parser->Tok[6], &lcoeff)) return setError(parser, 6, 202);
|
|
||||||
|
|
||||||
// Find loss coeff. curve for PCV
|
|
||||||
if (type == PCV && n >= 8)
|
|
||||||
{
|
|
||||||
c = findcurve(net, parser->Tok[7]);
|
|
||||||
if (c == 0) return setError(parser, 7, 206);
|
|
||||||
losscurve = c;
|
|
||||||
net->Curve[c].Type = VALVE_CURVE;
|
|
||||||
if (setting > 100.0) setting = 100.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for illegal connections
|
// Check for illegal connections
|
||||||
if (valvecheck(pr, net->Nlinks, type, j1, j2))
|
if (valvecheck(pr, net->Nlinks, type, j1, j2))
|
||||||
@@ -561,23 +596,67 @@ int valvedata(Project *pr)
|
|||||||
else return setError(parser, -1, 220);
|
else return setError(parser, -1, 220);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save valve data
|
// Add new valve to data base
|
||||||
|
errcode = addlinkID(net, net->Nlinks+1, parser->Tok[0]);
|
||||||
|
if (errcode) return setError(parser, 0, errcode);
|
||||||
|
net->Nvalves++;
|
||||||
|
net->Nlinks++;
|
||||||
|
|
||||||
|
// Assign default data to valve
|
||||||
link = &net->Link[net->Nlinks];
|
link = &net->Link[net->Nlinks];
|
||||||
link->N1 = j1;
|
link->N1 = j1;
|
||||||
link->N2 = j2;
|
link->N2 = j2;
|
||||||
link->Diam = diam;
|
if (parser->Unitsflag == SI) link->Diam = 254.0;
|
||||||
|
else link->Diam = 10.0;
|
||||||
link->Len = 0.0;
|
link->Len = 0.0;
|
||||||
link->Kc = setting;
|
link->Kc = 0.0;
|
||||||
link->Km = lcoeff;
|
link->Km = 0.0;
|
||||||
link->Kb = 0.0;
|
link->Kb = 0.0;
|
||||||
link->Kw = 0.0;
|
link->Kw = 0.0;
|
||||||
link->Type = type;
|
link->Type = type;
|
||||||
link->Status = status;
|
link->Status = ACTIVE;
|
||||||
link->Rpt = 0;
|
link->Rpt = 0;
|
||||||
link->ResultIndex = 0;
|
link->ResultIndex = 0;
|
||||||
link->Comment = xstrcpy(&link->Comment, parser->Comment, MAXMSG);
|
link->Comment = xstrcpy(&link->Comment, parser->Comment, MAXMSG);
|
||||||
net->Valve[net->Nvalves].Link = net->Nlinks;
|
net->Valve[net->Nvalves].Link = net->Nlinks;
|
||||||
net->Valve[net->Nvalves].Curve = losscurve;
|
net->Valve[net->Nvalves].Curve = 0;
|
||||||
|
|
||||||
|
// Parse data values
|
||||||
|
if (!getfloat(parser->Tok[3], &x) || x <= 0.0)
|
||||||
|
return setError(parser, 3, 202);
|
||||||
|
link->Diam = x;
|
||||||
|
if (n > 5)
|
||||||
|
{
|
||||||
|
// Find headloss curve for GPV
|
||||||
|
if (type == GPV)
|
||||||
|
{
|
||||||
|
c = findcurve(net, parser->Tok[5]);
|
||||||
|
if (c == 0) return setError(parser, 5, 206);
|
||||||
|
link->Kc = c;
|
||||||
|
net->Curve[c].Type = HLOSS_CURVE;
|
||||||
|
link->Status = OPEN;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!getfloat(parser->Tok[5], &x)) return setError(parser, 5, 202);
|
||||||
|
link->Kc = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (n > 6)
|
||||||
|
{
|
||||||
|
if (!getfloat(parser->Tok[6], &x) || x < 0.0)
|
||||||
|
return setError(parser, 6, 202);
|
||||||
|
link->Km = x;
|
||||||
|
}
|
||||||
|
if (n > 7 && type == PCV)
|
||||||
|
{
|
||||||
|
// Find loss coeff. curve for PCV
|
||||||
|
c = findcurve(net, parser->Tok[7]);
|
||||||
|
if (c == 0) return setError(parser, 7, 206);
|
||||||
|
net->Valve[net->Nvalves].Curve = c;
|
||||||
|
net->Curve[c].Type = VALVE_CURVE;
|
||||||
|
if (link->Kc > 100.0) link->Kc = 100.0;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -628,6 +707,7 @@ int patterndata(Project *pr)
|
|||||||
pattern->F = realloc(pattern->F, pattern->Length * sizeof(double));
|
pattern->F = realloc(pattern->F, pattern->Length * sizeof(double));
|
||||||
|
|
||||||
// Add parsed multipliers to the pattern
|
// Add parsed multipliers to the pattern
|
||||||
|
for (j = 1; j <= n; j++) pattern->F[n1 + j - 1] = 1.0;
|
||||||
for (j = 1; j <= n; j++)
|
for (j = 1; j <= n; j++)
|
||||||
{
|
{
|
||||||
if (!getfloat(parser->Tok[j], &x)) return setError(parser, j, 202);
|
if (!getfloat(parser->Tok[j], &x)) return setError(parser, j, 202);
|
||||||
@@ -776,7 +856,6 @@ int demanddata(Project *pr)
|
|||||||
** Purpose: processes node demand data
|
** Purpose: processes node demand data
|
||||||
** Format:
|
** Format:
|
||||||
** [DEMANDS]
|
** [DEMANDS]
|
||||||
** MULTIPLY factor
|
|
||||||
** node base_demand (pattern)
|
** node base_demand (pattern)
|
||||||
**
|
**
|
||||||
** NOTE: Demands entered in this section replace those
|
** NOTE: Demands entered in this section replace those
|
||||||
@@ -798,15 +877,7 @@ int demanddata(Project *pr)
|
|||||||
if (n < 2) return 201;
|
if (n < 2) return 201;
|
||||||
if (!getfloat(parser->Tok[1], &y)) return setError(parser, 1, 202);
|
if (!getfloat(parser->Tok[1], &y)) return setError(parser, 1, 202);
|
||||||
|
|
||||||
// If MULTIPLY command, save multiplier
|
// Find node (and pattern) being referenced
|
||||||
if (match(parser->Tok[0], w_MULTIPLY))
|
|
||||||
{
|
|
||||||
if (y <= 0.0) return setError(parser, 1, 213);
|
|
||||||
else hyd->Dmult = y;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise find node (and pattern) being referenced
|
|
||||||
if ((j = findnode(net, parser->Tok[0])) == 0) return setError(parser, 0, 203);
|
if ((j = findnode(net, parser->Tok[0])) == 0) return setError(parser, 0, 203);
|
||||||
if (j > net->Njuncs) return 0;
|
if (j > net->Njuncs) return 0;
|
||||||
if (n >= 3)
|
if (n >= 3)
|
||||||
@@ -1781,19 +1852,8 @@ int optionchoice(Project *pr, int n)
|
|||||||
if (match(parser->Tok[0], w_UNITS))
|
if (match(parser->Tok[0], w_UNITS))
|
||||||
{
|
{
|
||||||
if (n < 1) return 0;
|
if (n < 1) return 0;
|
||||||
else if (match(parser->Tok[1], w_CFS)) parser->Flowflag = CFS;
|
if (!getunitsoption(pr, parser->Tok[1]))
|
||||||
else if (match(parser->Tok[1], w_GPM)) parser->Flowflag = GPM;
|
return setError(parser, 1, 213);
|
||||||
else if (match(parser->Tok[1], w_AFD)) parser->Flowflag = AFD;
|
|
||||||
else if (match(parser->Tok[1], w_MGD)) parser->Flowflag = MGD;
|
|
||||||
else if (match(parser->Tok[1], w_IMGD)) parser->Flowflag = IMGD;
|
|
||||||
else if (match(parser->Tok[1], w_LPS)) parser->Flowflag = LPS;
|
|
||||||
else if (match(parser->Tok[1], w_LPM)) parser->Flowflag = LPM;
|
|
||||||
else if (match(parser->Tok[1], w_CMH)) parser->Flowflag = CMH;
|
|
||||||
else if (match(parser->Tok[1], w_CMD)) parser->Flowflag = CMD;
|
|
||||||
else if (match(parser->Tok[1], w_MLD)) parser->Flowflag = MLD;
|
|
||||||
else if (match(parser->Tok[1], w_CMS)) parser->Flowflag = CMS;
|
|
||||||
else if (match(parser->Tok[1], w_SI)) parser->Flowflag = LPS;
|
|
||||||
else return setError(parser, 1, 213);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PRESSURE units
|
// PRESSURE units
|
||||||
@@ -1811,10 +1871,8 @@ int optionchoice(Project *pr, int n)
|
|||||||
else if (match(parser->Tok[0], w_HEADLOSS))
|
else if (match(parser->Tok[0], w_HEADLOSS))
|
||||||
{
|
{
|
||||||
if (n < 1) return 0;
|
if (n < 1) return 0;
|
||||||
else if (match(parser->Tok[1], w_HW)) hyd->Formflag = HW;
|
if (!getheadlossoption(pr, parser->Tok[1]))
|
||||||
else if (match(parser->Tok[1], w_DW)) hyd->Formflag = DW;
|
return setError(parser, 1, 213);
|
||||||
else if (match(parser->Tok[1], w_CM)) hyd->Formflag = CM;
|
|
||||||
else return setError(parser, 1, 213);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HYDRUALICS USE/SAVE file option
|
// HYDRUALICS USE/SAVE file option
|
||||||
@@ -2063,101 +2121,6 @@ int optionvalue(Project *pr, int n)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getpumpcurve(Project *pr, int n)
|
|
||||||
/*
|
|
||||||
**--------------------------------------------------------
|
|
||||||
** Input: n = number of parameters for pump curve
|
|
||||||
** Output: returns error code
|
|
||||||
** Purpose: processes pump curve data for Version 1.1-
|
|
||||||
** style input data
|
|
||||||
** Notes:
|
|
||||||
** 1. Called by pumpdata() in INPUT3.C
|
|
||||||
** 2. Current link index & pump index of pump being
|
|
||||||
** processed is found in network variables Nlinks
|
|
||||||
** and Npumps, respectively
|
|
||||||
** 3. Curve data read from input line is found in
|
|
||||||
** parser's array X[0],...X[n-1]
|
|
||||||
**---------------------------------------------------------
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
Network *net = &pr->network;
|
|
||||||
Parser *parser = &pr->parser;
|
|
||||||
|
|
||||||
double a, b, c, h0, h1, h2, q1, q2;
|
|
||||||
Spump *pump = &net->Pump[net->Npumps];
|
|
||||||
|
|
||||||
// Constant HP curve
|
|
||||||
if (n == 1)
|
|
||||||
{
|
|
||||||
if (parser->X[0] <= 0.0) return 202;
|
|
||||||
pump->Ptype = CONST_HP;
|
|
||||||
net->Link[net->Nlinks].Km = parser->X[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Power function curve
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Single point power curve
|
|
||||||
if (n == 2)
|
|
||||||
{
|
|
||||||
q1 = parser->X[1];
|
|
||||||
h1 = parser->X[0];
|
|
||||||
h0 = 1.33334 * h1;
|
|
||||||
q2 = 2.0 * q1;
|
|
||||||
h2 = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3-point power curve
|
|
||||||
else if (n >= 5)
|
|
||||||
{
|
|
||||||
h0 = parser->X[0];
|
|
||||||
h1 = parser->X[1];
|
|
||||||
q1 = parser->X[2];
|
|
||||||
h2 = parser->X[3];
|
|
||||||
q2 = parser->X[4];
|
|
||||||
}
|
|
||||||
else return 202;
|
|
||||||
pump->Ptype = POWER_FUNC;
|
|
||||||
if (!powercurve(h0, h1, h2, q1, q2, &a, &b, &c)) return 206;
|
|
||||||
pump->H0 = -a;
|
|
||||||
pump->R = -b;
|
|
||||||
pump->N = c;
|
|
||||||
pump->Q0 = q1;
|
|
||||||
pump->Qmax = pow((-a / b), (1.0 / c));
|
|
||||||
pump->Hmax = h0;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int powercurve(double h0, double h1, double h2, double q1, double q2,
|
|
||||||
double *a, double *b, double *c)
|
|
||||||
/*
|
|
||||||
**---------------------------------------------------------
|
|
||||||
** Input: h0 = shutoff head
|
|
||||||
** h1 = design head
|
|
||||||
** h2 = head at max. flow
|
|
||||||
** q1 = design flow
|
|
||||||
** q2 = max. flow
|
|
||||||
** Output: *a, *b, *c = pump curve coeffs. (H = a-bQ^c),
|
|
||||||
** Returns 1 if sucessful, 0 otherwise.
|
|
||||||
** Purpose: computes coeffs. for pump curve
|
|
||||||
**----------------------------------------------------------
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
double h4, h5;
|
|
||||||
|
|
||||||
if (h0 < TINY || h0 - h1 < TINY || h1 - h2 < TINY ||
|
|
||||||
q1 < TINY || q2 - q1 < TINY
|
|
||||||
) return 0;
|
|
||||||
*a = h0;
|
|
||||||
h4 = h0 - h1;
|
|
||||||
h5 = h0 - h2;
|
|
||||||
*c = log(h5 / h4) / log(q2 / q1);
|
|
||||||
if (*c <= 0.0 || *c > 20.0) return 0;
|
|
||||||
*b = -h4 / pow(q1, *c);
|
|
||||||
if (*b >= 0.0) return 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void changestatus(Network *net, int j, StatusType status, double y)
|
void changestatus(Network *net, int j, StatusType status, double y)
|
||||||
/*
|
/*
|
||||||
|
|||||||
119
src/project.c
119
src/project.c
@@ -7,7 +7,7 @@
|
|||||||
Authors: see AUTHORS
|
Authors: see AUTHORS
|
||||||
Copyright: see AUTHORS
|
Copyright: see AUTHORS
|
||||||
License: see LICENSE
|
License: see LICENSE
|
||||||
Last Updated: 08/02/2023
|
Last Updated: 09/28/2023
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -24,6 +24,81 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "funcs.h"
|
#include "funcs.h"
|
||||||
|
|
||||||
|
int openproject(Project *pr, const char *inpFile, const char *rptFile,
|
||||||
|
const char *outFile, int allowerrors)
|
||||||
|
/*----------------------------------------------------------------
|
||||||
|
** Input: inpFile = name of input file
|
||||||
|
** rptFile = name of report file
|
||||||
|
** outFile = name of binary output file
|
||||||
|
** allowerrors = TRUE if project can be opened with errors
|
||||||
|
** Output: none
|
||||||
|
** Returns: error code
|
||||||
|
** Purpose: opens an EPANET input file & reads in network data
|
||||||
|
**----------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int errcode = 0;
|
||||||
|
int hyderrcode = 0;
|
||||||
|
int projectopened;
|
||||||
|
|
||||||
|
// Set system flags
|
||||||
|
pr->Openflag = FALSE;
|
||||||
|
pr->hydraul.OpenHflag = FALSE;
|
||||||
|
pr->quality.OpenQflag = FALSE;
|
||||||
|
pr->outfile.SaveHflag = FALSE;
|
||||||
|
pr->outfile.SaveQflag = FALSE;
|
||||||
|
pr->Warnflag = FALSE;
|
||||||
|
pr->report.Messageflag = TRUE;
|
||||||
|
pr->report.Rptflag = 1;
|
||||||
|
|
||||||
|
// Initialize data arrays to NULL
|
||||||
|
initpointers(pr);
|
||||||
|
|
||||||
|
// Open input & report files
|
||||||
|
ERRCODE(openfiles(pr, inpFile, rptFile, outFile));
|
||||||
|
if (errcode > 0)
|
||||||
|
{
|
||||||
|
errmsg(pr, errcode);
|
||||||
|
return errcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate memory for project's data arrays
|
||||||
|
ERRCODE(netsize(pr));
|
||||||
|
ERRCODE(allocdata(pr));
|
||||||
|
|
||||||
|
// Read input data
|
||||||
|
ERRCODE(getdata(pr));
|
||||||
|
|
||||||
|
// Close input file
|
||||||
|
if (pr->parser.InFile != NULL)
|
||||||
|
{
|
||||||
|
fclose(pr->parser.InFile);
|
||||||
|
pr->parser.InFile = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Input file read with no fatal errors
|
||||||
|
if (allowerrors) projectopened = (errcode == 0 || errcode == 200);
|
||||||
|
else projectopened = (errcode == 0);
|
||||||
|
if (projectopened)
|
||||||
|
{
|
||||||
|
// If using previously saved hydraulics file then open it
|
||||||
|
if (pr->outfile.Hydflag == USE)
|
||||||
|
{
|
||||||
|
hyderrcode = openhydfile(pr);
|
||||||
|
if (hyderrcode > 0)
|
||||||
|
{
|
||||||
|
errmsg(pr, hyderrcode);
|
||||||
|
pr->outfile.Hydflag = SCRATCH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write input summary to report file
|
||||||
|
if (pr->report.Summaryflag) writesummary(pr);
|
||||||
|
pr->Openflag = TRUE;
|
||||||
|
}
|
||||||
|
errmsg(pr, errcode);
|
||||||
|
return errcode;
|
||||||
|
}
|
||||||
|
|
||||||
int openfiles(Project *pr, const char *f1, const char *f2, const char *f3)
|
int openfiles(Project *pr, const char *f1, const char *f2, const char *f3)
|
||||||
/*----------------------------------------------------------------
|
/*----------------------------------------------------------------
|
||||||
@@ -1060,47 +1135,6 @@ void adjustcurves(Network *network, int index)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int adjustpumpparams(Project *pr, int curveIndex)
|
|
||||||
/*----------------------------------------------------------------
|
|
||||||
** Input: curveIndex = index of a data curve
|
|
||||||
** Output: returns an error code
|
|
||||||
** Purpose: updates head curve parameters for pumps using a
|
|
||||||
** curve whose data have been modified.
|
|
||||||
**----------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
Network *network = &pr->network;
|
|
||||||
|
|
||||||
double *Ucf = pr->Ucf;
|
|
||||||
int j, err = 0;
|
|
||||||
Spump *pump;
|
|
||||||
|
|
||||||
// Check each pump
|
|
||||||
for (j = 1; j <= network->Npumps; j++)
|
|
||||||
{
|
|
||||||
// Pump uses curve as head curve
|
|
||||||
pump = &network->Pump[j];
|
|
||||||
if ( curveIndex == pump->Hcurve)
|
|
||||||
{
|
|
||||||
// Update its head curve parameters
|
|
||||||
pump->Ptype = NOCURVE;
|
|
||||||
err = updatepumpparams(pr, j);
|
|
||||||
if (err > 0) break;
|
|
||||||
|
|
||||||
// Convert parameters to internal units
|
|
||||||
if (pump->Ptype == POWER_FUNC)
|
|
||||||
{
|
|
||||||
pump->H0 /= Ucf[HEAD];
|
|
||||||
pump->R *= (pow(Ucf[FLOW], pump->N) / Ucf[HEAD]);
|
|
||||||
}
|
|
||||||
pump->Q0 /= Ucf[FLOW];
|
|
||||||
pump->Qmax /= Ucf[FLOW];
|
|
||||||
pump->Hmax /= Ucf[HEAD];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int resizecurve(Scurve *curve, int size)
|
int resizecurve(Scurve *curve, int size)
|
||||||
/*----------------------------------------------------------------
|
/*----------------------------------------------------------------
|
||||||
@@ -1448,6 +1482,7 @@ double interp(int n, double x[], double y[], double xx)
|
|||||||
int k, m;
|
int k, m;
|
||||||
double dx, dy;
|
double dx, dy;
|
||||||
|
|
||||||
|
if (n == 0) return 0.0;
|
||||||
m = n - 1; // Highest data index
|
m = n - 1; // Highest data index
|
||||||
if (xx <= x[0]) return (y[0]); // xx off low end of curve
|
if (xx <= x[0]) return (y[0]); // xx off low end of curve
|
||||||
for (k = 1; k <= m; k++) // Bracket xx on curve
|
for (k = 1; k <= m; k++) // Bracket xx on curve
|
||||||
|
|||||||
@@ -404,7 +404,7 @@ void adjustrules(Project *pr, int objtype, int index)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void adjusttankrules(Project *pr)
|
void adjusttankrules(Project *pr, int ndiff)
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
// Adjusts tank indices in rule premises.
|
// Adjusts tank indices in rule premises.
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
@@ -420,7 +420,8 @@ void adjusttankrules(Project *pr)
|
|||||||
p = net->Rule[i].Premises;
|
p = net->Rule[i].Premises;
|
||||||
while (p != NULL)
|
while (p != NULL)
|
||||||
{
|
{
|
||||||
if (p->object == r_NODE && p->index > njuncs) p->index++;
|
if (p->object == r_NODE && p->index > njuncs)
|
||||||
|
p->index += ndiff;
|
||||||
p = p->next;
|
p = p->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
413
src/validate.c
Normal file
413
src/validate.c
Normal file
@@ -0,0 +1,413 @@
|
|||||||
|
/*
|
||||||
|
******************************************************************************
|
||||||
|
Project: OWA EPANET
|
||||||
|
Version: 2.2
|
||||||
|
Module: validate.c
|
||||||
|
Description: validates project data
|
||||||
|
Authors: see AUTHORS
|
||||||
|
Copyright: see AUTHORS
|
||||||
|
License: see LICENSE
|
||||||
|
Last Updated: 09/28/2023
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "funcs.h"
|
||||||
|
#include "text.h"
|
||||||
|
|
||||||
|
// Exported functions
|
||||||
|
int validateproject(Project *pr);
|
||||||
|
void reindextanks(Project *pr);
|
||||||
|
|
||||||
|
int validatetanks(Project *pr)
|
||||||
|
/*
|
||||||
|
**-------------------------------------------------------------------
|
||||||
|
** Input: none
|
||||||
|
** Output: returns 1 if successful, 0 if not
|
||||||
|
** Purpose: checks for valid tank levels.
|
||||||
|
**-------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
Network *net = &pr->network;
|
||||||
|
int i, j, n, result = 1, levelerr;
|
||||||
|
char errmsg[MAXMSG+1] = "";
|
||||||
|
Stank *tank;
|
||||||
|
Scurve *curve;
|
||||||
|
|
||||||
|
for (j = 1; j <= net->Ntanks; j++)
|
||||||
|
{
|
||||||
|
tank = &net->Tank[j];
|
||||||
|
if (tank->A == 0.0) continue; // Skip reservoirs
|
||||||
|
|
||||||
|
// Check for valid lower/upper tank levels
|
||||||
|
levelerr = 0;
|
||||||
|
if (tank->H0 > tank->Hmax ||
|
||||||
|
tank->Hmin > tank->Hmax ||
|
||||||
|
tank->H0 < tank->Hmin
|
||||||
|
) levelerr = 1;
|
||||||
|
|
||||||
|
// Check that tank heights are within volume curve
|
||||||
|
i = tank->Vcurve;
|
||||||
|
if (i > 0)
|
||||||
|
{
|
||||||
|
curve = &net->Curve[i];
|
||||||
|
n = curve->Npts - 1;
|
||||||
|
if (tank->Hmin * pr->Ucf[ELEV] < curve->X[0] ||
|
||||||
|
tank->Hmax * pr->Ucf[ELEV]> curve->X[n])
|
||||||
|
{
|
||||||
|
levelerr = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Report error in levels if found
|
||||||
|
if (levelerr)
|
||||||
|
{
|
||||||
|
sprintf(pr->Msg, "Error 225: %s node %s", geterrmsg(225, errmsg),
|
||||||
|
net->Node[tank->Node].ID);
|
||||||
|
writeline(pr, pr->Msg);
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int validatepatterns(Project *pr)
|
||||||
|
/*
|
||||||
|
**-------------------------------------------------------------------
|
||||||
|
** Input: none
|
||||||
|
** Output: returns 1 if successful, 0 if not
|
||||||
|
** Purpose: checks if time patterns have data.
|
||||||
|
**-------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
Network *net = &pr->network;
|
||||||
|
int j, result = 1;
|
||||||
|
char errmsg[MAXMSG+1] = "";
|
||||||
|
|
||||||
|
if (pr->network.Pattern != NULL)
|
||||||
|
{
|
||||||
|
for (j = 0; j <= pr->network.Npats; j++)
|
||||||
|
{
|
||||||
|
if (pr->network.Pattern[j].Length == 0)
|
||||||
|
{
|
||||||
|
sprintf(pr->Msg, "Error 232: %s %s", geterrmsg(232, errmsg),
|
||||||
|
pr->network.Pattern[j].ID);
|
||||||
|
writeline(pr, pr->Msg);
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int validatecurves(Project *pr)
|
||||||
|
/*
|
||||||
|
**-------------------------------------------------------------------
|
||||||
|
** Input: none
|
||||||
|
** Output: returns 1 if successful, 0 if not
|
||||||
|
** Purpose: checks if data curves have data.
|
||||||
|
**-------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int i, j, npts, result = 1;
|
||||||
|
char errmsg[MAXMSG+1] = "";
|
||||||
|
Scurve *curve;
|
||||||
|
|
||||||
|
if (pr->network.Curve != NULL)
|
||||||
|
{
|
||||||
|
for (j = 1; j <= pr->network.Ncurves; j++)
|
||||||
|
{
|
||||||
|
// Check that curve has data
|
||||||
|
curve = &pr->network.Curve[j];
|
||||||
|
npts = curve->Npts;
|
||||||
|
if (npts == 0)
|
||||||
|
{
|
||||||
|
sprintf(pr->Msg, "Error 231: %s %s", geterrmsg(231, errmsg),
|
||||||
|
curve->ID);
|
||||||
|
writeline(pr, pr->Msg);
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that x values are increasing
|
||||||
|
for (i = 1; i < npts; i++)
|
||||||
|
{
|
||||||
|
if (curve->X[i-1] >= curve->X[i])
|
||||||
|
{
|
||||||
|
sprintf(pr->Msg, "Error 230: %s %s", geterrmsg(230, errmsg),
|
||||||
|
curve->ID);
|
||||||
|
writeline(pr, pr->Msg);
|
||||||
|
result = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int powercurve(double h0, double h1, double h2, double q1, double q2,
|
||||||
|
double *a, double *b, double *c)
|
||||||
|
/*
|
||||||
|
**---------------------------------------------------------
|
||||||
|
** Input: h0 = shutoff head
|
||||||
|
** h1 = design head
|
||||||
|
** h2 = head at max. flow
|
||||||
|
** q1 = design flow
|
||||||
|
** q2 = max. flow
|
||||||
|
** Output: *a, *b, *c = pump curve coeffs. (H = a-bQ^c),
|
||||||
|
** Returns 1 if sucessful, 0 otherwise.
|
||||||
|
** Purpose: computes coeffs. for pump curve
|
||||||
|
**----------------------------------------------------------
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
double h4, h5;
|
||||||
|
|
||||||
|
if (h0 < TINY || h0 - h1 < TINY || h1 - h2 < TINY ||
|
||||||
|
q1 < TINY || q2 - q1 < TINY
|
||||||
|
) return 0;
|
||||||
|
*a = h0;
|
||||||
|
h4 = h0 - h1;
|
||||||
|
h5 = h0 - h2;
|
||||||
|
*c = log(h5 / h4) / log(q2 / q1);
|
||||||
|
if (*c <= 0.0 || *c > 20.0) return 0;
|
||||||
|
*b = -h4 / pow(q1, *c);
|
||||||
|
if (*b >= 0.0) return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int findpumpparams(Project *pr, int pumpindex)
|
||||||
|
/*
|
||||||
|
**-------------------------------------------------------------
|
||||||
|
** Input: pumpindex = index of a pump
|
||||||
|
** Output: returns error code
|
||||||
|
** Purpose: computes & checks a pump's head curve coefficients
|
||||||
|
**--------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
Network *net = &pr->network;
|
||||||
|
Spump *pump;
|
||||||
|
Scurve *curve;
|
||||||
|
|
||||||
|
int m;
|
||||||
|
int curveindex;
|
||||||
|
int npts = 0;
|
||||||
|
int errcode = 0;
|
||||||
|
double a, b, c, h0 = 0.0, h1 = 0.0, h2 = 0.0, q1 = 0.0, q2 = 0.0;
|
||||||
|
|
||||||
|
pump = &net->Pump[pumpindex];
|
||||||
|
if (pump->Ptype == CONST_HP) // Constant Hp pump
|
||||||
|
{
|
||||||
|
pump->H0 = 0.0;
|
||||||
|
pump->R = -8.814 * net->Link[pump->Link].Km;
|
||||||
|
pump->N = -1.0;
|
||||||
|
pump->Hmax = BIG; // No head limit
|
||||||
|
pump->Qmax = BIG; // No flow limit
|
||||||
|
pump->Q0 = 1.0; // Init. flow = 1 cfs
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (pump->Ptype == NOCURVE) // Pump curve specified
|
||||||
|
{
|
||||||
|
curveindex = pump->Hcurve;
|
||||||
|
if (curveindex == 0) return 226;
|
||||||
|
curve = &net->Curve[curveindex];
|
||||||
|
curve->Type = PUMP_CURVE;
|
||||||
|
npts = curve->Npts;
|
||||||
|
|
||||||
|
// Generic power function curve
|
||||||
|
if (npts == 1)
|
||||||
|
{
|
||||||
|
pump->Ptype = POWER_FUNC;
|
||||||
|
q1 = curve->X[0];
|
||||||
|
h1 = curve->Y[0];
|
||||||
|
h0 = 1.33334 * h1;
|
||||||
|
q2 = 2.0 * q1;
|
||||||
|
h2 = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3 point curve with shutoff head
|
||||||
|
else if (npts == 3 && curve->X[0] == 0.0)
|
||||||
|
{
|
||||||
|
pump->Ptype = POWER_FUNC;
|
||||||
|
h0 = curve->Y[0];
|
||||||
|
q1 = curve->X[1];
|
||||||
|
h1 = curve->Y[1];
|
||||||
|
q2 = curve->X[2];
|
||||||
|
h2 = curve->Y[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom pump curve
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pump->Ptype = CUSTOM;
|
||||||
|
for (m = 1; m < npts; m++)
|
||||||
|
{
|
||||||
|
if (curve->Y[m] >= curve->Y[m - 1])
|
||||||
|
{
|
||||||
|
pump->Ptype = NOCURVE;
|
||||||
|
return 227;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pump->Qmax = curve->X[npts - 1];
|
||||||
|
pump->Q0 = (curve->X[0] + pump->Qmax) / 2.0;
|
||||||
|
pump->Hmax = curve->Y[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute shape factors & limits of power function curves
|
||||||
|
if (pump->Ptype == POWER_FUNC)
|
||||||
|
{
|
||||||
|
if (!powercurve(h0, h1, h2, q1, q2, &a, &b, &c))
|
||||||
|
{
|
||||||
|
pump->Ptype = NOCURVE;
|
||||||
|
return 227;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pump->H0 = -a;
|
||||||
|
pump->R = -b;
|
||||||
|
pump->N = c;
|
||||||
|
pump->Q0 = q1;
|
||||||
|
pump->Qmax = pow((-a / b), (1.0 / c));
|
||||||
|
pump->Hmax = h0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert units of pump coefficients
|
||||||
|
if (pump->Ptype == POWER_FUNC)
|
||||||
|
{
|
||||||
|
pump->H0 /= pr->Ucf[HEAD];
|
||||||
|
pump->R *= (pow(pr->Ucf[FLOW], pump->N) / pr->Ucf[HEAD]);
|
||||||
|
}
|
||||||
|
pump->R /= pr->Ucf[POWER];
|
||||||
|
pump->Q0 /= pr->Ucf[FLOW];
|
||||||
|
pump->Qmax /= pr->Ucf[FLOW];
|
||||||
|
pump->Hmax /= pr->Ucf[HEAD];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int validatepumps(Project *pr)
|
||||||
|
/*
|
||||||
|
**-------------------------------------------------------------------
|
||||||
|
** Input: none
|
||||||
|
** Output: returns 1 if successful, 0 if not
|
||||||
|
** Purpose: checks if pumps assigned pump curves.
|
||||||
|
**-------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
Network *net = &pr->network;
|
||||||
|
int i, k, errcode, result = 1;
|
||||||
|
char errmsg[MAXMSG+1] = "";
|
||||||
|
Spump *pump;
|
||||||
|
|
||||||
|
for (i = 1; i <= net->Npumps; i++)
|
||||||
|
{
|
||||||
|
// Check if pump has neither a head curve nor power setting
|
||||||
|
pump = &net->Pump[i];
|
||||||
|
k = pump->Link;
|
||||||
|
if (net->Link[k].Km == 0.0 && pump->Hcurve <= 0)
|
||||||
|
{
|
||||||
|
sprintf(pr->Msg, "Error 226: %s %s",
|
||||||
|
geterrmsg(226, errmsg), net->Link[k].ID);
|
||||||
|
writeline(pr, pr->Msg);
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute & check pump's head curve coefficients
|
||||||
|
else
|
||||||
|
{
|
||||||
|
errcode = findpumpparams(pr, i);
|
||||||
|
if (errcode)
|
||||||
|
{
|
||||||
|
sprintf(pr->Msg, "Error %d: %s %s",
|
||||||
|
errcode, geterrmsg(errcode, errmsg), net->Link[k].ID);
|
||||||
|
writeline(pr, pr->Msg);
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int validateproject(Project *pr)
|
||||||
|
/*
|
||||||
|
*--------------------------------------------------------------
|
||||||
|
* Input: none
|
||||||
|
* Output: returns error code
|
||||||
|
* Purpose: checks for valid network data.
|
||||||
|
*--------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int errcode = 0;
|
||||||
|
if (pr->network.Nnodes < 2) return 223;
|
||||||
|
if (pr->network.Ntanks == 0) return 224;
|
||||||
|
if (!validatetanks(pr)) errcode = 110;
|
||||||
|
if (!validatepumps(pr)) errcode = 110;
|
||||||
|
if (!validatepatterns(pr)) errcode = 110;
|
||||||
|
if (!validatecurves(pr)) errcode = 110;
|
||||||
|
return errcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reindextanks(Project *pr)
|
||||||
|
/*
|
||||||
|
*--------------------------------------------------------------
|
||||||
|
* Input: none
|
||||||
|
* Output: none
|
||||||
|
* Purpose: adjusts tank node indexes when the number of
|
||||||
|
* junctions created from an input file is less than
|
||||||
|
* the total number of junction lines in the file.
|
||||||
|
*--------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
Network *net = &pr->network;
|
||||||
|
Parser *parser = &pr->parser;
|
||||||
|
Quality *qual = &pr->quality;
|
||||||
|
Scontrol *control;
|
||||||
|
int i, j, ndiff, n1, n2, size;
|
||||||
|
|
||||||
|
// ndiff = # unused entries in Node array before first tank node
|
||||||
|
ndiff = parser->MaxJuncs - net->Njuncs;
|
||||||
|
if (ndiff > 0)
|
||||||
|
{
|
||||||
|
for (i = 1; i <= net->Ntanks; ++i)
|
||||||
|
{
|
||||||
|
// n1 is current tank index in Node array, n2 is adjusted index
|
||||||
|
n1 = net->Tank[i].Node;
|
||||||
|
n2 = n1 - ndiff;
|
||||||
|
|
||||||
|
// Update the tank node's hash table entry
|
||||||
|
hashtable_update(net->NodeHashTable, net->Node[n1].ID, n2);
|
||||||
|
|
||||||
|
// Update the tank's node index
|
||||||
|
net->Tank[i].Node = n2;
|
||||||
|
|
||||||
|
// Re-position tank node in Node array
|
||||||
|
net->Node[n2] = net->Node[n1];
|
||||||
|
|
||||||
|
// Replace all references to old tank node index with new one
|
||||||
|
for (j = 1; j <= net->Nlinks; ++j)
|
||||||
|
{
|
||||||
|
if (net->Link[j].N1 == n1) net->Link[j].N1 = n2;
|
||||||
|
if (net->Link[j].N2 == n1) net->Link[j].N2 = n2;
|
||||||
|
}
|
||||||
|
for (j = 1; j <= net->Ncontrols; ++j)
|
||||||
|
{
|
||||||
|
control = &net->Control[j];
|
||||||
|
if (control->Node == n1) control->Node = n2;
|
||||||
|
}
|
||||||
|
adjusttankrules(pr, -ndiff);
|
||||||
|
if (qual->TraceNode == n1) qual->TraceNode = n2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reallocate the Node array (shouldn't fail as new size < old size)
|
||||||
|
parser->MaxJuncs = net->Njuncs;
|
||||||
|
parser->MaxNodes = net->Njuncs + net->Ntanks;
|
||||||
|
size = (net->Nnodes + 2) * sizeof(Snode);
|
||||||
|
net->Node = (Snode *)realloc(net->Node, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user