Merge pull request #719 from lbutler/add-pressure-unit-selection

Get and set pressure units in toolkit
This commit is contained in:
Lew Rossman
2023-04-01 11:10:49 -04:00
committed by GitHub
14 changed files with 467 additions and 9 deletions

View File

@@ -279,6 +279,7 @@ __Formats:__
<table style = "border: 0px solid black"> <table style = "border: 0px solid black">
<tr><td><B>UNITS</B></td><td><B>CFS / GPM / MGD / IMGD / AFD /</B></td></tr> <tr><td><B>UNITS</B></td><td><B>CFS / GPM / MGD / IMGD / AFD /</B></td></tr>
<tr><td> </td><td><B>LPS / LPM / MLD / CMS / CMH / CMD</B></td></tr> <tr><td> </td><td><B>LPS / LPM / MLD / CMS / CMH / CMD</B></td></tr>
<tr><td><B>PRESSURE</B></td><td><B>PSI / KPA / METERS</B></td></tr>
<tr><td><B>HEADLOSS</B></td><td><B>H-W / D-W / C-M</B></td></tr> <tr><td><B>HEADLOSS</B></td><td><B>H-W / D-W / C-M</B></td></tr>
<tr><td><B>HYDRAULICS</B></td><td><B>USE / SAVE </B><I>&nbsp;filename</I></td></tr> <tr><td><B>HYDRAULICS</B></td><td><B>USE / SAVE </B><I>&nbsp;filename</I></td></tr>
<tr><td><B>VISCOSITY</B></td><td><I>value</I></td></tr> <tr><td><B>VISCOSITY</B></td><td><I>value</I></td></tr>
@@ -321,6 +322,8 @@ __Definitions:__
For <b>CFS, GPM, MGD, IMGD</b>, and <b>AFD</b> other input quantities are expressed in US Customary Units. If flow units are in liters or cubic meters then Metric Units must be used for all other input quantities as well. (See the @ref Units topic). The default flow units are \b GPM. For <b>CFS, GPM, MGD, IMGD</b>, and <b>AFD</b> other input quantities are expressed in US Customary Units. If flow units are in liters or cubic meters then Metric Units must be used for all other input quantities as well. (See the @ref Units topic). The default flow units are \b GPM.
\b PRESSURE sets the units in which pressure is expressed, for networks using metric units, as determined by the \b UNITS option, the choices are: (\b KPA), or (\b METERS). For networks using US Customary Units, you can only use (\b PSI).
\b HEADLOSS selects a formula to use for computing head loss for flow through a pipe. The choices are the Hazen-Williams (\b H-W ), Darcy-Weisbach (\b D-W ), or Chezy-Manning (\b C-M ) formulas. The default is \b H-W. \b HEADLOSS selects a formula to use for computing head loss for flow through a pipe. The choices are the Hazen-Williams (\b H-W ), Darcy-Weisbach (\b D-W ), or Chezy-Manning (\b C-M ) formulas. The default is \b H-W.
The \b HYDRAULICS option allows you to either <B>SAVE</B> the current hydraulics solution to a file or \b USE a previously saved hydraulics solution. This is useful when studying factors that only affect water quality behavior. The \b HYDRAULICS option allows you to either <B>SAVE</B> the current hydraulics solution to a file or \b USE a previously saved hydraulics solution. This is useful when studying factors that only affect water quality behavior.

View File

@@ -289,6 +289,7 @@ These are the toolkit's enumerated types whose members are used as function argu
\enum EN_TimeParameter \enum EN_TimeParameter
\enum EN_Option \enum EN_Option
\enum EN_FlowUnits \enum EN_FlowUnits
\enum EN_PressUnits
\enum EN_DemandModel \enum EN_DemandModel
\enum EN_MixingModel \enum EN_MixingModel
\enum EN_StatisticType \enum EN_StatisticType

View File

@@ -25,7 +25,7 @@ The toolkit can use data expressed in either US Customary of SI Metric units. A
|Length | feet | meters | |Length | feet | meters |
|Minor Loss Coeff. | unitless | unitless | |Minor Loss Coeff. | unitless | unitless |
|Power | horsepower | kwatts | |Power | horsepower | kwatts |
|Pressure | psi | meters | |Pressure | psi | meters or kPa |
|Reaction Coeff. (Bulk) | 1/day (1st-order)| 1/day (1st-order) | |Reaction Coeff. (Bulk) | 1/day (1st-order)| 1/day (1st-order) |
|Reaction Coeff. (Wall) | mass/sq-ft/day (0-order) | mass/sq-m/day (0-order) | |Reaction Coeff. (Wall) | mass/sq-ft/day (0-order) | mass/sq-m/day (0-order) |
| | ft/day (1st-order) | meters/day (1st-order) | | | ft/day (1st-order) | meters/day (1st-order) |

View File

@@ -157,6 +157,10 @@ namespace EpanetCSharpLibrary
public const int EN_CMD = 9; public const int EN_CMD = 9;
public const int EN_CMS = 10; public const int EN_CMS = 10;
public const int EN_PSI = 0; //Pressure units types
public const int EN_KPA = 1;
public const int EN_METERS = 2;
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
@@ -185,6 +189,7 @@ namespace EpanetCSharpLibrary
public const int EN_CONCENLIMIT = 22; public const int EN_CONCENLIMIT = 22;
public const int EN_DEMANDPATTERN = 23; public const int EN_DEMANDPATTERN = 23;
public const int EN_EMITBACKFLOW = 24; public const int EN_EMITBACKFLOW = 24;
public const int EN_PRESS_UNITS = 25;
public const int EN_LOWLEVEL = 0; //Control types public const int EN_LOWLEVEL = 0; //Control types
public const int EN_HILEVEL = 1; public const int EN_HILEVEL = 1;

View File

@@ -154,6 +154,10 @@ Public Const EN_CMH = 8
Public Const EN_CMD = 9 Public Const EN_CMD = 9
Public Const EN_CMS = 10 Public Const EN_CMS = 10
Public Const EN_PSI = 0 ' Pressure units types
Public Const EN_KPA = 1
Public Const EN_METERS = 2
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
@@ -182,6 +186,7 @@ Public Const EN_TANKORDER = 21
Public Const EN_CONCENLIMIT = 22 Public Const EN_CONCENLIMIT = 22
Public Const EN_DEMANDPATTERN = 23 Public Const EN_DEMANDPATTERN = 23
Public Const EN_EMITBACKFLOW = 24 Public Const EN_EMITBACKFLOW = 24
Public Const EN_PRESS_UNITS = 25
Public Const EN_LOWLEVEL = 0 ' Control types Public Const EN_LOWLEVEL = 0 ' Control types
Public Const EN_HILEVEL = 1 Public Const EN_HILEVEL = 1

View File

@@ -149,6 +149,10 @@ Public Const EN_CMH = 8
Public Const EN_CMD = 9 Public Const EN_CMD = 9
Public Const EN_CMS = 10 Public Const EN_CMS = 10
Public Const EN_PSI = 0 ' Pressure units types
Public Const EN_KPA = 1
Public Const EN_METERS = 2
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
@@ -177,6 +181,7 @@ Public Const EN_TANKORDER = 21
Public Const EN_CONCENLIMIT = 22 Public Const EN_CONCENLIMIT = 22
Public Const EN_DEMANDPATTERN = 23 Public Const EN_DEMANDPATTERN = 23
Public Const EN_EMITBACKFLOW = 24 Public Const EN_EMITBACKFLOW = 24
Public Const EN_PRESS_UNITS = 25
Public Const EN_LOWLEVEL = 0 ' Control types Public Const EN_LOWLEVEL = 0 ' Control types
Public Const EN_HILEVEL = 1 Public Const EN_HILEVEL = 1

View File

@@ -291,6 +291,19 @@ typedef enum {
EN_CMS = 10 //!< Cubic meters per second EN_CMS = 10 //!< Cubic meters per second
} EN_FlowUnits; } EN_FlowUnits;
/// Pressure units
/**
The available choices for pressure units for the \b EN_PRESS_UNITS option in @ref EN_getoption
and @ref EN_setoption. For networks using US Customary units for flow ( \b EN_CFS through
\b EN_AFD ) pressure units can only be set as PSI. For network using metric units, you can
select either \b EN_METERS or \b EN_KPA.
*/
typedef enum {
EN_PSI = 0, //!< Pounds per square inch
EN_KPA = 1, //!< Kilopascals
EN_METERS = 2 //!< Meters
} EN_PressUnits;
/// Demand models /// Demand models
/** /**
These choices for modeling consumer demands are used with @ref EN_getdemandmodel These choices for modeling consumer demands are used with @ref EN_getdemandmodel
@@ -337,7 +350,8 @@ typedef enum {
EN_TANKORDER = 21, //!< Bulk water reaction order for tanks EN_TANKORDER = 21, //!< Bulk water reaction order for tanks
EN_CONCENLIMIT = 22, //!< Limiting concentration for growth reactions EN_CONCENLIMIT = 22, //!< Limiting concentration for growth reactions
EN_DEMANDPATTERN = 23, //!< Name of default demand pattern EN_DEMANDPATTERN = 23, //!< Name of default demand pattern
EN_EMITBACKFLOW = 24 //!< 1 if emitters can backflow, 0 if not EN_EMITBACKFLOW = 24, //!< 1 if emitters can backflow, 0 if not
EN_PRESS_UNITS = 25 //!< Pressure units (see @ref EN_PressUnits)
} EN_Option; } EN_Option;
/// Simple control types /// Simple control types

View File

@@ -1208,6 +1208,9 @@ int DLLEXPORT EN_getoption(EN_Project p, int option, double *value)
case EN_EMITBACKFLOW: case EN_EMITBACKFLOW:
v = hyd->EmitBackFlag; v = hyd->EmitBackFlag;
break; break;
case EN_PRESS_UNITS:
v = (double)p->parser.Pressflag;
break;
default: default:
return 251; return 251;
} }
@@ -1231,9 +1234,12 @@ int DLLEXPORT EN_setoption(EN_Project p, int option, double value)
int Njuncs = net->Njuncs; int Njuncs = net->Njuncs;
double *Ucf = p->Ucf; double *Ucf = p->Ucf;
int i, j, pat; int i, j, pat, unit;
double Ke, n, ucf; double Ke, n, ucf;
double qfactor, hfactor, pfactor, dfactor;
double dcf, pcf, hcf, qcf;
if (!p->Openflag) return 102; if (!p->Openflag) return 102;
// The EN_UNBALANCED option can be < 0 indicating that the simulation // The EN_UNBALANCED option can be < 0 indicating that the simulation
@@ -1375,6 +1381,27 @@ int DLLEXPORT EN_setoption(EN_Project p, int option, double value)
else return 213; else return 213;
break; break;
case EN_PRESS_UNITS:
unit = ROUND(value);
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;
dfactor = Ucf[DEMAND];
pfactor = Ucf[PRESSURE];
hfactor = Ucf[HEAD];
qfactor = Ucf[FLOW];
initunits(p);
// Update units in rules
dcf = Ucf[DEMAND] / dfactor;
pcf = Ucf[PRESSURE] / pfactor;
hcf = Ucf[HEAD] / hfactor;
qcf = Ucf[FLOW] / qfactor;
updateruleunits(p, dcf, pcf, hcf, qcf);
break;
default: default:
return 251; return 251;
} }
@@ -1408,7 +1435,8 @@ int DLLEXPORT EN_setflowunits(EN_Project p, int units)
Network *net = &p->network; Network *net = &p->network;
int i, j; int i, j;
double qfactor, vfactor, hfactor, efactor, xfactor, yfactor; double qfactor, vfactor, hfactor, efactor, pfactor, dfactor, xfactor, yfactor;
double dcf, pcf, hcf, qcf;
double *Ucf = p->Ucf; double *Ucf = p->Ucf;
if (!p->Openflag) return 102; if (!p->Openflag) return 102;
@@ -1418,6 +1446,8 @@ int DLLEXPORT EN_setflowunits(EN_Project p, int units)
vfactor = Ucf[VOLUME]; vfactor = Ucf[VOLUME];
hfactor = Ucf[HEAD]; hfactor = Ucf[HEAD];
efactor = Ucf[ELEV]; efactor = Ucf[ELEV];
pfactor = Ucf[PRESSURE];
dfactor = Ucf[DEMAND];
p->parser.Flowflag = units; p->parser.Flowflag = units;
switch (units) switch (units)
@@ -1440,6 +1470,13 @@ int DLLEXPORT EN_setflowunits(EN_Project p, int units)
else if (p->parser.Pressflag == PSI) p->parser.Pressflag = METERS; else if (p->parser.Pressflag == PSI) p->parser.Pressflag = METERS;
initunits(p); initunits(p);
// Update pressure units in rules
dcf = Ucf[DEMAND] / dfactor;
pcf = Ucf[PRESSURE] / pfactor;
hcf = Ucf[HEAD] / hfactor;
qcf = Ucf[FLOW] / qfactor;
updateruleunits(p, dcf, pcf, hcf, qcf);
//update curves //update curves
for (i = 1; i <= net->Ncurves; i++) for (i = 1; i <= net->Ncurves; i++)
{ {

View File

@@ -124,6 +124,7 @@ Spremise *getpremise(Spremise *, int);
Saction *getaction(Saction *, int); Saction *getaction(Saction *, int);
int writerule(Project *, FILE *, int); int writerule(Project *, FILE *, int);
int checkrules(Project *, long); int checkrules(Project *, long);
void updateruleunits(Project *pr, double dcf, double pcf, double hcf, double qcf);
// ------- REPORT.C ----------------- // ------- REPORT.C -----------------

View File

@@ -549,6 +549,126 @@ int checkrules(Project *pr, long dt)
return actionCount; return actionCount;
} }
void updateruleunits(Project *pr, double dcf, double pcf, double hcf, double qcf)
//-----------------------------------------------------------
// Updates the units of a rule's premises and actions.
//-----------------------------------------------------------
{
Network *net = &pr->network;
Slink *Link = net->Link;
int i, k;
double x;
Spremise *p;
Saction *a;
for (i = 1; i <= net->Nrules; i++)
{
p = net->Rule[i].Premises;
while (p != NULL)
{
switch (p->variable)
{
case r_DEMAND:
p->value *= dcf;
break;
case r_HEAD:
case r_GRADE:
p->value *= hcf;
break;
case r_PRESSURE:
p->value *= pcf;
break;
case r_LEVEL:
p->value *= hcf;
break;
case r_FLOW:
p->value *= qcf;
break;
case r_SETTING:
switch (Link[p->index].Type)
{
case PRV:
case PSV:
case PBV:
p->value *= pcf;
break;
case FCV:
p->value *= qcf;
break;
default:
break;
}
break;
default:
break;
}
p = p->next;
}
a = net->Rule[i].ThenActions;
while (a != NULL)
{
k = a->link;
x = a->setting;
// Change link's setting
if (x != MISSING)
{
switch (net->Link[k].Type)
{
case PRV:
case PSV:
case PBV:
a->setting *= pcf;
break;
case FCV:
a->setting *= qcf;
break;
default:
break;
}
}
a = a->next;
}
a = net->Rule[i].ElseActions;
while (a != NULL)
{
k = a->link;
x = a->setting;
// Change link's setting
if (x != MISSING)
{
switch (net->Link[k].Type)
{
case PRV:
case PSV:
case PBV:
a->setting *= pcf;
break;
case FCV:
a->setting *= qcf;
break;
default:
break;
}
}
a = a->next;
}
}
}
void newrule(Project *pr) void newrule(Project *pr)
//---------------------------------------------------------- //----------------------------------------------------------
// Adds a new rule to the project // Adds a new rule to the project

View File

@@ -40,6 +40,7 @@ set(toolkit_test_srcs
test_overflow.cpp test_overflow.cpp
test_pda.cpp test_pda.cpp
test_valve.cpp test_valve.cpp
test_units.cpp
) )
add_executable(test_toolkit ${toolkit_test_srcs}) add_executable(test_toolkit ${toolkit_test_srcs})

View File

@@ -23,11 +23,11 @@ BOOST_FIXTURE_TEST_CASE(test_anlys_getoption, FixtureOpenClose)
{ {
int i; int i;
std::vector<double> test(23); std::vector<double> test(26);
double *array = test.data(); double *array = test.data();
std::vector<double> ref = {40.0, 0.001, 0.01, 0.5, 1.0, 0.0, 0.0, 0.0, 75.0, 0.0, 0.0, 0.0, std::vector<double> ref = {40.0, 0.001, 0.01, 0.5, 1.0, 0.0, 0.0, 0.0, 75.0, 0.0, 0.0, 0.0,
1.0, 1.0, 10.0, 2.0, 10.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0}; 1.0, 1.0, 10.0, 2.0, 10.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0};
error = EN_solveH(ph); error = EN_solveH(ph);
BOOST_REQUIRE(error == 0); BOOST_REQUIRE(error == 0);
@@ -36,7 +36,7 @@ BOOST_FIXTURE_TEST_CASE(test_anlys_getoption, FixtureOpenClose)
BOOST_REQUIRE(error == 0); BOOST_REQUIRE(error == 0);
for (i=EN_TRIALS; i<=EN_CONCENLIMIT; i++) { for (i=EN_TRIALS; i<=EN_PRESS_UNITS; i++) {
error = EN_getoption(ph, i, array++); error = EN_getoption(ph, i, array++);
BOOST_REQUIRE(error == 0); BOOST_REQUIRE(error == 0);
} }
@@ -44,7 +44,7 @@ BOOST_FIXTURE_TEST_CASE(test_anlys_getoption, FixtureOpenClose)
BOOST_CHECK_EQUAL_COLLECTIONS(ref.begin(), ref.end(), test.begin(), test.end()); BOOST_CHECK_EQUAL_COLLECTIONS(ref.begin(), ref.end(), test.begin(), test.end());
double temp; double temp;
error = EN_getoption(ph, 25, &temp); error = EN_getoption(ph, 26, &temp);
BOOST_CHECK(error == 251); BOOST_CHECK(error == 251);
} }

View File

@@ -118,7 +118,6 @@ BOOST_AUTO_TEST_CASE(test_run)
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_SUITE(test_proj_fixture) BOOST_AUTO_TEST_SUITE(test_proj_fixture)
BOOST_FIXTURE_TEST_CASE(test_title, FixtureOpenClose) BOOST_FIXTURE_TEST_CASE(test_title, FixtureOpenClose)

267
tests/test_units.cpp Normal file
View File

@@ -0,0 +1,267 @@
/*
******************************************************************************
Project: OWA EPANET
Version: 2.2
Module: test_units.cpp
Description: Tests EPANET toolkit api functions
Authors: see AUTHORS
Copyright: see AUTHORS
License: see LICENSE
Last Updated: 03/30/2023
******************************************************************************
*/
/*
This is a test for the API functions that change the units of a project.
*/
#include <boost/test/unit_test.hpp>
#include "test_toolkit.hpp"
/*
----------------------------------------------
Flow units conversion factors
----------------------------------------------
*/
double GPMperCFS = 448.831;
double LPSperCFS = 28.317;
double MperFT = 0.3048;
double PSIperFT = 0.4333;
double KPAperPSI = 6.895;
char unitrules[] = "RULE 1\n IF NODE 10 DEMAND > 10 \n"
"AND NODE 10 HEAD > 20 \n"
"AND NODE 10 PRESSURE > 30 \n"
"AND NODE 10 LEVEL > 40 \n"
"AND LINK 10 FLOW > 50 \n"
"AND LINK PRV1 SETTING > 60 \n"
"AND LINK FCV1 SETTING > 70 \n"
"THEN LINK PRV1 SETTING = 80\n ELSE LINK FCV1 SETTING = 90";
BOOST_AUTO_TEST_SUITE (test_units)
BOOST_FIXTURE_TEST_CASE(test_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);
// Run simulation and get junction pressure
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);
error = EN_getnodevalue(ph, 1, EN_PRESSURE, &p);
BOOST_REQUIRE(error == 0);
BOOST_CHECK(abs(p - 43.33) < 1.e-5);
// Get pressure unit and check that it is PSI
error = EN_getoption(ph, EN_PRESS_UNITS, &units);
BOOST_REQUIRE(error == 0);
BOOST_CHECK(units == EN_PSI);
// Change to pressure from PSI to meters and check it's still PSI
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_PSI);
// Change flow units to LPS to change to metric units and rerun simulation
error = EN_setflowunits(ph, EN_LPS);
BOOST_REQUIRE(error == 0);
error = EN_initH(ph, EN_NOSAVE);
BOOST_REQUIRE(error == 0);
error = EN_runH(ph, &t);
BOOST_REQUIRE(error == 0);
// Confirm that pressure is now in meters
error = EN_getnodevalue(ph, 1, EN_PRESSURE, &p);
BOOST_REQUIRE(error == 0);
BOOST_CHECK(abs(p - 30.48) < 1.e-5);
error = EN_getoption(ph, EN_PRESS_UNITS, &units);
BOOST_REQUIRE(error == 0);
BOOST_CHECK(units == EN_METERS);
// Set and check that pressure units are in kPa
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);
error = EN_getnodevalue(ph, 1, EN_PRESSURE, &p);
BOOST_REQUIRE(error == 0);
BOOST_CHECK(abs(p - 298.76035) < 1.e-5);
// Set pressure to PSI and check that it remains in kPa
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_KPA);
error = EN_closeH(ph);
BOOST_REQUIRE(error == 0);
}
BOOST_FIXTURE_TEST_CASE(test_pda_unit_change, FixtureOpenClose)
{
int type;
double pmin, preq, pexp;
// Switch to PDA with pressure limits of 20 - 100 psi
error = EN_setdemandmodel(ph, EN_PDA, 20, 100, 0.5);
BOOST_REQUIRE(error == 0);
error = EN_setflowunits(ph, EN_LPS);
BOOST_REQUIRE(error == 0);
error = EN_getdemandmodel(ph, &type, &pmin, &preq, &pexp);
BOOST_REQUIRE(error == 0);
BOOST_CHECK(abs(pmin - (20/PSIperFT*MperFT)) < 1.e-5);
BOOST_CHECK(abs(preq - (100/PSIperFT*MperFT)) < 1.e-5);
}
BOOST_FIXTURE_TEST_CASE(test_rule_unit_change, FixtureOpenClose)
{
int index, node22, link12;
double units;
// Rule variables
int r_logop, r_object, r_objIndex, r_variable, r_relop, r_status;
double r_value;
// Control variables
int c_index, c_type, c_linkIndex, c_nodeIndex;
double c_setting, c_level;
// Add new PRV and FCV to test rules
error = EN_addlink(ph, (char *)"PRV1", EN_PRV, (char *)"10", (char *)"11", &index);
BOOST_REQUIRE(error == 0);
error = EN_addlink(ph, (char *)"FCV1", EN_FCV, (char *)"12", (char *)"13", &index);
BOOST_REQUIRE(error == 0);
// Add the rule to the project
error = EN_addrule(ph, unitrules);
BOOST_REQUIRE(error == 0);
// Add control that checks junction pressure
EN_getnodeindex(ph, (char *)"22", &node22);
EN_getlinkindex(ph, (char *)"12", &link12);
error = EN_addcontrol(ph, EN_HILEVEL, link12, 0, node22, 250, &c_index);
BOOST_REQUIRE(error == 0);
// Check that rules and controls are in US units
error = EN_getpremise(ph, 1, 3, &r_logop, &r_object, &r_objIndex, &r_variable, &r_relop, &r_status, &r_value);
BOOST_REQUIRE(error == 0);
BOOST_CHECK(r_value == 30);
error = EN_getcontrol(ph, c_index, &c_type, &c_linkIndex, &c_setting, &c_nodeIndex, &c_level);
BOOST_REQUIRE(error == 0);
BOOST_CHECK(c_level == 250);
// Change flow units to lps and pressure to meters
error = EN_setflowunits(ph, EN_LPS);
BOOST_REQUIRE(error == 0);
error = EN_getoption(ph, EN_PRESS_UNITS, &units);
BOOST_REQUIRE(error == 0);
BOOST_CHECK(units == EN_METERS);
// Check that rules and controls are in meters
// Simple Control - 250 psi to meters
error = EN_getcontrol(ph, c_index, &c_type, &c_linkIndex, &c_setting, &c_nodeIndex, &c_level);
BOOST_REQUIRE(error == 0);
BOOST_CHECK(abs(c_level - (250/PSIperFT*MperFT)) < 1.e-5); // 250 PSI to M
// Premise 1 - Demand GPM to LPS
error = EN_getpremise(ph, 1, 1, &r_logop, &r_object, &r_objIndex, &r_variable, &r_relop, &r_status, &r_value);
BOOST_REQUIRE(error == 0);
BOOST_CHECK(abs(r_value - (10/GPMperCFS*LPSperCFS)) < 1.e-5); //10 GPM to LPS
// Premise 2 - Head FT to Meters
error = EN_getpremise(ph, 1, 2, &r_logop, &r_object, &r_objIndex, &r_variable, &r_relop, &r_status, &r_value);
BOOST_REQUIRE(error == 0);
BOOST_CHECK(abs(r_value - (20*MperFT)) < 1.e-5); //20 FT to M
// Premise 3 - Pressure PSI to Meters
error = EN_getpremise(ph, 1, 3, &r_logop, &r_object, &r_objIndex, &r_variable, &r_relop, &r_status, &r_value);
BOOST_REQUIRE(error == 0);
BOOST_CHECK(abs(r_value - (30/PSIperFT*MperFT)) < 1.e-5); //30 PSI to M
// Premise 4 - Level FT to Meters
error = EN_getpremise(ph, 1, 4, &r_logop, &r_object, &r_objIndex, &r_variable, &r_relop, &r_status, &r_value);
BOOST_REQUIRE(error == 0);
BOOST_CHECK(abs(r_value - (40*MperFT)) < 1.e-5); //40 FT to M
// Premise 5 - Flow GPM to LPS
error = EN_getpremise(ph, 1, 5, &r_logop, &r_object, &r_objIndex, &r_variable, &r_relop, &r_status, &r_value);
BOOST_REQUIRE(error == 0);
BOOST_CHECK(abs(r_value - (50/GPMperCFS*LPSperCFS)) < 1.e-5); //50 GPM to LPS
// Premise 6 - Setting PSI to Meters
error = EN_getpremise(ph, 1, 6, &r_logop, &r_object, &r_objIndex, &r_variable, &r_relop, &r_status, &r_value);
BOOST_REQUIRE(error == 0);
BOOST_CHECK(abs(r_value - (60/PSIperFT*MperFT)) < 1.e-5); //60 PSI to M
// Premise 7 - Setting GPM to LPS
error = EN_getpremise(ph, 1, 7, &r_logop, &r_object, &r_objIndex, &r_variable, &r_relop, &r_status, &r_value);
BOOST_REQUIRE(error == 0);
BOOST_CHECK(abs(r_value - (70/GPMperCFS*LPSperCFS)) < 1.e-5); //70 GPM to LPS
// ThenAction - Setting PSI to Meters
error = EN_getthenaction(ph, 1, 1, &r_objIndex, &r_status, &r_value);
BOOST_REQUIRE(error == 0);
BOOST_CHECK(abs(r_value - (80/PSIperFT*MperFT)) < 1.e-5); //80 PSI to M
// ElseAction - Setting GPM to LPS
error = EN_getelseaction(ph, 1, 1, &r_objIndex, &r_status, &r_value);
BOOST_REQUIRE(error == 0);
BOOST_CHECK(abs(r_value - (90/GPMperCFS*LPSperCFS)) < 1.e-5); //90 GPM to LPS
// Change pressure units to kPa
error = EN_setoption(ph, EN_PRESS_UNITS, EN_KPA);
BOOST_REQUIRE(error == 0);
// Simple Control - 250 psi to kPa
error = EN_getcontrol(ph, c_index, &c_type, &c_linkIndex, &c_setting, &c_nodeIndex, &c_level);
BOOST_REQUIRE(error == 0);
BOOST_CHECK(abs(c_level - (250*KPAperPSI)) < 1.e-5); //250 PSI to kPa
// Premise 3 - Pressure PSI to kPa
error = EN_getpremise(ph, 1, 3, &r_logop, &r_object, &r_objIndex, &r_variable, &r_relop, &r_status, &r_value);
BOOST_REQUIRE(error == 0);
BOOST_CHECK(abs(r_value - (30*KPAperPSI)) < 1.e-5); //30 PSI to kPa
// Premise 6 - Setting PSI to kPa
error = EN_getpremise(ph, 1, 6, &r_logop, &r_object, &r_objIndex, &r_variable, &r_relop, &r_status, &r_value);
BOOST_REQUIRE(error == 0);
BOOST_CHECK(abs(r_value - (60*KPAperPSI)) < 1.e-5); //60 PSI to kPa
// ThenAction - Setting PSI to kPa
error = EN_getthenaction(ph, 1, 1, &r_objIndex, &r_status, &r_value);
BOOST_REQUIRE(error == 0);
BOOST_CHECK(abs(r_value - (80*KPAperPSI)) < 1.e-5); //80 PSI to kPa
}
BOOST_AUTO_TEST_SUITE_END()