From 1d8d2fb882212e6a885c1d8ab29896e476749cc9 Mon Sep 17 00:00:00 2001 From: sam hatchett Date: Thu, 17 Dec 2015 13:22:28 -0500 Subject: [PATCH] combining testing framework with python diff script --- build/CMake/CMakeLists.txt | 2 +- tests/network_tests/net1/net1.enb | Bin 0 -> 16832 bytes tests/network_tests/net1/net1.inp | 178 ++++++++++++++++++++++++++++ tests/test_networks.sh | 9 +- tools/outputapi/ENBinaryOutDiff.py | 1 + tools/outputapi/ENOutputWrapper.py | 2 +- tools/outputapi/OutDiff.py | 1 - tools/outputapi/_ENOutputToolkit.py | 1 - 8 files changed, 188 insertions(+), 6 deletions(-) create mode 100644 tools/outputapi/ENBinaryOutDiff.py delete mode 100644 tools/outputapi/OutDiff.py delete mode 100644 tools/outputapi/_ENOutputToolkit.py diff --git a/build/CMake/CMakeLists.txt b/build/CMake/CMakeLists.txt index caa4fa2..54fbc32 100644 --- a/build/CMake/CMakeLists.txt +++ b/build/CMake/CMakeLists.txt @@ -20,4 +20,4 @@ target_link_libraries (runepanet LINK_PUBLIC epanet m) # the binary hydraulics file API include_directories(../../tools/outputapi) -add_library(epanet_bin_out STATIC ../../tools/outputapi/outputapi.c) +add_library(ENBinaryOut SHARED ../../tools/outputapi/outputapi.c) diff --git a/tests/network_tests/net1/net1.enb b/tests/network_tests/net1/net1.enb index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..489729c2193e8aef0ab91915afcd2d3f23088718 100644 GIT binary patch literal 16832 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 F{{?jOU$y`M literal 0 HcmV?d00001 diff --git a/tests/network_tests/net1/net1.inp b/tests/network_tests/net1/net1.inp index e69de29..4df5bbf 100644 --- a/tests/network_tests/net1/net1.inp +++ b/tests/network_tests/net1/net1.inp @@ -0,0 +1,178 @@ +[TITLE] + EPANET Example Network 1 +A simple example of modeling chlorine decay. Both bulk and +wall reactions are included. + +[JUNCTIONS] +;ID Elev Demand Pattern + 10 710 0 ; + 11 710 150 ; + 12 700 150 ; + 13 695 100 ; + 21 700 150 ; + 22 695 200 ; + 23 690 150 ; + 31 700 100 ; + 32 710 100 ; + +[RESERVOIRS] +;ID Head Pattern + 9 800 ; + +[TANKS] +;ID Elevation InitLevel MinLevel MaxLevel Diameter MinVol VolCurve + 2 850 120 100 150 50.5 0 ; + +[PIPES] +;ID Node1 Node2 Length Diameter Roughness MinorLoss Status + 10 10 11 10530 18 100 0 Open ; + 11 11 12 5280 14 100 0 Open ; + 12 12 13 5280 10 100 0 Open ; + 21 21 22 5280 10 100 0 Open ; + 22 22 23 5280 12 100 0 Open ; + 31 31 32 5280 6 100 0 Open ; + 110 2 12 200 18 100 0 Open ; + 111 11 21 5280 10 100 0 Open ; + 112 12 22 5280 12 100 0 Open ; + 113 13 23 5280 8 100 0 Open ; + 121 21 31 5280 8 100 0 Open ; + 122 22 32 5280 6 100 0 Open ; + +[PUMPS] +;ID Node1 Node2 Parameters + 9 9 10 HEAD 1 ; + +[VALVES] +;ID Node1 Node2 Diameter Type Setting MinorLoss + +[TAGS] + +[DEMANDS] +;Junction Demand Pattern Category + +[STATUS] +;ID Status/Setting + +[PATTERNS] +;ID Multipliers +;Demand Pattern + 1 1.0 1.2 1.4 1.6 1.4 1.2 + 1 1.0 0.8 0.6 0.4 0.6 0.8 + +[CURVES] +;ID X-Value Y-Value +;PUMP: Pump Curve for Pump 9 + 1 1500 250 + +[CONTROLS] + LINK 9 OPEN IF NODE 2 BELOW 110 + LINK 9 CLOSED IF NODE 2 ABOVE 140 + + +[RULES] + +[ENERGY] + Global Efficiency 75 + Global Price 0.0 + Demand Charge 0.0 + +[EMITTERS] +;Junction Coefficient + +[QUALITY] +;Node InitQual + 10 0.5 + 11 0.5 + 12 0.5 + 13 0.5 + 21 0.5 + 22 0.5 + 23 0.5 + 31 0.5 + 32 0.5 + 9 1.0 + 2 1.0 + +[SOURCES] +;Node Type Quality Pattern + +[REACTIONS] +;Type Pipe/Tank Coefficient + + +[REACTIONS] + Order Bulk 1 + Order Tank 1 + Order Wall 1 + Global Bulk -.5 + Global Wall -1 + Limiting Potential 0.0 + Roughness Correlation 0.0 + +[MIXING] +;Tank Model + +[TIMES] + Duration 24:00 + Hydraulic Timestep 1:00 + Quality Timestep 0:05 + Pattern Timestep 2:00 + Pattern Start 0:00 + Report Timestep 1:00 + Report Start 0:00 + Start ClockTime 12 am + Statistic None + +[REPORT] + Status Yes + Summary No + Page 0 + +[OPTIONS] + Units GPM + Headloss H-W + Specific Gravity 1.0 + Viscosity 1.0 + Trials 40 + Accuracy 0.001 + CHECKFREQ 2 + MAXCHECK 10 + DAMPLIMIT 0 + Unbalanced Continue 10 + Pattern 1 + Demand Multiplier 1.0 + Emitter Exponent 0.5 + Quality Chlorine mg/L + Diffusivity 1.0 + Tolerance 0.01 + +[COORDINATES] +;Node X-Coord Y-Coord + 10 20.00 70.00 + 11 30.00 70.00 + 12 50.00 70.00 + 13 70.00 70.00 + 21 30.00 40.00 + 22 50.00 40.00 + 23 70.00 40.00 + 31 30.00 10.00 + 32 50.00 10.00 + 9 10.00 70.00 + 2 50.00 90.00 + +[VERTICES] +;Link X-Coord Y-Coord + +[LABELS] +;X-Coord Y-Coord Label & Anchor Node + 6.99 73.63 "Source" + 13.48 68.13 "Pump" + 43.85 91.21 "Tank" + +[BACKDROP] + DIMENSIONS 7.00 6.00 73.00 94.00 + UNITS None + FILE + OFFSET 0.00 0.00 + +[END] diff --git a/tests/test_networks.sh b/tests/test_networks.sh index 3e3d07a..a6527b8 100755 --- a/tests/test_networks.sh +++ b/tests/test_networks.sh @@ -7,14 +7,14 @@ for d in network_tests/*/ ; do officialBinFile=${netfile%.*}.enb candidateBinFile=${netfile%.*}-candidate.enb echo "testing $netfile with known good binary output $officialBinFile" - if true ## path/to/runepanet $netfile ${netfile%.*}-candidate.rpt $candidateBinFile + if ../build/CMake/buildproducts/bin/runepanet $netfile ${netfile%.*}-candidate.rpt $candidateBinFile then echo "epanet run for $netfile SUCCESS" else echo "epanet run for $netfile FAILED" returnValue=1 fi - if python compare_enb.py $officialBinFile $candidateBinFile + if python ENBinaryOutDiff.py $officialBinFile $candidateBinFile then echo "binary output for $netfile PASSED" else @@ -27,4 +27,9 @@ done return $returnValue } +cp ../build/CMake/buildproducts/bin/libENBinaryOut.* ./libENBinaryOut.so +cp ../tools/outputapi/*.py ./ + + + test_networks diff --git a/tools/outputapi/ENBinaryOutDiff.py b/tools/outputapi/ENBinaryOutDiff.py new file mode 100644 index 0000000..0b6e06f --- /dev/null +++ b/tools/outputapi/ENBinaryOutDiff.py @@ -0,0 +1 @@ +''' Compares Two EPANET binary output files. Author: Bryant E. McDonnell Date: 12/16/2015 Compares the absolute value of two values against a given threshold value. ******************* Command Line Arguments: python <*.out 1> <*.out 2> Returns True / False (Pass / Fail, respectively) ******************* ''' import sys import os from math import log from ENOutputWrapper import * def BinCompare(args): # Some Error Checking for Command Line Arguments.... if len(args) < 3: raise Exception("Not Enough Input Arguments: python <*.out 1> <*.out 2>") # if not args[1].endswith('.out') or not args[2].endswith('.out'): # raise Exception("Wrong file extension: python <*.out 1> <*.out 2>") print(sys.argv[1],sys.argv[2]) dllLoc = '' if (sys.platform == 'linux2' or sys.platform == 'darwin'): dllLoc = os.getcwd() + '/libENBinaryOut.so' else: raise Exception("only implemented on mac/linux") BinFile1 = OutputObject(dllLoc) BinFile1.OpenOutputFile(args[1]) BinFile1.get_NetSize() BinFile1.get_Times() BinFile2 = OutputObject(dllLoc) BinFile2.OpenOutputFile(args[2]) ####ENR_NodeAttribute; ##ENR_demand = 0 ##ENR_head = 1 ##ENR_pressure = 2 ##ENR_quality = 3 NumberOfNodeAttr = 4 ####ENR_LinkAttribute; ##ENR_flow = 0 ##ENR_velocity = 1 ##ENR_headloss = 2 ##ENR_avgQuality = 3 ##ENR_status = 4 ##ENR_setting = 5 ##ENR_rxRate = 6 ##ENT_frctnFctr = 7 NumberOfLinkAttr = 8 NumberOfPeriods = BinFile1.numPeriods # Set Tolerances for each attribute # demand, head, pressure, quality NodeAttributeTolerances = [1e-6, 1e-6, 1e-6, 1e-6] # flow, velocity, headloss, avgQuality, status, setting, rxRate, frctnFctr LinkAttributeTolerances = [1e-6, 1e-6, 1e-6, 1e-6, 1e-6, 1e-6, 1e-6, 1e-6] #Compare Node Attributes for nodeAttrInd in range(NumberOfNodeAttr): for TSind in range(NumberOfPeriods): #Get 1 attribute for all nodes at time t NodeAttributeOut1 = BinFile1.get_NodeAttribute(nodeAttrInd, TSind) #Get 1 attribute for all nodes at time t NodeAttributeOut2 = BinFile2.get_NodeAttribute(nodeAttrInd, TSind) for Nodeind, NodeAttrVal in enumerate(NodeAttributeOut1): if abs(NodeAttrVal - NodeAttributeOut2[Nodeind]) > 0: diff = abs(NodeAttrVal - NodeAttributeOut2[Nodeind] ) if diff > NodeAttributeTolerances[nodeAttrInd]: return False #Compare Link Attributes for linkAttrInd in range(NumberOfLinkAttr): for TSind in range(NumberOfPeriods): #Get 1 attribute for all links at time t LinkAttributeOut1 = BinFile1.get_NodeAttribute(linkAttrInd, TSind) #Get 1 attribute for all links at time t LinkAttributeOut2 = BinFile2.get_NodeAttribute(linkAttrInd, TSind) for linkind, LinkAttrVal in enumerate(LinkAttributeOut1): if abs(LinkAttrVal - LinkAttributeOut2[linkind]) > 0: diff = abs(LinkAttrVal - LinkAttributeOut2[linkind] ) if diff > LinkAttributeTolerances[linkAttrInd]: return False return True if __name__ == '__main__': if(BinCompare(sys.argv)): sys.exit(0) else: sys.exit(1) \ No newline at end of file diff --git a/tools/outputapi/ENOutputWrapper.py b/tools/outputapi/ENOutputWrapper.py index a3dcb59..8f934d4 100644 --- a/tools/outputapi/ENOutputWrapper.py +++ b/tools/outputapi/ENOutputWrapper.py @@ -1 +1 @@ -''' Wrapper for EPANET Output API. Author: Bryant E. McDonnell Date: 12/7/2015 Language: Anglais ''' from ctypes import * from _ENOutputToolkit import * #Used just to pull the Pointer of the ENResultsAPI struct class _Opaque(Structure): ''' Used soley for passing the pointer to the enrapi struct to API ''' pass class OutputObject: def __init__(self, dllLoc): ''' Instantiate python Wrapper Object and build Wrapper functions. ''' try: self.DLL = CDLL(dllLoc) except: raise Exception('Failed to Open Linked Library') ###ENResultsAPI* DLLEXPORT ENR_alloc(void); self._enrapiFunc = self.DLL.ENR_alloc self._enrapiFunc.restype = POINTER(_Opaque) ###int DLLEXPORT ENR_open(ENResultsAPI* enrapi, const char* path); self._OpenFunc = self.DLL.ENR_open ###int DLLEXPORT ENR_getNetSize(ENResultsAPI* enrapi, ENR_ElementCount code, int* count); self._GetNetSize = self.DLL.ENR_getNetSize ###int DLLEXPORT ENR_getUnits(ENResultsAPI* enrapi, ENR_Unit code, int* unitFlag); self._GetUnits = self.DLL.ENR_getUnits self._GetUnits.argtypes = [POINTER(_Opaque), c_int, POINTER(c_int)] self._GetUnits.restype = c_int ###int DLLEXPORT ENR_getTimes(ENResultsAPI* enrapi, ENR_Time code, int* time) self._getTimes = self.DLL.ENR_getTimes ###float* ENR_newOutValueSeries(ENResultsAPI* enrapi, int seriesStart, ### int seriesLength, int* length, int* errcode); self._newOutValueSeries = self.DLL.ENR_newOutValueSeries self._newOutValueSeries.argtypes = [POINTER(_Opaque), c_int, c_int, POINTER(c_int), POINTER(c_int)] self._newOutValueSeries.restype = POINTER(c_float) ###float* ENR_newOutValueArray(ENResultsAPI* enrapi, ENR_ApiFunction func, ### ENR_ElementType type, int* length, int* errcode); self._newOutValueArray = self.DLL.ENR_newOutValueArray self._newOutValueArray.argtypes = [POINTER(_Opaque), c_int, c_int, POINTER(c_int), POINTER(c_int)] self._newOutValueArray.restype = POINTER(c_float) ###int DLLEXPORT ENR_getNodeSeries(ENResultsAPI* enrapi, int nodeIndex, ENR_NodeAttribute attr, ### int timeIndex, int length, float* outValueSeries, int* len); self._getNodeSeries = self.DLL.ENR_getNodeSeries ###int DLLEXPORT ENR_getLinkSeries(ENResultsAPI* enrapi, int linkIndex, ENR_LinkAttribute attr, ### int timeIndex, int length, float* outValueSeries); self._getLinkSeries = self.DLL.ENR_getLinkSeries ###int DLLEXPORT ENR_getNodeAttribute(ENResultsAPI* enrapi, int timeIndex, ### ENR_NodeAttribute attr, float* outValueArray); self._getNodeAttribute = self.DLL.ENR_getNodeAttribute ###int DLLEXPORT ENT_getLinkAttribute(ENResultsAPI* enrapi, int timeIndex, ### ENR_LinkAttribute attr, float* outValueArray); self._getLinkAttribute = self.DLL.ENR_getLinkAttribute ###int DLLEXPORT ENR_getNodeResult(ENResultsAPI* enrapi, int timeIndex, int nodeIndex, ### float* outValueArray); self._getNodeResult = self.DLL.ENR_getNodeResult ###int DLLEXPORT ENR_getLinkResult(ENResultsAPI* enrapi, int timeIndex, int linkIndex, ### float* outValueArray); self._getLinkResult = self.DLL.ENR_getLinkResult ###int DLLEXPORT ENR_free(float *array); self._free = self.DLL.ENR_free ###int DLLEXPORT ENR_close(ENResultsAPI* enrapi); self._CloseOut = self.DLL.ENR_close ###int DLLEXPORT ENR_errMessage(int errcode, char* errmsg, int n); self._RetErrMessage = self.DLL.ENR_errMessage def OpenOutputFile(self, binfile): ''' 1) Initializes the opaque pointer to enrapi struct. 2) Opens the output file. ''' self.enrapi = self._enrapiFunc() ret = self._OpenFunc(self.enrapi, binfile) if ret != 0: self.CloseOutputFile(self.enrapi) raise Exception('Failed to open OutputFile') ##Update Function at a later date ## def RaiseError(self, ErrNo): ## ErMsg = c_char_p(256) ## ## self._RetErrMessage(ErrNo , ErMsg, 256) ## ## print ErMsg def get_Units(self): ''' Purpose: Returns pressure and flow units ''' unit = c_int() self._GetUnits(self.enrapi, ENR_flowUnits, unit) self.flowUnits = unit.value unit = c_int() self._GetUnits(self.enrapi, ENR_pressUnits, unit) self.pressUnits = unit.value def get_NetSize(self): ''' Populates object attributes with the water object counts ''' count = c_int() self._GetNetSize(self.enrapi, ENR_nodeCount, byref(count)) self.nodeCount = count.value count = c_int() self._GetNetSize(self.enrapi, ENR_tankCount, byref(count)) self.tankCount = count.value count = c_int() self._GetNetSize(self.enrapi, ENR_linkCount, byref(count)) self.linkCount = count.value count = c_int() self._GetNetSize(self.enrapi, ENR_pumpCount, byref(count)) self.pumpCount = count.value count = c_int() self._GetNetSize(self.enrapi, ENR_valveCount, byref(count)) self.valveCount = count.value def get_Times(self): ''' Purpose: Returns report and simulation time related parameters. ''' temp = c_int() self._getTimes(self.enrapi, ENR_reportStart, byref(temp)) self.reportStart = temp.value temp = c_int() self._getTimes(self.enrapi, ENR_reportStep, byref(temp)) self.reportStep = temp.value temp = c_int() self._getTimes(self.enrapi, ENR_simDuration, byref(temp)) self.simDuration = temp.value temp = c_int() self._getTimes(self.enrapi, ENR_numPeriods, byref(temp)) self.numPeriods = temp.value def get_NodeSeries(self, NodeInd, NodeAttr, SeriesStartInd = 0, SeriesLen = -1): ''' Purpose: Get time series results for particular attribute. Specify series start and length using seriesStart and seriesLength respectively. SeriesLen = -1 Default input: Gets data from Series Start Ind to end ''' if not hasattr(self, 'numPeriods'): self.get_Times() if SeriesLen > self.numPeriods : raise Exception("Outside Number of TimeSteps") elif SeriesLen == -1: SeriesLen = self.numPeriods sLength = c_int() ErrNo1 = c_int() SeriesPtr = self._newOutValueSeries(self.enrapi, SeriesStartInd,\ SeriesLen, byref(sLength), byref(ErrNo1)) ErrNo2 = self._getNodeSeries(self.enrapi, NodeInd, NodeAttr, \ SeriesStartInd, sLength.value, SeriesPtr) BldArray = [SeriesPtr[i] for i in range(sLength.value)] self._free(SeriesPtr) return BldArray def get_LinkSeries(self, LinkInd, LinkAttr, SeriesStartInd = 0, SeriesLen = -1): ''' Purpose: Get time series results for particular attribute. Specify series start and length using seriesStart and seriesLength respectively. SeriesLen = -1 Default input: Gets data from Series Start Ind to end ''' if not hasattr(self, 'numPeriods'): self.get_Times() if SeriesLen > self.numPeriods : raise Exception("Outside Number of TimeSteps") elif SeriesLen == -1: SeriesLen = self.numPeriods sLength = c_int() ErrNo1 = c_int() SeriesPtr = self._newOutValueSeries(self.enrapi, SeriesStartInd,\ SeriesLen, byref(sLength), byref(ErrNo1)) ErrNo2 = self._getLinkSeries(self.enrapi, LinkInd, LinkAttr, \ SeriesStartInd, sLength.value, SeriesPtr) BldArray = [SeriesPtr[i] for i in range(sLength.value)] ret = self._free(SeriesPtr) return BldArray def get_NodeAttribute(self, NodeAttr, TimeInd): ''' Purpose: For all nodes at given time, get a particular attribute ''' if not hasattr(self, 'nodeCount'): self.get_NetSize() alength = c_int() ErrNo1 = c_int() ValArrayPtr = self._newOutValueArray(self.enrapi, ENR_getAttribute,\ ENR_node, byref(alength), byref(ErrNo1)) ErrNo2 = self._getNodeAttribute(self.enrapi, TimeInd, NodeAttr, ValArrayPtr) BldArray = [ValArrayPtr[i] for i in range(alength.value)] self._free(ValArrayPtr) return BldArray def get_LinkAttribute(self, LinkAttr, TimeInd): ''' Purpose: For all links at given time, get a particular attribute ''' if not hasattr(self, 'linkCount'): self.get_NetSize() alength = c_int() ErrNo1 = c_int() ValArrayPtr = self._newOutValueArray(self.enrapi, ENR_getAttribute,\ ENR_link, byref(alength), byref(ErrNo1)) ErrNo2 = self._getLinkAttribute(self.enrapi, TimeInd, LinkAttr, ValArrayPtr) BldArray = [ValArrayPtr[i] for i in range(alength.value)] self._free(ValArrayPtr) return BldArray def get_NodeResult(self, NodeInd, TimeInd): ''' Purpose: For a node at given time, get all attributes ''' alength = c_int() ErrNo1 = c_int() ValArrayPtr = self._newOutValueArray(self.enrapi, ENR_getResult,\ ENR_node, byref(alength), byref(ErrNo1)) ErrNo2 = self._getNodeResult(self.enrapi, TimeInd, NodeInd, ValArrayPtr) BldArray = [ValArrayPtr[i] for i in range(alength.value)] self._free(ValArrayPtr) return BldArray def get_LinkResult(self, LinkInd, TimeInd): ''' Purpose: For a link at given time, get all attributes ''' alength = c_int() ErrNo1 = c_int() ValArrayPtr = self._newOutValueArray(self.enrapi, ENR_getResult,\ ENR_link, byref(alength), byref(ErrNo1)) ErrNo2 = self._getLinkResult(self.enrapi, TimeInd, LinkInd, ValArrayPtr) BldArray = [ValArrayPtr[i] for i in range(alength.value)] self._free(ValArrayPtr) return BldArray def CloseOutputFile(self): ''' Call to close binary file. ''' ret = self._CloseOut(self.enrapi) if ret != 0: raise Exception('Failed to Close *.out file') if __name__ in "__main__": dllLoc = 'outputAPI.dll' binfile = 'C:\\PROJECTCODE\\EPANEToutputAPI\\Net3.out' print("Testing Wrapper...") print("Test Network 3...") print("-->Instantiating DLL Object / Opening DLL") self = OutputObject(dllLoc) print("...Opened DLL") print("\n-->Reading Binary File") self.OpenOutputFile(binfile) print("...Opened Bin File") print("\n-->get_NodeSeries") LENTest = -1 demands = self.get_NodeSeries(0,ENR_demand, 0, LENTest) head = self.get_NodeSeries(0,ENR_head, 0, LENTest) pressure = self.get_NodeSeries(0,ENR_pressure, 0, LENTest) quality = self.get_NodeSeries(0,ENR_quality, 0, LENTest) print('\t'.join(["ind","demand","head","pressure","quality"])) for ind, val in enumerate(demands): print ind, val, head[ind], pressure[ind], quality[ind] print("\n-->get_LinkSeries") flow = self.get_LinkSeries(0,ENR_flow) velocity =self.get_LinkSeries(0,ENR_velocity) headloss =self.get_LinkSeries(0,ENR_headloss) avgQuality=self.get_LinkSeries(0,ENR_avgQuality) status=self.get_LinkSeries(0,ENR_status) setting=self.get_LinkSeries(0,ENR_setting) rxRate=self.get_LinkSeries(0,ENR_rxRate) frctnFctr =self.get_LinkSeries(0,ENT_frctnFctr) print('\t'.join(["ind","flow","velocity","headloss","avgQuality",\ "status","setting","rxRate","frctnFctr"])) for ind, val in enumerate(flow): print ind, val, velocity[ind],headloss[ind],avgQuality[ind],status[ind],setting[ind],rxRate[ind],frctnFctr[ind] print("\n-->get_NodeAttribute") demand_1 = self.get_NodeAttribute(ENR_demand,0) head_1 = self.get_NodeAttribute(ENR_head,0) pressure_1 = self.get_NodeAttribute(ENR_pressure,0) quality_1 = self.get_NodeAttribute(ENR_quality,0) print('\t'.join(["ind","demand","head","pressure","quality"])) for ind, val in enumerate(demand_1): print ind, val, head_1[ind], pressure_1[ind], quality_1[ind] print("\n-->get_LinkAttribute") flow1 = self.get_LinkAttribute(ENR_flow,0) velocity1 =self.get_LinkAttribute(ENR_velocity,0) headloss1 =self.get_LinkAttribute(ENR_headloss,0) avgQuality1=self.get_LinkAttribute(ENR_avgQuality,0) status1=self.get_LinkAttribute(ENR_status,0) setting1=self.get_LinkAttribute(ENR_setting,0) rxRate1=self.get_LinkAttribute(ENR_rxRate,0) frctnFctr1 =self.get_LinkAttribute(ENT_frctnFctr,0) print('\t'.join(["ind","flow","velocity","headloss","avgQuality",\ "status","setting","rxRate","frctnFctr"])) for ind, val in enumerate(flow1): print ind, val, velocity1[ind],headloss1[ind],avgQuality1[ind],status1[ind],setting1[ind],rxRate1[ind],frctnFctr1[ind] print("\n-->Object Counts") print("Nodes") print(self.nodeCount) print("Nodes") print(self.nodeCount) print("Tanks") print(self.tankCount) print("Links") print(self.linkCount) print("Pumps") print(self.pumpCount) print("Values") print(self.valveCount) print("\n-->get_NodeResult") print(self.get_NodeResult(96,24)) print("\n-->get_LinkResult") print(self.get_LinkResult(0,0)) print("\n-->get_Units") self.get_Units() print("...flow unit code") print(self.flowUnits) print("...pressure unit code") print(self.pressUnits) print("\n-->Closing Binary File") self.CloseOutputFile() print("...Closed Binary File") \ No newline at end of file +''' Wrapper for EPANET Output API. Author: Bryant E. McDonnell Date: 12/7/2015 Language: Anglais ''' from ctypes import * ##ENR_ElementType; ENR_node = 1 ENR_link = 2 ##ENR_ApiFunction; ENR_getSeries = 1 ENR_getAttribute = 2 ENR_getResult = 3 ##ENR_ElementCount; ENR_nodeCount = 1 ENR_tankCount = 2 ENR_linkCount = 3 ENR_pumpCount = 4 ENR_valveCount = 5 ##ENR_Unit; ENR_flowUnits = 1 ENR_pressUnits = 2 ##ENR_Time; ENR_reportStart = 1 ENR_reportStep = 2 ENR_simDuration = 3 ENR_numPeriods = 4 ##ENR_NodeAttribute; ENR_demand = 0 ENR_head = 1 ENR_pressure = 2 ENR_quality = 3 ##ENR_LinkAttribute; ENR_flow = 0 ENR_velocity = 1 ENR_headloss = 2 ENR_avgQuality = 3 ENR_status = 4 ENR_setting = 5 ENR_rxRate = 6 ENT_frctnFctr = 7 #Used just to pull the Pointer of the ENResultsAPI struct class _Opaque(Structure): ''' Used soley for passing the pointer to the enrapi struct to API ''' pass class OutputObject: def __init__(self, dllLoc): ''' Instantiate python Wrapper Object and build Wrapper functions. ''' try: self.DLL = CDLL(dllLoc) except: raise Exception('Failed to Open Linked Library') ###ENResultsAPI* DLLEXPORT ENR_alloc(void); self._enrapiFunc = self.DLL.ENR_alloc self._enrapiFunc.restype = POINTER(_Opaque) ###int DLLEXPORT ENR_open(ENResultsAPI* enrapi, const char* path); self._OpenFunc = self.DLL.ENR_open ###int DLLEXPORT ENR_getNetSize(ENResultsAPI* enrapi, ENR_ElementCount code, int* count); self._GetNetSize = self.DLL.ENR_getNetSize ###int DLLEXPORT ENR_getUnits(ENResultsAPI* enrapi, ENR_Unit code, int* unitFlag); self._GetUnits = self.DLL.ENR_getUnits self._GetUnits.argtypes = [POINTER(_Opaque), c_int, POINTER(c_int)] self._GetUnits.restype = c_int ###int DLLEXPORT ENR_getTimes(ENResultsAPI* enrapi, ENR_Time code, int* time) self._getTimes = self.DLL.ENR_getTimes ###float* ENR_newOutValueSeries(ENResultsAPI* enrapi, int seriesStart, ### int seriesLength, int* length, int* errcode); self._newOutValueSeries = self.DLL.ENR_newOutValueSeries self._newOutValueSeries.argtypes = [POINTER(_Opaque), c_int, c_int, POINTER(c_int), POINTER(c_int)] self._newOutValueSeries.restype = POINTER(c_float) ###float* ENR_newOutValueArray(ENResultsAPI* enrapi, ENR_ApiFunction func, ### ENR_ElementType type, int* length, int* errcode); self._newOutValueArray = self.DLL.ENR_newOutValueArray self._newOutValueArray.argtypes = [POINTER(_Opaque), c_int, c_int, POINTER(c_int), POINTER(c_int)] self._newOutValueArray.restype = POINTER(c_float) ###int DLLEXPORT ENR_getNodeSeries(ENResultsAPI* enrapi, int nodeIndex, ENR_NodeAttribute attr, ### int timeIndex, int length, float* outValueSeries, int* len); self._getNodeSeries = self.DLL.ENR_getNodeSeries ###int DLLEXPORT ENR_getLinkSeries(ENResultsAPI* enrapi, int linkIndex, ENR_LinkAttribute attr, ### int timeIndex, int length, float* outValueSeries); self._getLinkSeries = self.DLL.ENR_getLinkSeries ###int DLLEXPORT ENR_getNodeAttribute(ENResultsAPI* enrapi, int timeIndex, ### ENR_NodeAttribute attr, float* outValueArray); self._getNodeAttribute = self.DLL.ENR_getNodeAttribute ###int DLLEXPORT ENT_getLinkAttribute(ENResultsAPI* enrapi, int timeIndex, ### ENR_LinkAttribute attr, float* outValueArray); self._getLinkAttribute = self.DLL.ENR_getLinkAttribute ###int DLLEXPORT ENR_getNodeResult(ENResultsAPI* enrapi, int timeIndex, int nodeIndex, ### float* outValueArray); self._getNodeResult = self.DLL.ENR_getNodeResult ###int DLLEXPORT ENR_getLinkResult(ENResultsAPI* enrapi, int timeIndex, int linkIndex, ### float* outValueArray); self._getLinkResult = self.DLL.ENR_getLinkResult ###int DLLEXPORT ENR_free(float *array); self._free = self.DLL.ENR_free ###int DLLEXPORT ENR_close(ENResultsAPI* enrapi); self._CloseOut = self.DLL.ENR_close ###int DLLEXPORT ENR_errMessage(int errcode, char* errmsg, int n); self._RetErrMessage = self.DLL.ENR_errMessage def OpenOutputFile(self, binfile): ''' 1) Initializes the opaque pointer to enrapi struct. 2) Opens the output file. ''' self.enrapi = self._enrapiFunc() ret = self._OpenFunc(self.enrapi, binfile) if ret != 0: self.CloseOutputFile() raise Exception('Failed to open OutputFile') ##Update Function at a later date ## def RaiseError(self, ErrNo): ## ErMsg = c_char_p(256) ## ## self._RetErrMessage(ErrNo , ErMsg, 256) ## ## print ErMsg def get_Units(self): ''' Purpose: Returns pressure and flow units ''' unit = c_int() self._GetUnits(self.enrapi, ENR_flowUnits, unit) self.flowUnits = unit.value unit = c_int() self._GetUnits(self.enrapi, ENR_pressUnits, unit) self.pressUnits = unit.value def get_NetSize(self): ''' Populates object attributes with the water object counts ''' count = c_int() self._GetNetSize(self.enrapi, ENR_nodeCount, byref(count)) self.nodeCount = count.value count = c_int() self._GetNetSize(self.enrapi, ENR_tankCount, byref(count)) self.tankCount = count.value count = c_int() self._GetNetSize(self.enrapi, ENR_linkCount, byref(count)) self.linkCount = count.value count = c_int() self._GetNetSize(self.enrapi, ENR_pumpCount, byref(count)) self.pumpCount = count.value count = c_int() self._GetNetSize(self.enrapi, ENR_valveCount, byref(count)) self.valveCount = count.value def get_Times(self): ''' Purpose: Returns report and simulation time related parameters. ''' temp = c_int() self._getTimes(self.enrapi, ENR_reportStart, byref(temp)) self.reportStart = temp.value temp = c_int() self._getTimes(self.enrapi, ENR_reportStep, byref(temp)) self.reportStep = temp.value temp = c_int() self._getTimes(self.enrapi, ENR_simDuration, byref(temp)) self.simDuration = temp.value temp = c_int() self._getTimes(self.enrapi, ENR_numPeriods, byref(temp)) self.numPeriods = temp.value def get_NodeSeries(self, NodeInd, NodeAttr, SeriesStartInd = 0, SeriesLen = -1): ''' Purpose: Get time series results for particular attribute. Specify series start and length using seriesStart and seriesLength respectively. SeriesLen = -1 Default input: Gets data from Series Start Ind to end ''' if not hasattr(self, 'numPeriods'): self.get_Times() if SeriesLen > self.numPeriods : raise Exception("Outside Number of TimeSteps") elif SeriesLen == -1: SeriesLen = self.numPeriods sLength = c_int() ErrNo1 = c_int() SeriesPtr = self._newOutValueSeries(self.enrapi, SeriesStartInd,\ SeriesLen, byref(sLength), byref(ErrNo1)) ErrNo2 = self._getNodeSeries(self.enrapi, NodeInd, NodeAttr, \ SeriesStartInd, sLength.value, SeriesPtr) BldArray = [SeriesPtr[i] for i in range(sLength.value)] self._free(SeriesPtr) return BldArray def get_LinkSeries(self, LinkInd, LinkAttr, SeriesStartInd = 0, SeriesLen = -1): ''' Purpose: Get time series results for particular attribute. Specify series start and length using seriesStart and seriesLength respectively. SeriesLen = -1 Default input: Gets data from Series Start Ind to end ''' if not hasattr(self, 'numPeriods'): self.get_Times() if SeriesLen > self.numPeriods : raise Exception("Outside Number of TimeSteps") elif SeriesLen == -1: SeriesLen = self.numPeriods sLength = c_int() ErrNo1 = c_int() SeriesPtr = self._newOutValueSeries(self.enrapi, SeriesStartInd,\ SeriesLen, byref(sLength), byref(ErrNo1)) ErrNo2 = self._getLinkSeries(self.enrapi, LinkInd, LinkAttr, \ SeriesStartInd, sLength.value, SeriesPtr) BldArray = [SeriesPtr[i] for i in range(sLength.value)] ret = self._free(SeriesPtr) return BldArray def get_NodeAttribute(self, NodeAttr, TimeInd): ''' Purpose: For all nodes at given time, get a particular attribute ''' if not hasattr(self, 'nodeCount'): self.get_NetSize() alength = c_int() ErrNo1 = c_int() ValArrayPtr = self._newOutValueArray(self.enrapi, ENR_getAttribute,\ ENR_node, byref(alength), byref(ErrNo1)) ErrNo2 = self._getNodeAttribute(self.enrapi, TimeInd, NodeAttr, ValArrayPtr) BldArray = [ValArrayPtr[i] for i in range(alength.value)] self._free(ValArrayPtr) return BldArray def get_LinkAttribute(self, LinkAttr, TimeInd): ''' Purpose: For all links at given time, get a particular attribute ''' if not hasattr(self, 'linkCount'): self.get_NetSize() alength = c_int() ErrNo1 = c_int() ValArrayPtr = self._newOutValueArray(self.enrapi, ENR_getAttribute,\ ENR_link, byref(alength), byref(ErrNo1)) ErrNo2 = self._getLinkAttribute(self.enrapi, TimeInd, LinkAttr, ValArrayPtr) BldArray = [ValArrayPtr[i] for i in range(alength.value)] self._free(ValArrayPtr) return BldArray def get_NodeResult(self, NodeInd, TimeInd): ''' Purpose: For a node at given time, get all attributes ''' alength = c_int() ErrNo1 = c_int() ValArrayPtr = self._newOutValueArray(self.enrapi, ENR_getResult,\ ENR_node, byref(alength), byref(ErrNo1)) ErrNo2 = self._getNodeResult(self.enrapi, TimeInd, NodeInd, ValArrayPtr) BldArray = [ValArrayPtr[i] for i in range(alength.value)] self._free(ValArrayPtr) return BldArray def get_LinkResult(self, LinkInd, TimeInd): ''' Purpose: For a link at given time, get all attributes ''' alength = c_int() ErrNo1 = c_int() ValArrayPtr = self._newOutValueArray(self.enrapi, ENR_getResult,\ ENR_link, byref(alength), byref(ErrNo1)) ErrNo2 = self._getLinkResult(self.enrapi, TimeInd, LinkInd, ValArrayPtr) BldArray = [ValArrayPtr[i] for i in range(alength.value)] self._free(ValArrayPtr) return BldArray def CloseOutputFile(self): ''' Call to close binary file. ''' ret = self._CloseOut(self.enrapi) if ret != 0: raise Exception('Failed to Close *.out file') if __name__ in "__main__": dllLoc = 'outputAPI.dll' binfile = 'C:\\PROJECTCODE\\EPANEToutputAPI\\Net3.out' print("Testing Wrapper...") print("Test Network 3...") print("-->Instantiating DLL Object / Opening DLL") self = OutputObject(dllLoc) print("...Opened DLL") print("\n-->Reading Binary File") self.OpenOutputFile(binfile) print("...Opened Bin File") print("\n-->get_NodeSeries") LENTest = -1 demands = self.get_NodeSeries(0,ENR_demand, 0, LENTest) head = self.get_NodeSeries(0,ENR_head, 0, LENTest) pressure = self.get_NodeSeries(0,ENR_pressure, 0, LENTest) quality = self.get_NodeSeries(0,ENR_quality, 0, LENTest) print('\t'.join(["ind","demand","head","pressure","quality"])) for ind, val in enumerate(demands): print ind, val, head[ind], pressure[ind], quality[ind] print("\n-->get_LinkSeries") flow = self.get_LinkSeries(0,ENR_flow) velocity =self.get_LinkSeries(0,ENR_velocity) headloss =self.get_LinkSeries(0,ENR_headloss) avgQuality=self.get_LinkSeries(0,ENR_avgQuality) status=self.get_LinkSeries(0,ENR_status) setting=self.get_LinkSeries(0,ENR_setting) rxRate=self.get_LinkSeries(0,ENR_rxRate) frctnFctr =self.get_LinkSeries(0,ENT_frctnFctr) print('\t'.join(["ind","flow","velocity","headloss","avgQuality",\ "status","setting","rxRate","frctnFctr"])) for ind, val in enumerate(flow): print ind, val, velocity[ind],headloss[ind],avgQuality[ind],status[ind],setting[ind],rxRate[ind],frctnFctr[ind] print("\n-->get_NodeAttribute") demand_1 = self.get_NodeAttribute(ENR_demand,0) head_1 = self.get_NodeAttribute(ENR_head,0) pressure_1 = self.get_NodeAttribute(ENR_pressure,0) quality_1 = self.get_NodeAttribute(ENR_quality,0) print('\t'.join(["ind","demand","head","pressure","quality"])) for ind, val in enumerate(demand_1): print ind, val, head_1[ind], pressure_1[ind], quality_1[ind] print("\n-->get_LinkAttribute") flow1 = self.get_LinkAttribute(ENR_flow,0) velocity1 =self.get_LinkAttribute(ENR_velocity,0) headloss1 =self.get_LinkAttribute(ENR_headloss,0) avgQuality1=self.get_LinkAttribute(ENR_avgQuality,0) status1=self.get_LinkAttribute(ENR_status,0) setting1=self.get_LinkAttribute(ENR_setting,0) rxRate1=self.get_LinkAttribute(ENR_rxRate,0) frctnFctr1 =self.get_LinkAttribute(ENT_frctnFctr,0) print('\t'.join(["ind","flow","velocity","headloss","avgQuality",\ "status","setting","rxRate","frctnFctr"])) for ind, val in enumerate(flow1): print ind, val, velocity1[ind],headloss1[ind],avgQuality1[ind],status1[ind],setting1[ind],rxRate1[ind],frctnFctr1[ind] print("\n-->Object Counts") print("Nodes") print(self.nodeCount) print("Nodes") print(self.nodeCount) print("Tanks") print(self.tankCount) print("Links") print(self.linkCount) print("Pumps") print(self.pumpCount) print("Values") print(self.valveCount) print("\n-->get_NodeResult") print(self.get_NodeResult(96,24)) print("\n-->get_LinkResult") print(self.get_LinkResult(0,0)) print("\n-->get_Units") self.get_Units() print("...flow unit code") print(self.flowUnits) print("...pressure unit code") print(self.pressUnits) print("\n-->Closing Binary File") self.CloseOutputFile() print("...Closed Binary File") \ No newline at end of file diff --git a/tools/outputapi/OutDiff.py b/tools/outputapi/OutDiff.py deleted file mode 100644 index c7046dc..0000000 --- a/tools/outputapi/OutDiff.py +++ /dev/null @@ -1 +0,0 @@ -''' Compares Two EPANET binary output files. Author: Bryant E. McDonnell Date: 12/16/2015 Compares the absolute value of two values against a given threshold value. ******************* Command Line Arguments: python <*.out 1> <*.out 2> Returns True / False (Pass / Fail, respectively) ******************* ''' import sys import os from math import log from ENOutputWrapper import * def BinCompare(args): # Some Error Checking for Command Line Arguments.... if len(args) < 3: raise Exception("Not Enough Input Arguments: python <*.out 1> <*.out 2>") if args[1].endswith('.out') == False or args[2].endswith('.out') == False: raise Exception("python <*.out 1> <*.out 2>") print(sys.argv[1],sys.argv[2]) dllLoc = os.getcwd() + '/' + 'outputAPI.dll' BinFile1 = OutputObject(dllLoc) BinFile1.OpenOutputFile(args[1]) BinFile1.get_NetSize() BinFile1.get_Times() BinFile2 = OutputObject(dllLoc) BinFile2.OpenOutputFile(args[2]) ####ENR_NodeAttribute; ##ENR_demand = 0 ##ENR_head = 1 ##ENR_pressure = 2 ##ENR_quality = 3 NumberOfNodeAttr = 4 ####ENR_LinkAttribute; ##ENR_flow = 0 ##ENR_velocity = 1 ##ENR_headloss = 2 ##ENR_avgQuality = 3 ##ENR_status = 4 ##ENR_setting = 5 ##ENR_rxRate = 6 ##ENT_frctnFctr = 7 NumberOfLinkAttr = 8 NumberOfPeriods = BinFile1.numPeriods # Set Tolerances for each attribute # demand, head, pressure, quality NodeAttributeTolerances = [1e-6, 1e-6, 1e-6, 1e-6] # flow, velocity, headloss, avgQuality, status, setting, rxRate, frctnFctr LinkAttributeTolerances = [1e-6, 1e-6, 1e-6, 1e-6, 1e-6, 1e-6, 1e-6, 1e-6] #Compare Node Attributes for nodeAttrInd in range(NumberOfNodeAttr): for TSind in range(NumberOfPeriods): #Get 1 attribute for all nodes at time t NodeAttributeOut1 = BinFile1.get_NodeAttribute(nodeAttrInd, TSind) #Get 1 attribute for all nodes at time t NodeAttributeOut2 = BinFile2.get_NodeAttribute(nodeAttrInd, TSind) for Nodeind, NodeAttrVal in enumerate(NodeAttributeOut1): if abs(NodeAttrVal - NodeAttributeOut2[Nodeind]) > 0: diff = abs(NodeAttrVal - NodeAttributeOut2[Nodeind] ) if diff > NodeAttributeTolerances[nodeAttrInd]: return False #Compare Link Attributes for linkAttrInd in range(NumberOfLinkAttr): for TSind in range(NumberOfPeriods): #Get 1 attribute for all links at time t LinkAttributeOut1 = BinFile1.get_NodeAttribute(linkAttrInd, TSind) #Get 1 attribute for all links at time t LinkAttributeOut2 = BinFile2.get_NodeAttribute(linkAttrInd, TSind) for linkind, LinkAttrVal in enumerate(LinkAttributeOut1): if abs(LinkAttrVal - LinkAttributeOut2[linkind]) > 0: diff = abs(LinkAttrVal - LinkAttributeOut2[linkind] ) if diff > LinkAttributeTolerances[linkAttrInd]: return False return True if __name__ == '__main__': print(BinCompare(sys.argv)) \ No newline at end of file diff --git a/tools/outputapi/_ENOutputToolkit.py b/tools/outputapi/_ENOutputToolkit.py deleted file mode 100644 index 7687828..0000000 --- a/tools/outputapi/_ENOutputToolkit.py +++ /dev/null @@ -1 +0,0 @@ -##ENR_ElementType; ENR_node = 1 ENR_link = 2 ##ENR_ApiFunction; ENR_getSeries = 1 ENR_getAttribute = 2 ENR_getResult = 3 ##ENR_ElementCount; ENR_nodeCount = 1 ENR_tankCount = 2 ENR_linkCount = 3 ENR_pumpCount = 4 ENR_valveCount = 5 ##ENR_Unit; ENR_flowUnits = 1 ENR_pressUnits = 2 ##ENR_Time; ENR_reportStart = 1 ENR_reportStep = 2 ENR_simDuration = 3 ENR_numPeriods = 4 ##ENR_NodeAttribute; ENR_demand = 0 ENR_head = 1 ENR_pressure = 2 ENR_quality = 3 ##ENR_LinkAttribute; ENR_flow = 0 ENR_velocity = 1 ENR_headloss = 2 ENR_avgQuality = 3 ENR_status = 4 ENR_setting = 5 ENR_rxRate = 6 ENT_frctnFctr = 7 \ No newline at end of file