Decoupled pressure units from the flow unit system
Decoupled pressure units from the flow unit system, allowing them to be set independently to support mixed-unit conventions (e.g., using LPS for flow and PSI for pressure).
This commit is contained in:
@@ -42,6 +42,8 @@ This document describes the changes and updates that have been made in version 2
|
|||||||
|
|
||||||
- `EN_PRESS_UNITS` can now be used with `EN_getoption` and `EN_setoption` to get or set the pressure unit used in EPANET.
|
- `EN_PRESS_UNITS` can now be used with `EN_getoption` and `EN_setoption` to get or set the pressure unit used in EPANET.
|
||||||
|
|
||||||
|
- Decoupled pressure units from the flow unit system, allowing them to be set independently to support mixed-unit conventions (e.g., using LPS for flow and PSI for pressure).
|
||||||
|
|
||||||
- The following constants can be used with EN_getnodevalue to retrieve the components of a node's total demand at a given point in time:
|
- The following constants can be used with EN_getnodevalue to retrieve the components of a node's total demand at a given point in time:
|
||||||
- `EN_FULLDEMAND` - the consumer demand requested
|
- `EN_FULLDEMAND` - the consumer demand requested
|
||||||
- `EN_DEMANDFLOW` - the consumer demand delivered
|
- `EN_DEMANDFLOW` - the consumer demand delivered
|
||||||
|
|||||||
@@ -1411,8 +1411,6 @@ 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 > METERS) return 205;
|
||||||
if (p->parser.Unitsflag == US && unit > PSI) return 0;
|
|
||||||
if (p->parser.Unitsflag == SI && unit == PSI) return 0;
|
|
||||||
p->parser.Pressflag = unit;
|
p->parser.Pressflag = unit;
|
||||||
|
|
||||||
dfactor = Ucf[DEMAND];
|
dfactor = Ucf[DEMAND];
|
||||||
|
|||||||
22
src/input1.c
22
src/input1.c
@@ -103,7 +103,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 = PSI; // Pressure units are psi
|
parser->Pressflag = UNITDEFAULT; // 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,8 +269,11 @@ void adjustdata(Project *pr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Revise pressure units depending on flow units
|
// Revise pressure units depending on flow units
|
||||||
if (parser->Unitsflag != SI) parser->Pressflag = PSI;
|
if (parser->Pressflag == UNITDEFAULT)
|
||||||
else if (parser->Pressflag == PSI) parser->Pressflag = METERS;
|
{
|
||||||
|
if (parser->Unitsflag == SI) parser->Pressflag = METERS;
|
||||||
|
else parser->Pressflag = PSI;
|
||||||
|
}
|
||||||
|
|
||||||
// Store value of viscosity & diffusivity
|
// Store value of viscosity & diffusivity
|
||||||
ucf = 1.0;
|
ucf = 1.0;
|
||||||
@@ -404,8 +407,6 @@ void initunits(Project *pr)
|
|||||||
strcpy(rpt->Field[DEMAND].Units, RptFlowUnitsTxt[parser->Flowflag]);
|
strcpy(rpt->Field[DEMAND].Units, RptFlowUnitsTxt[parser->Flowflag]);
|
||||||
strcpy(rpt->Field[ELEV].Units, u_METERS);
|
strcpy(rpt->Field[ELEV].Units, u_METERS);
|
||||||
strcpy(rpt->Field[HEAD].Units, u_METERS);
|
strcpy(rpt->Field[HEAD].Units, u_METERS);
|
||||||
if (parser->Pressflag == METERS) strcpy(rpt->Field[PRESSURE].Units, u_METERS);
|
|
||||||
else strcpy(rpt->Field[PRESSURE].Units, u_KPA);
|
|
||||||
strcpy(rpt->Field[LENGTH].Units, u_METERS);
|
strcpy(rpt->Field[LENGTH].Units, u_METERS);
|
||||||
strcpy(rpt->Field[DIAM].Units, u_MMETERS);
|
strcpy(rpt->Field[DIAM].Units, u_MMETERS);
|
||||||
strcpy(rpt->Field[FLOW].Units, RptFlowUnitsTxt[parser->Flowflag]);
|
strcpy(rpt->Field[FLOW].Units, RptFlowUnitsTxt[parser->Flowflag]);
|
||||||
@@ -423,8 +424,6 @@ void initunits(Project *pr)
|
|||||||
if (parser->Flowflag == CMS) qcf = CMSperCFS;
|
if (parser->Flowflag == CMS) qcf = CMSperCFS;
|
||||||
|
|
||||||
hcf = MperFT;
|
hcf = MperFT;
|
||||||
if (parser->Pressflag == METERS) pcf = MperFT * hyd->SpGrav;
|
|
||||||
else pcf = KPAperPSI * PSIperFT * hyd->SpGrav;
|
|
||||||
wcf = KWperHP;
|
wcf = KWperHP;
|
||||||
}
|
}
|
||||||
else // US units
|
else // US units
|
||||||
@@ -448,10 +447,17 @@ void initunits(Project *pr)
|
|||||||
if (parser->Flowflag == IMGD) qcf = IMGDperCFS;
|
if (parser->Flowflag == IMGD) qcf = IMGDperCFS;
|
||||||
if (parser->Flowflag == AFD) qcf = AFDperCFS;
|
if (parser->Flowflag == AFD) qcf = AFDperCFS;
|
||||||
hcf = 1.0;
|
hcf = 1.0;
|
||||||
pcf = PSIperFT * hyd->SpGrav;
|
|
||||||
wcf = 1.0;
|
wcf = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (parser->Pressflag == METERS) strcpy(rpt->Field[PRESSURE].Units, u_METERS);
|
||||||
|
else if (parser->Pressflag == KPA) strcpy(rpt->Field[PRESSURE].Units, u_KPA);
|
||||||
|
else strcpy(rpt->Field[PRESSURE].Units, u_PSI);
|
||||||
|
|
||||||
|
if (parser->Pressflag == METERS) pcf = MperFT * hyd->SpGrav;
|
||||||
|
else if (parser->Pressflag == KPA) pcf = KPAperPSI * PSIperFT * hyd->SpGrav;
|
||||||
|
else pcf = PSIperFT * hyd->SpGrav;
|
||||||
|
|
||||||
strcpy(rpt->Field[QUALITY].Units, "");
|
strcpy(rpt->Field[QUALITY].Units, "");
|
||||||
ccf = 1.0;
|
ccf = 1.0;
|
||||||
if (qual->Qualflag == CHEM)
|
if (qual->Qualflag == CHEM)
|
||||||
|
|||||||
@@ -238,7 +238,8 @@ typedef enum {
|
|||||||
typedef enum {
|
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)
|
||||||
} PressureUnitsType;
|
} PressureUnitsType;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|||||||
@@ -74,13 +74,13 @@ BOOST_FIXTURE_TEST_CASE(test_pressure_units, FixtureInitClose)
|
|||||||
BOOST_REQUIRE(error == 0);
|
BOOST_REQUIRE(error == 0);
|
||||||
BOOST_CHECK(units == EN_PSI);
|
BOOST_CHECK(units == EN_PSI);
|
||||||
|
|
||||||
// Change to pressure from PSI to meters and check it's still PSI
|
// Change to pressure from PSI to meters and check it is meters
|
||||||
error = EN_setoption(ph, EN_PRESS_UNITS, EN_METERS);
|
error = EN_setoption(ph, EN_PRESS_UNITS, EN_METERS);
|
||||||
BOOST_REQUIRE(error == 0);
|
BOOST_REQUIRE(error == 0);
|
||||||
|
|
||||||
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_PSI);
|
BOOST_CHECK(units == EN_METERS);
|
||||||
|
|
||||||
// Change flow units to LPS to change to metric units and rerun simulation
|
// Change flow units to LPS to change to metric units and rerun simulation
|
||||||
error = EN_setflowunits(ph, EN_LPS);
|
error = EN_setflowunits(ph, EN_LPS);
|
||||||
@@ -108,12 +108,12 @@ BOOST_FIXTURE_TEST_CASE(test_pressure_units, FixtureInitClose)
|
|||||||
BOOST_REQUIRE(error == 0);
|
BOOST_REQUIRE(error == 0);
|
||||||
BOOST_CHECK(abs(p - 298.76035) < 1.e-5);
|
BOOST_CHECK(abs(p - 298.76035) < 1.e-5);
|
||||||
|
|
||||||
// Set pressure to PSI and check that it remains in kPa
|
// Set pressure to PSI and check that it has changed to PSI
|
||||||
error = EN_setoption(ph, EN_PRESS_UNITS, EN_PSI);
|
error = EN_setoption(ph, EN_PRESS_UNITS, EN_PSI);
|
||||||
BOOST_REQUIRE(error == 0);
|
BOOST_REQUIRE(error == 0);
|
||||||
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_PSI);
|
||||||
|
|
||||||
error = EN_closeH(ph);
|
error = EN_closeH(ph);
|
||||||
BOOST_REQUIRE(error == 0);
|
BOOST_REQUIRE(error == 0);
|
||||||
@@ -264,4 +264,197 @@ BOOST_FIXTURE_TEST_CASE(test_rule_unit_change, FixtureOpenClose)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(test_decoupled_pressure_units, FixtureInitClose)
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
long t;
|
||||||
|
double p, units;
|
||||||
|
|
||||||
|
// Create basic network
|
||||||
|
error = EN_addnode(ph, "R1", EN_RESERVOIR, &index);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
error = EN_setnodevalue(ph, index, EN_ELEVATION, 100);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
error = EN_addnode(ph, "J1", EN_JUNCTION, &index);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
error = EN_addlink(ph, "P1", EN_PIPE, "R1", "J1", &index);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
|
||||||
|
// Test 1: Start with US flow units (GPM) and change to PSI
|
||||||
|
error = EN_setflowunits(ph, EN_GPM);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
|
||||||
|
// Should succeed in setting PSI pressure units
|
||||||
|
error = EN_setoption(ph, EN_PRESS_UNITS, EN_PSI);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
|
||||||
|
error = EN_getoption(ph, EN_PRESS_UNITS, &units);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
BOOST_CHECK(units == EN_PSI);
|
||||||
|
|
||||||
|
// Test 2: With US flow units, set pressure to meters (should now work)
|
||||||
|
error = EN_setoption(ph, EN_PRESS_UNITS, EN_METERS);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
|
||||||
|
error = EN_getoption(ph, EN_PRESS_UNITS, &units);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
BOOST_CHECK(units == EN_METERS);
|
||||||
|
|
||||||
|
// Test 3: With US flow units, set pressure to kPa (should now work)
|
||||||
|
error = EN_setoption(ph, EN_PRESS_UNITS, EN_KPA);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
|
||||||
|
error = EN_getoption(ph, EN_PRESS_UNITS, &units);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
BOOST_CHECK(units == EN_KPA);
|
||||||
|
|
||||||
|
// Test 4: Change to SI flow units (LPS) but keep kPa pressure
|
||||||
|
error = EN_setflowunits(ph, EN_LPS);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
|
||||||
|
// Pressure units should remain kPa (not auto-changed to meters)
|
||||||
|
error = EN_getoption(ph, EN_PRESS_UNITS, &units);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
BOOST_CHECK(units == EN_KPA);
|
||||||
|
|
||||||
|
// Test 5: With SI flow units, set pressure to PSI (should now work)
|
||||||
|
error = EN_setoption(ph, EN_PRESS_UNITS, EN_PSI);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
|
||||||
|
error = EN_getoption(ph, EN_PRESS_UNITS, &units);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
BOOST_CHECK(units == EN_PSI);
|
||||||
|
|
||||||
|
// Test 6: Run simulation and check pressure values are correctly converted
|
||||||
|
error = EN_openH(ph);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
error = EN_initH(ph, EN_NOSAVE);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
error = EN_runH(ph, &t);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
|
||||||
|
// Get pressure in PSI (should be ~43.33 PSI for 100 ft head)
|
||||||
|
error = EN_getnodevalue(ph, 1, EN_PRESSURE, &p);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
BOOST_CHECK(abs(p - 43.33) < 1.e-5);
|
||||||
|
|
||||||
|
// Change pressure units to meters during simulation
|
||||||
|
error = EN_setoption(ph, EN_PRESS_UNITS, EN_METERS);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
|
||||||
|
// Pressure should now be in meters (~30.48 m for 100 ft head)
|
||||||
|
error = EN_getnodevalue(ph, 1, EN_PRESSURE, &p);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
BOOST_CHECK(abs(p - 30.48) < 1.e-5);
|
||||||
|
|
||||||
|
error = EN_closeH(ph);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(test_automatic_pressure_unit_switching, FixtureInitClose)
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
double pressure_units;
|
||||||
|
|
||||||
|
// Create basic network
|
||||||
|
error = EN_addnode(ph, "R1", EN_RESERVOIR, &index);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
error = EN_setnodevalue(ph, index, EN_ELEVATION, 100);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
error = EN_addnode(ph, "J1", EN_JUNCTION, &index);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
error = EN_addlink(ph, "P1", EN_PIPE, "R1", "J1", &index);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
|
||||||
|
// Test 1: Start with US flow units (CFS) - should have PSI pressure units
|
||||||
|
error = EN_setflowunits(ph, EN_CFS);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
error = EN_getoption(ph, EN_PRESS_UNITS, &pressure_units);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
BOOST_CHECK(pressure_units == EN_PSI);
|
||||||
|
|
||||||
|
// Test 2: Change from US flow units (CFS) to metric flow units (LPS)
|
||||||
|
// Pressure units should automatically change from PSI to METERS
|
||||||
|
error = EN_setflowunits(ph, EN_LPS);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
error = EN_getoption(ph, EN_PRESS_UNITS, &pressure_units);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
BOOST_CHECK(pressure_units == EN_METERS);
|
||||||
|
|
||||||
|
// Test 3: Change from metric flow units (LPS) back to US flow units (GPM)
|
||||||
|
// Pressure units should automatically change from METERS to PSI
|
||||||
|
error = EN_setflowunits(ph, EN_GPM);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
error = EN_getoption(ph, EN_PRESS_UNITS, &pressure_units);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
BOOST_CHECK(pressure_units == EN_PSI);
|
||||||
|
|
||||||
|
// Test 4: Change from US flow units (GPM) to another metric flow unit (MLD)
|
||||||
|
// Pressure units should automatically change from PSI to METERS
|
||||||
|
error = EN_setflowunits(ph, EN_MLD);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
error = EN_getoption(ph, EN_PRESS_UNITS, &pressure_units);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
BOOST_CHECK(pressure_units == EN_METERS);
|
||||||
|
|
||||||
|
// Test 5: Manually set pressure units to kPa while using metric flow units
|
||||||
|
error = EN_setoption(ph, EN_PRESS_UNITS, EN_KPA);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
error = EN_getoption(ph, EN_PRESS_UNITS, &pressure_units);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
BOOST_CHECK(pressure_units == EN_KPA);
|
||||||
|
|
||||||
|
// Test 6: Change from metric flow units (MLD) to US flow units (MGD)
|
||||||
|
// Pressure units should automatically change from kPa to PSI
|
||||||
|
error = EN_setflowunits(ph, EN_MGD);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
error = EN_getoption(ph, EN_PRESS_UNITS, &pressure_units);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
BOOST_CHECK(pressure_units == EN_PSI);
|
||||||
|
|
||||||
|
// Test 7: Change from US flow units (MGD) to metric flow units (CMH)
|
||||||
|
// Pressure units should automatically change from PSI to METERS
|
||||||
|
error = EN_setflowunits(ph, EN_CMH);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
error = EN_getoption(ph, EN_PRESS_UNITS, &pressure_units);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
BOOST_CHECK(pressure_units == EN_METERS);
|
||||||
|
|
||||||
|
// Test 8: Set pressure to kPa again with metric flow units
|
||||||
|
error = EN_setoption(ph, EN_PRESS_UNITS, EN_KPA);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
|
||||||
|
// Test 9: Change between metric flow units (CMH to CMD)
|
||||||
|
// Pressure units should remain kPa (not changed to METERS since not switching from PSI)
|
||||||
|
error = EN_setflowunits(ph, EN_CMD);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
error = EN_getoption(ph, EN_PRESS_UNITS, &pressure_units);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
BOOST_CHECK(pressure_units == EN_KPA);
|
||||||
|
|
||||||
|
// Test 10: Change from metric flow units (CMD) to US flow units (AFD)
|
||||||
|
// Pressure units should automatically change from kPa to PSI
|
||||||
|
error = EN_setflowunits(ph, EN_AFD);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
error = EN_getoption(ph, EN_PRESS_UNITS, &pressure_units);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
BOOST_CHECK(pressure_units == EN_PSI);
|
||||||
|
|
||||||
|
// Test 11: Change between US flow units (AFD to IMGD)
|
||||||
|
// Pressure units should remain PSI
|
||||||
|
error = EN_setflowunits(ph, EN_IMGD);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
error = EN_getoption(ph, EN_PRESS_UNITS, &pressure_units);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
BOOST_CHECK(pressure_units == EN_PSI);
|
||||||
|
|
||||||
|
// Test 12: Final test - metric flow units (CMS) should change PSI to METERS
|
||||||
|
error = EN_setflowunits(ph, EN_CMS);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
error = EN_getoption(ph, EN_PRESS_UNITS, &pressure_units);
|
||||||
|
BOOST_REQUIRE(error == 0);
|
||||||
|
BOOST_CHECK(pressure_units == EN_METERS);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|||||||
Reference in New Issue
Block a user