Add support for bar and feet as pressure units, fix psi or m for emitters

This commit is contained in:
lbutler
2025-07-04 16:10:01 -04:00
parent f8f2d74bea
commit 3d1d6496c9
12 changed files with 59 additions and 25 deletions

View File

@@ -166,6 +166,8 @@ Public Const EN_CMS = 10
Public Const EN_PSI = 0 ' Pressure units types Public Const EN_PSI = 0 ' Pressure units types
Public Const EN_KPA = 1 Public Const EN_KPA = 1
Public Const EN_METERS = 2 Public Const EN_METERS = 2
Public Const EN_BAR = 3
Public Const EN_FEET = 4
Public Const EN_DDA = 0 ' Demand driven analysis Public Const EN_DDA = 0 ' Demand driven analysis
Public Const EN_PDA = 1 ' Pressure driven analysis Public Const EN_PDA = 1 ' Pressure driven analysis

View File

@@ -170,6 +170,8 @@ namespace EpanetCSharpLibrary
public const int EN_PSI = 0; //Pressure units types public const int EN_PSI = 0; //Pressure units types
public const int EN_KPA = 1; public const int EN_KPA = 1;
public const int EN_METERS = 2; public const int EN_METERS = 2;
public const int EN_BAR = 3;
public const int EN_FEET = 4;
public const int EN_DDA = 0; //Demand driven analysis public const int EN_DDA = 0; //Demand driven analysis
public const int EN_PDA = 1; //Pressure driven analysis public const int EN_PDA = 1; //Pressure driven analysis

View File

@@ -174,6 +174,8 @@ const
EN_PSI = 0; { Pressure units types } EN_PSI = 0; { Pressure units types }
EN_KPA = 1; EN_KPA = 1;
EN_METERS = 2; EN_METERS = 2;
EN_BAR = 3;
EN_FEET = 4;
EN_DDA = 0; { Demand model types } EN_DDA = 0; { Demand model types }
EN_PDA = 1; EN_PDA = 1;

View File

@@ -161,6 +161,8 @@ Public Const EN_CMS = 10
Public Const EN_PSI = 0 ' Pressure units types Public Const EN_PSI = 0 ' Pressure units types
Public Const EN_KPA = 1 Public Const EN_KPA = 1
Public Const EN_METERS = 2 Public Const EN_METERS = 2
Public Const EN_BAR = 3
Public Const EN_FEET = 4
Public Const EN_DDA = 0 ' Demand driven analysis Public Const EN_DDA = 0 ' Demand driven analysis
Public Const EN_PDA = 1 ' Pressure driven analysis Public Const EN_PDA = 1 ' Pressure driven analysis

View File

@@ -301,14 +301,14 @@ typedef enum {
/// Pressure units /// Pressure units
/** /**
The available choices for pressure units for the `EN_PRESS_UNITS` option in @ref EN_getoption The available choices for pressure units for the `EN_PRESS_UNITS` option in @ref EN_getoption
and @ref EN_setoption. For networks using US Customary units for flow (`EN_CFS` through and @ref EN_setoption.
`EN_AFD`) pressure units can only be set as PSI. For network using metric units, you can
select either `EN_METERS` or `EN_KPA`.
*/ */
typedef enum { typedef enum {
EN_PSI = 0, //!< Pounds per square inch EN_PSI = 0, //!< Pounds per square inch
EN_KPA = 1, //!< Kilopascals EN_KPA = 1, //!< Kilopascals
EN_METERS = 2 //!< Meters EN_METERS = 2, //!< Meters
EN_BAR = 3, //!< Bar
EN_FEET = 4 //!< Feet
} EN_PressUnits; } EN_PressUnits;
/// Demand models /// Demand models

View File

@@ -76,7 +76,9 @@ char *FlowUnitsTxt[] = {w_CFS,
char *PressUnitsTxt[] = {w_PSI, char *PressUnitsTxt[] = {w_PSI,
w_KPA, w_KPA,
w_METERS}; w_METERS,
w_BAR,
w_FEET};
char *DemandModelTxt[] = { w_DDA, char *DemandModelTxt[] = { w_DDA,
w_PDA, w_PDA,

View File

@@ -1410,7 +1410,7 @@ int DLLEXPORT EN_setoption(EN_Project p, int option, double value)
case EN_PRESS_UNITS: case EN_PRESS_UNITS:
unit = ROUND(value); unit = ROUND(value);
if (unit < 0 || unit > METERS) return 205; if (unit < 0 || unit > FEET) return 205;
p->parser.Pressflag = unit; p->parser.Pressflag = unit;
dfactor = Ucf[DEMAND]; dfactor = Ucf[DEMAND];
@@ -1465,7 +1465,7 @@ int DLLEXPORT EN_setflowunits(EN_Project p, int units)
{ {
Network *net = &p->network; Network *net = &p->network;
int i, j; int i, j, oldUnitFlag;
double qfactor, vfactor, hfactor, efactor, pfactor, dfactor, xfactor, yfactor; double qfactor, vfactor, hfactor, efactor, pfactor, dfactor, xfactor, yfactor;
double dcf, pcf, hcf, qcf; double dcf, pcf, hcf, qcf;
double *Ucf = p->Ucf; double *Ucf = p->Ucf;
@@ -1480,6 +1480,7 @@ int DLLEXPORT EN_setflowunits(EN_Project p, int units)
pfactor = Ucf[PRESSURE]; pfactor = Ucf[PRESSURE];
dfactor = Ucf[DEMAND]; dfactor = Ucf[DEMAND];
oldUnitFlag = p->parser.Unitsflag;
p->parser.Flowflag = units; p->parser.Flowflag = units;
switch (units) switch (units)
{ {
@@ -1497,8 +1498,11 @@ int DLLEXPORT EN_setflowunits(EN_Project p, int units)
} }
// Revise pressure units depending on flow units // Revise pressure units depending on flow units
if (p->parser.Unitsflag != SI) p->parser.Pressflag = PSI; if (oldUnitFlag != p->parser.Unitsflag)
else if (p->parser.Pressflag == PSI) p->parser.Pressflag = METERS; {
if (p->parser.Unitsflag == US) p->parser.Pressflag = PSI;
else p->parser.Pressflag = METERS;
}
initunits(p); initunits(p);
// Update pressure units in rules // Update pressure units in rules
@@ -2233,8 +2237,10 @@ int DLLEXPORT EN_getnodevalue(EN_Project p, int index, int property, double *val
Network *net = &p->network; Network *net = &p->network;
Hydraul *hyd = &p->hydraul; Hydraul *hyd = &p->hydraul;
Quality *qual = &p->quality; Quality *qual = &p->quality;
Parser *parser = &p->parser;
double v = 0.0; double v = 0.0;
double ecfTmp; // Unit conversion factor for emitter pressure
Psource source; Psource source;
Snode *Node = net->Node; Snode *Node = net->Node;
@@ -2279,7 +2285,9 @@ int DLLEXPORT EN_getnodevalue(EN_Project p, int index, int property, double *val
v = 0.0; v = 0.0;
if (Node[index].Ke > 0.0) if (Node[index].Ke > 0.0)
{ {
v = Ucf[FLOW] / pow((Ucf[PRESSURE] * Node[index].Ke), (1.0 / hyd->Qexp)); ecfTmp = (parser->Unitsflag == US) ? (1.0 / PSIperFT) : (1.0 / MperFT);
ecfTmp /= hyd->SpGrav;
v = Ucf[FLOW] / pow((ecfTmp * Node[index].Ke), (1.0 / hyd->Qexp));
} }
break; break;
@@ -2468,6 +2476,7 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int property, double valu
Network *net = &p->network; Network *net = &p->network;
Hydraul *hyd = &p->hydraul; Hydraul *hyd = &p->hydraul;
Quality *qual = &p->quality; Quality *qual = &p->quality;
Parser *parser = &p->parser;
Snode *Node = net->Node; Snode *Node = net->Node;
Stank *Tank = net->Tank; Stank *Tank = net->Tank;
@@ -2481,7 +2490,7 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int property, double valu
int i, j, n; int i, j, n;
Psource source; Psource source;
double hTmp; double hTmp, ecfTmp;
if (!p->Openflag) return 102; if (!p->Openflag) return 102;
if (index <= 0 || index > nNodes) return 203; if (index <= 0 || index > nNodes) return 203;
@@ -2523,7 +2532,12 @@ int DLLEXPORT EN_setnodevalue(EN_Project p, int index, int property, double valu
case EN_EMITTER: case EN_EMITTER:
if (index > nJuncs) return 0; if (index > nJuncs) return 0;
if (value < 0.0) return 209; if (value < 0.0) return 209;
if (value > 0.0) value = pow((Ucf[FLOW] / value), hyd->Qexp) / Ucf[PRESSURE]; if (value > 0.0)
{
ecfTmp = (parser->Unitsflag == US) ? (1.0 / PSIperFT) : (1.0 / MperFT);
ecfTmp /= hyd->SpGrav;
value = pow((Ucf[FLOW] / value), hyd->Qexp) / ecfTmp;
}
Node[index].Ke = value; Node[index].Ke = value;
if (hyd->EmitterFlow[index] == 0.0) hyd->EmitterFlow[index] = 1.0; if (hyd->EmitterFlow[index] == 0.0) hyd->EmitterFlow[index] = 1.0;
break; break;

View File

@@ -40,6 +40,7 @@ Last Updated: 04/19/2025
// Defined in ENUMSTXT.H // Defined in ENUMSTXT.H
extern char *Fldname[]; extern char *Fldname[];
extern char *RptFlowUnitsTxt[]; extern char *RptFlowUnitsTxt[];
extern char *PressUnitsTxt[];
extern void reindextanks(Project *pr); extern void reindextanks(Project *pr);
@@ -103,7 +104,7 @@ void setdefaults(Project *pr)
pr->Warnflag = FALSE; // Warning flag is off pr->Warnflag = FALSE; // Warning flag is off
parser->Unitsflag = US; // US unit system parser->Unitsflag = US; // US unit system
parser->Flowflag = GPM; // Flow units are gpm parser->Flowflag = GPM; // Flow units are gpm
parser->Pressflag = UNITDEFAULT; // Pressure units set based on unit system parser->Pressflag = DEFAULTUNIT; // Pressure units set based on unit system
out->Hydflag = SCRATCH; // No external hydraulics file out->Hydflag = SCRATCH; // No external hydraulics file
rpt->Tstatflag = SERIES; // Generate time series output rpt->Tstatflag = SERIES; // Generate time series output
@@ -269,7 +270,7 @@ void adjustdata(Project *pr)
} }
// Revise pressure units depending on flow units // Revise pressure units depending on flow units
if (parser->Pressflag == UNITDEFAULT) if (parser->Pressflag == DEFAULTUNIT)
{ {
if (parser->Unitsflag == SI) parser->Pressflag = METERS; if (parser->Unitsflag == SI) parser->Pressflag = METERS;
else parser->Pressflag = PSI; else parser->Pressflag = PSI;
@@ -450,13 +451,12 @@ void initunits(Project *pr)
wcf = 1.0; wcf = 1.0;
} }
if (parser->Pressflag == METERS) strcpy(rpt->Field[PRESSURE].Units, u_METERS); strcpy(rpt->Field[PRESSURE].Units, PressUnitsTxt[parser->Pressflag]);
else if (parser->Pressflag == KPA) strcpy(rpt->Field[PRESSURE].Units, u_KPA); pcf = PSIperFT * hyd->SpGrav; // Default to PSI
else strcpy(rpt->Field[PRESSURE].Units, u_PSI);
if (parser->Pressflag == METERS) pcf = MperFT * hyd->SpGrav; if (parser->Pressflag == METERS) pcf = MperFT * hyd->SpGrav;
else if (parser->Pressflag == KPA) pcf = KPAperPSI * PSIperFT * hyd->SpGrav; if (parser->Pressflag == KPA) pcf = KPAperPSI * PSIperFT * hyd->SpGrav;
else pcf = PSIperFT * hyd->SpGrav; if (parser->Pressflag == BAR) pcf = BARperPSI * PSIperFT * hyd->SpGrav;
if (parser->Pressflag == FEET) pcf = 1.0 * hyd->SpGrav;
strcpy(rpt->Field[QUALITY].Units, ""); strcpy(rpt->Field[QUALITY].Units, "");
ccf = 1.0; ccf = 1.0;
@@ -514,7 +514,7 @@ void convertunits(Project *pr)
Parser *parser = &pr->parser; Parser *parser = &pr->parser;
int i, j, k; int i, j, k;
double ucf; // Unit conversion factor double ucf, ecf; // Unit conversion factor
Pdemand demand; // Pointer to demand record Pdemand demand; // Pointer to demand record
Snode *node; Snode *node;
Stank *tank; Stank *tank;
@@ -545,7 +545,10 @@ void convertunits(Project *pr)
hyd->Preq /= pr->Ucf[PRESSURE]; hyd->Preq /= pr->Ucf[PRESSURE];
// Convert emitter discharge coeffs. to head loss coeff. // Convert emitter discharge coeffs. to head loss coeff.
ucf = pow(pr->Ucf[FLOW], hyd->Qexp) / pr->Ucf[PRESSURE]; ecf = (parser->Unitsflag == US) ? (1.0 / PSIperFT) : (1.0 / MperFT);
ecf /= hyd->SpGrav;
ucf = pow(pr->Ucf[FLOW], hyd->Qexp) / ecf;
for (i = 1; i <= net->Njuncs; i++) for (i = 1; i <= net->Njuncs; i++)
{ {
node = &net->Node[i]; node = &net->Node[i];

View File

@@ -1926,6 +1926,8 @@ int optionchoice(Project *pr, int n)
else if (match(parser->Tok[1], w_PSI)) parser->Pressflag = PSI; else if (match(parser->Tok[1], w_PSI)) parser->Pressflag = PSI;
else if (match(parser->Tok[1], w_KPA)) parser->Pressflag = KPA; else if (match(parser->Tok[1], w_KPA)) parser->Pressflag = KPA;
else if (match(parser->Tok[1], w_METERS)) parser->Pressflag = METERS; else if (match(parser->Tok[1], w_METERS)) parser->Pressflag = METERS;
else if (match(parser->Tok[1], w_BAR)) parser->Pressflag = BAR;
else if (match(parser->Tok[1], w_FEET)) parser->Pressflag = FEET;
else return setError(parser, 1, 213); else return setError(parser, 1, 213);
} }

View File

@@ -90,6 +90,8 @@
#define w_PSI "PSI" #define w_PSI "PSI"
#define w_KPA "KPA" #define w_KPA "KPA"
#define w_METERS "METERS" #define w_METERS "METERS"
#define w_BAR "BAR"
#define w_FEET "FEET"
#define w_ELEV "ELEV" #define w_ELEV "ELEV"
#define w_DEMAND "DEMAND" #define w_DEMAND "DEMAND"

View File

@@ -83,6 +83,7 @@ typedef int INT4;
#define MperFT 0.3048 #define MperFT 0.3048
#define PSIperFT 0.4333 #define PSIperFT 0.4333
#define KPAperPSI 6.895 #define KPAperPSI 6.895
#define BARperPSI 0.068948
#define KWperHP 0.7457 #define KWperHP 0.7457
#define SECperDAY 86400 #define SECperDAY 86400
@@ -239,7 +240,9 @@ typedef enum {
PSI, // pounds per square inch PSI, // pounds per square inch
KPA, // kiloPascals KPA, // kiloPascals
METERS, // meters METERS, // meters
UNITDEFAULT // default based on unit system (SI or US) BAR, // bar
FEET, // feet
DEFAULTUNIT // default based on unit system (SI or US)
} PressureUnitsType; } PressureUnitsType;
typedef enum { typedef enum {

View File

@@ -312,10 +312,10 @@ BOOST_FIXTURE_TEST_CASE(test_decoupled_pressure_units, FixtureInitClose)
error = EN_setflowunits(ph, EN_LPS); error = EN_setflowunits(ph, EN_LPS);
BOOST_REQUIRE(error == 0); BOOST_REQUIRE(error == 0);
// Pressure units should remain kPa (not auto-changed to meters) // Pressure units should change to metric default of meters
error = EN_getoption(ph, EN_PRESS_UNITS, &units); error = EN_getoption(ph, EN_PRESS_UNITS, &units);
BOOST_REQUIRE(error == 0); BOOST_REQUIRE(error == 0);
BOOST_CHECK(units == EN_KPA); BOOST_CHECK(units == EN_METERS);
// Test 5: With SI flow units, set pressure to PSI (should now work) // Test 5: With SI flow units, set pressure to PSI (should now work)
error = EN_setoption(ph, EN_PRESS_UNITS, EN_PSI); error = EN_setoption(ph, EN_PRESS_UNITS, EN_PSI);