diff --git a/.github/workflows/build_tests.yml b/.github/workflows/build_tests.yml index b6a5a84..e3030e0 100644 --- a/.github/workflows/build_tests.yml +++ b/.github/workflows/build_tests.yml @@ -30,4 +30,4 @@ jobs: flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - name: Test with pytest run: | - pytest + pytest -v \ No newline at end of file diff --git a/README.md b/README.md index 050a7d0..f86090a 100644 --- a/README.md +++ b/README.md @@ -518,6 +518,7 @@ If you want to contribute, please check out our [Code of Conduct](https://github | MSX Functions |loadMSXFile|Opens the EPANET-MSX toolkit system| |unloadMSX|Closes the EPANET-MSX toolkit system| +|addMSXPattern|Adds a new, empty MSX source time pattern to the project| |initializeMSXQualityAnalysis|Initializes the MSX system before solving for water quality results in step-wise fashion| |stepMSXQualityAnalysisTimeLeft|Advances the water quality solution through a single water quality time step when performing a step-wise simulation| |saveMSXFile|Saves the data associated with the current MSX project into a new MSX input file| @@ -584,6 +585,8 @@ If you want to contribute, please check out our [Code of Conduct](https://github |setMSXTimeStep|Sets time step| |setMSXPatternValue|Assigns a new value to the multiplier for a specific time period in a given MSX source time pattern| |setMSXPattern|Sets all of the multiplier factors for a specific time pattern| +|setMSXParametersPipesValue|Assigns a value to a particular reaction parameter for given pipes| +|setMSXParametersTanksValue|Assigns a value to a particular reaction parameter for given tanks| |setMSXConstantsValue|Assigns a new value to a specific reaction constant| |useMSXHydraulicFile|Uses a previously saved EPANET hydraulics file as the source of hydraulic information| diff --git a/epyt/__init__.py b/epyt/__init__.py index a6be376..f48588b 100644 --- a/epyt/__init__.py +++ b/epyt/__init__.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- __author__ = """Marios S. Kyriakou""" __email__ = "kiriakou.marios@ucy.ac.cy" -__version__ = "1.0.9-beta.2" +__version__ = "1.0.9-beta.4" +__msxversion__ = "2.0.0" __copyright__ = """Copyright 2022, KIOS Research and Innovation Center of Excellence (KIOS CoE), University of Cyprus (www.kios.org.cy).""" __license__ = "EUPL License, Version 1.2" diff --git a/epyt/epanet.py b/epyt/epanet.py index b632c53..33b69ca 100644 --- a/epyt/epanet.py +++ b/epyt/epanet.py @@ -64,7 +64,7 @@ c_char_p import matplotlib.pyplot as plt from datetime import datetime -from epyt import __version__ +from epyt import __version__, __msxversion__ from shutil import copyfile from matplotlib import cm import matplotlib as mpl @@ -331,6 +331,28 @@ def __init__(self): MSX_FLOWPACED = 3 +def safe_delete(file): + if isinstance(file, list): + for file_path in file: + if os.path.exists(file_path): + try: + try: + os.unlink(rf"{file_path}") + except: + os.remove(rf"{file_path}") + except Exception as e: + print(f"Could not delete {file}: {e}") + else: + if os.path.exists(file): + try: + try: + os.unlink(rf"{file}") + except: + os.remove(rf"{file}") + except Exception as e: + print(f"Could not delete {file}: {e}") + + class EpytValues: def __init__(self): @@ -482,10 +504,11 @@ def isList(var): class epanet: """ EPyt main functions class """ - def __init__(self, *argv, version=2.2, loadfile=False, msx=False): + def __init__(self, *argv, version=2.2, ph=False, loadfile=False, msx=False): # Constants # Demand model types. DDA #0 Demand driven analysis, # PDA #1 Pressure driven analysis. + self.msxname = None self.DEMANDMODEL = ['DDA', 'PDA'] # Link types self.TYPELINK = ['CVPIPE', 'PIPE', 'PUMP', 'PRV', 'PSV', @@ -603,7 +626,8 @@ def __init__(self, *argv, version=2.2, loadfile=False, msx=False): self.LibEPANETpath = self.api.LibEPANETpath self.LibEPANET = self.api.LibEPANET print(f'Input File {self.netName} loaded successfully.\n') - else: + + if ph: self.createProject() # Global plot settings @@ -613,8 +637,7 @@ def __init__(self, *argv, version=2.2, loadfile=False, msx=False): plt.rcParams['figure.max_open_warning'] = 30 if msx: - self.msx = epanetmsxapi() - MSX_SPECIES = 3 + self.msx = epanetmsxapi(ignore_msxfile=True) def addControls(self, control, *argv): """ Adds a new simple control. @@ -1685,8 +1708,8 @@ def deleteAllTemps(self): for filename in os.listdir(net_dir): if 'temp' in filename: try: - os.remove(os.path.join(net_dir, filename)) - finally: + os.unlink(os.path.join(net_dir, filename)) + except: pass def deleteControls(self, *argv): @@ -2441,10 +2464,8 @@ def getControls(self, *argv): indices = self.__getControlIndices(*argv) value = {} self.ControlTypes = [] - self.ControlTypesIndex, self.ControlLinkIndex, \ - self.ControlSettings, self.ControlTypes, \ - self.ControlNodeIndex, self.ControlLevelValues = \ - [], [], [], [], [], [] + self.ControlTypesIndex, self.ControlLinkIndex, self.ControlSettings, self.ControlTypes, \ + self.ControlNodeIndex, self.ControlLevelValues = [], [], [], [], [], [] if not isList(indices): indices = [indices] for i in indices: @@ -10343,26 +10364,22 @@ def unload(self): try: self.api.ENclose() finally: - try: - if os.path.exists(self.TempInpFile): - os.remove(self.TempInpFile) - except: - pass - try: - if os.path.exists(self.TempInpFile): - os.unlink(self.TempInpFile) - except: - pass - try: - os.remove(self.TempInpFile[0:-4] + '.txt') - os.remove(self.InputFile[0:-4] + '.txt') - os.remove(self.BinTempfile) - except: - pass + safe_delete(self.TempInpFile) + files_to_delete = [self.TempInpFile[0:-4] + '.txt', self.InputFile[0:-4] + '.txt', self.BinTempfile] + for file in files_to_delete: + safe_delete(file) for file in Path(".").glob("@#*.txt"): - file.unlink() + safe_delete(file) + safe_delete(self.TempInpFile) + + cwd = os.getcwd() + tmp_files = list(filter(lambda f: os.path.isfile(os.path.join(cwd, f)) + and f.startswith("s") and 6 <= len(f) <= 8 and "." not in f and "_" in f, + os.listdir(cwd))) + tmp_files_paths = [os.path.join(cwd, f) for f in tmp_files] + safe_delete(tmp_files_paths) - print(f'Close toolkit for the input file "{self.netName[0:-4]}". EPANET Toolkit is unloaded.\n') + print(f'Close toolkit for the input file "{self.netName[0:-4]}". EPANET Toolkit is unloaded.\n') def useHydraulicFile(self, hydname): """ Uses the contents of the specified file as the current binary hydraulics file. @@ -11016,7 +11033,7 @@ def __setControlFunction(self, index, value): self.api.ENsetcontrol(controlRuleIndex, controlTypeIndex, linkIndex, controlSettingValue, nodeIndex, controlLevel) - def __setEval(self, func, code_pStr, Type, value, *argv): + def __setEval(self, func, code_pstr, Type, value, *argv): if len(argv) == 1: index = value value = argv[0] @@ -11026,27 +11043,27 @@ def __setEval(self, func, code_pStr, Type, value, *argv): if np.isnan(value[j]): continue strFunc = 'self.api.' + func + '(' + str( - i) + ',' + 'self.ToolkitConstants.EN_' + code_pStr + ',' + str(value[j]) + ')' + i) + ',' + 'self.ToolkitConstants.EN_' + code_pstr + ',' + str(value[j]) + ')' eval(strFunc) j += 1 else: strFunc = 'self.api.' + func + '(' + str( - index) + ',' + 'self.ToolkitConstants.EN_' + code_pStr + ',' + str(value) + ')' + index) + ',' + 'self.ToolkitConstants.EN_' + code_pstr + ',' + str(value) + ')' eval(strFunc) else: count = 0 - if (Type == 'LINK'): + if Type == 'LINK': count = self.getLinkCount() - elif (Type == 'NODE'): + elif Type == 'NODE': count = self.getNodeCount() for i in range(count): if np.isnan(value[i]): continue strFunc = 'self.api.' + func + '(' + str( - i + 1) + ',' + 'self.ToolkitConstants.EN_' + code_pStr + ',' + str(value[i]) + ')' + i + 1) + ',' + 'self.ToolkitConstants.EN_' + code_pstr + ',' + str(value[i]) + ')' eval(strFunc) - def __setEvalLinkNode(self, func, code_pStr, Type, value, *argv): + def __setEvalLinkNode(self, func, code_pstr, Type, value, *argv): if len(argv) == 1: index = value value = argv[0] @@ -11055,13 +11072,13 @@ def __setEvalLinkNode(self, func, code_pStr, Type, value, *argv): if isinstance(value, list): for i in index: strFunc = 'self.api.' + func + '(' + str( - i) + ',' + 'self.ToolkitConstants.EN_' + code_pStr + ',' + str(value[j]) + ')' + i) + ',' + 'self.ToolkitConstants.EN_' + code_pstr + ',' + str(value[j]) + ')' eval(strFunc) j += 1 else: for i in index: strFunc = 'self.api.' + func + '(' + str( - i) + ',' + 'self.ToolkitConstants.EN_' + code_pStr + ',' + str(value) + ')' + i) + ',' + 'self.ToolkitConstants.EN_' + code_pstr + ',' + str(value) + ')' eval(strFunc) j += 1 else: @@ -11077,7 +11094,7 @@ def __setEvalLinkNode(self, func, code_pStr, Type, value, *argv): if isinstance(value, (list, np.ndarray)): value = value[0] strFunc = 'self.api.' + func + '(' + str( - Index) + ',' + 'self.ToolkitConstants.EN_' + code_pStr + ',' + str(value) + ')' + Index) + ',' + 'self.ToolkitConstants.EN_' + code_pstr + ',' + str(value) + ')' eval(strFunc) else: count = 0 @@ -11091,12 +11108,12 @@ def __setEvalLinkNode(self, func, code_pStr, Type, value, *argv): if isinstance(value, (list, np.ndarray)): for i in range(count): strFunc = 'self.api.' + func + '(' + str( - indices[i]) + ',' + 'self.ToolkitConstants.EN_' + code_pStr + ',' + str(value[i]) + ')' + indices[i]) + ',' + 'self.ToolkitConstants.EN_' + code_pstr + ',' + str(value[i]) + ')' eval(strFunc) else: for i in range(count): strFunc = 'self.api.' + func + '(' + str( - indices[i]) + ',' + 'self.ToolkitConstants.EN_' + code_pStr + ',' + str(value) + ')' + indices[i]) + ',' + 'self.ToolkitConstants.EN_' + code_pstr + ',' + str(value) + ')' eval(strFunc) def __setFlowUnits(self, unitcode, *argv): @@ -11138,15 +11155,62 @@ def __setNodeDemandPattern(self, fun, propertyCode, value, *argv): eval('self.api.' + fun + '(i, categ, param[j])') j += 1 - """MSX Funtions""" + """MSX Functions""" - def loadMSXfile(self, msxname): + def loadMSXFile(self, msxname, ignore_properties=False): """Loads an msx file Example: - d.loadMSXfile('net2-cl2.msx') + d.loadMSXFile('net2-cl2.msx') """ - self.realmsx = msxname - self.MSXPythonSetup(msxname) + self.msxname = msxname[:-4] + '_temp.msx' + copyfile(msxname, self.msxname) + self.msx = epanetmsxapi(self.msxname) + print(f'MSX version {__msxversion__}.') + + if ignore_properties: + self.msx.MSXEquationsTerms = self.getMSXEquationsTerms() + self.msx.MSXEquationsPipes = self.getMSXEquationsPipes() + self.msx.MSXEquationsTanks = self.getMSXEquationsTanks() + self.msx.MSXSpeciesCount = self.getMSXSpeciesCount() + self.msx.MSXConstantsCount = self.getMSXConstantsCount() + self.msx.MSXParametersCount = self.getMSXParametersCount() + self.msx.MSXPatternsCount = self.getMSXPatternsCount() + self.msx.MSXSpeciesIndex = self.getMSXSpeciesIndex() + self.msx.MSXSpeciesNameID = self.getMSXSpeciesNameID() + self.MSXSpeciesType = self.getMSXSpeciesType() + self.msx.MSXSpeciesUnits = self.getMSXSpeciesUnits() + self.msx.MSXSpeciesATOL = self.getMSXSpeciesATOL() + self.msx.MSXSpeciesRTOL = self.getMSXSpeciesRTOL() + self.msx.MSXConstantsNameID = self.getMSXConstantsNameID() + self.msx.MSXConstantsValue = self.getMSXConstantsValue() + self.msx.MSXConstantsIndex = self.getMSXConstantsIndex() + self.msx.MSXParametersNameID = self.getMSXParametersNameID() + self.msx.MSXParametersIndex = self.getMSXParametersIndex() + self.msx.MSXParametersTanksValue = self.getMSXParametersTanksValue() + self.msx.MSXParametersPipesValue = self.getMSXParametersPipesValue() + self.msx.MSXPatternsNameID = self.getMSXPatternsNameID() + self.msx.MSXPatternsIndex = self.getMSXPatternsIndex() + self.msx.MSXPatternsLengths = self.getMSXPatternsLengths() + self.msx.MSXNodeInitqualValue = self.getMSXNodeInitqualValue() + self.msx.MSXLinkInitqualValue = self.getMSXLinkInitqualValue() + self.msx.MSXSources = self.getMSXSources() + self.msx.MSXSourceType = self.getMSXSourceType() + self.msx.MSXSourceLevel = self.getMSXSourceLevel() + self.msx.MSXSourcePatternIndex = self.getMSXSourcePatternIndex() + self.msx.MSXSourceNodeNameID = self.getMSXSourceNodeNameID() + self.msx.MSXPattern = self.getMSXPattern() + + # options + self.solver = self.getMSXSolver() + self.areaunits = self.getMSXAreaUnits() + self.rateunits = self.getMSXRateUnits() + self.rtol = self.getMSXRtol() + self.atol = self.getMSXAtol() + self.timestep = self.getMSXTimeStep() + self.coupling = self.getMSXCoupling() + self.compiler = self.getMSXCompiler() + + return self.msx def unloadMSX(self): """Unload library and close the MSX Toolkit system. @@ -11154,74 +11218,88 @@ def unloadMSX(self): d.unloadMSX() """ self.msx.MSXclose() + msx_temp_files = list(filter(lambda f: os.path.isfile(os.path.join(os.getcwd(), f)) + and f.startswith("msx") and "." not in f, os.listdir(os.getcwd()))) + safe_delete(msx_temp_files) def getMSXSpeciesCount(self): """ Retrieves the number of species. Example: - d = epanet('Net3-NH2CL.inp'); - d.loadMSXFile('Net3-NH2CL.msx'); + d = epanet('Net3-NH2CL.inp') + d.loadMSXFile('Net3-NH2CL.msx') d.getMSXSpeciesCount() See also getMSXSpeciesIndex, getMSXSpeciesNameID, getMSXSpeciesConcentration, getMSXSpeciesType, getMSXSpeciesUnits, getMSXSpeciesATOL, getMSXSpeciesRTOL.""" - MSX_SPECIES = self.ToolkitConstants.MSX_SPECIES - return self.msx.MSXgetcount(MSX_SPECIES) + return self.msx.MSXgetcount(self.ToolkitConstants.MSX_SPECIES) def getMSXConstantsCount(self): """ Retrieves the number of constants. Example: - d = epanet('Net3-NH2CL.inp'); - d.loadMSXFile('Net3-NH2CL.msx'); + d = epanet('Net3-NH2CL.inp') + d.loadMSXFile('Net3-NH2CL.msx') d.getMSXConstantsCount() See also getMSXConstantsIndex, getMSXConstantsValue, getMSXConstantsNameID.""" - MSX_CONSTANT = self.ToolkitConstants.MSX_CONSTANT - return self.msx.MSXgetcount(MSX_CONSTANT) + return self.msx.MSXgetcount(self.ToolkitConstants.MSX_CONSTANT) def getMSXParametersCount(self): """ Retrieves the number of parameters. Example: - d = epanet('Net3-NH2CL.inp'); - d.loadMSXFile('Net3-NH2CL.msx'); + d = epanet('Net3-NH2CL.inp') + d.loadMSXFile('Net3-NH2CL.msx') d.getMSXParametersCount() See also setMSXParametersTanksValue, setMSXParametersPipesValue, getMSXParametersIndex, getMSXParametersTanksValue, getMSXParametersPipesValue.""" - MSX_PARAMETER = self.ToolkitConstants.MSX_PARAMETER - return self.msx.MSXgetcount(MSX_PARAMETER) + return self.msx.MSXgetcount(self.ToolkitConstants.MSX_PARAMETER) def getMSXPatternsCount(self): """ Retrieves the number of patterns. Example: - d = epanet('net2-cl2.inp'); - d.loadMSXFile('net2-cl2.msx'); - d.addMSXPattern('P1', [1.0, 0.0 1.0]); - d.addMSXPattern('P2', [0.0, 0.0 2.0]); + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') + d.addMSXPattern('P1', [1.0, 0.0 1.0]) + d.addMSXPattern('P2', [0.0, 0.0 2.0]) d.getMSXPatternsCount() See also setMSXPattern, setMSXPatternValue, addMSXPattern.""" - MSX_PATTERN = self.ToolkitConstants.MSX_PATTERN - return self.msx.MSXgetcount(MSX_PATTERN) + return self.msx.MSXgetcount(self.ToolkitConstants.MSX_PATTERN) def saveMSXFile(self, msxname): + """ Saves the data associated with the current MSX project into a new MSX input file. + + Example: + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') + d.saveMSXFile('testMSX.msx') + + See also writeMSXFile.""" self.msx.MSXsavemsxfile(msxname) def saveMSXQualityFile(self, outfname): + """ Saves the quality as bin file. + + Example: + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') + d.getMSXComputedQualitySpecie('CL2') + d.saveMSXQualityFile('testMSXQuality.bin')""" self.msx.MSXsaveoutfile(outfname) def solveMSXCompleteHydraulics(self): """Solve complete hydraulic over the entire simulation period. % % Example: - % d = epanet('net2-cl2.inp'); - % d.loadMSXFile('net2-cl2.msx'); + % d = epanet('net2-cl2.inp') + % d.loadMSXFile('net2-cl2.msx') % d.solveMSXCompleteHydraulics() % % See also solveMSXCompleteQuality.""" @@ -11231,8 +11309,8 @@ def solveMSXCompleteQuality(self): """Solve complete hydraulic over the entire simulation period. Example: - d = epanet('net2-cl2.inp'); - d.loadMSXFile('net2-cl2.msx'); + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') d.solveMSXCompleteQuality() See also solveMSXCompleteHydraulics.""" @@ -11242,15 +11320,69 @@ def writeMSXReport(self): self.msx.MSXreport() def useMSXHydraulicFile(self, hydname): + """% Uses a previously saved EPANET hydraulics file as the source + % of hydraulic information. + % + % Example: + % d = epanet('net2-cl2.inp'); + % d.loadMSXFile('net2-cl2.msx'); + % d.saveHydraulicsOutputReportingFile + % d.saveHydraulicFile('testMSXHydraulics.hyd') + % d.useMSXHydraulicFile('testMSXHydraulics.hyd') + % + % See also saveHydraulicsOutputReportingFile, saveHydraulicFile.""" self.msx.MSXusehydfile(hydname) def getMSXPatternValue(self, patternIndex, patternStep): + """ Retrieves the multiplier at a specific time period for a given source time pattern. + + Example: + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') + d.addMSXPattern('P1', [1.0 0.0 3.0]) + d.getMSXPatternValue(1,3) Retrieves the third multiplier of the first pattern. + + See also setMSXPatternValue, setMSXPattern, setMSXPatternMatrix, + getMSXPatternsIndex, getMSXPatternsNameID.""" return self.msx.MSXgetpatternvalue(patternIndex, patternStep) def initializeMSXQualityAnalysis(self, flag): + """ Initializes the MSX system before solving for water quality results + in step-wise fashion. + + flag options: + 1: if water quality results should be saved to a scratch + binary file or + 0: if results are not saved to file. + + Example: + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') + tleft = 1 + d.solveMSXCompleteHydraulics() + d.initializeMSXQualityAnalysis(0) + while(tleft>0): + t,tleft = d.stepMSXQualityAnalysisTimeLeft + + + See also solveMSXCompleteHydraulics, stepMSXQualityAnalysisTimeLeft.""" self.msx.MSXinit(flag) def stepMSXQualityAnalysisTimeLeft(self): + """ Advances the water quality solution through a single water quality time step when + performing a step-wise simulation. + + Example: + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') + tleft = 1 + d.solveMSXCompleteHydraulics() + d.initializeMSXQualityAnalysis(0) + while(tleft>0): + t,tleft = d.stepMSXQualityAnalysisTimeLeft() + + + % See also solveMSXCompleteHydraulics, initializeMSXQualityAnalysis.""" t, tleft = self.msx.MSXstep() return t, tleft @@ -11265,10 +11397,10 @@ def getMSXOptions(self, param="", getall=False): """ Retrieves all the options. Example: - d=epanet('net2-cl2.inp'); - d.loadMSXFile('net2-cl2.msx'); + d=epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') d.getMSXOptions()""" - msxname=self.msxname + msxname = self.msxname options = {} options["AREA_UNITS"] = "FT2" options["RATE_UNITS"] = "HR" @@ -11326,8 +11458,8 @@ def getMSXTimeStep(self): """ Retrieves the time step. Example: - d=epanet('net2-cl2.inp'); - d.loadMSXFile('net2-cl2.msx'); + d=epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') d.getMSXTimeStep() See also setMSXTimeStep.""" @@ -11336,8 +11468,8 @@ def getMSXTimeStep(self): def getMSXRateUnits(self): """ Retrieves rate units. Example: - d = epanet('net2-cl2.inp'); - d.loadMSXFile('net2-cl2.msx'); + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') d.getMSXRateUnits() See also setMSXRateUnits.""" @@ -11346,8 +11478,8 @@ def getMSXRateUnits(self): def getMSXAreaUnits(self): """ Retrieves Are units. Example: - d = epanet('net2-cl2.inp'); - d.loadMSXFile('net2-cl2.msx'); + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') d.getMSXAreaUnits() See also setMSXAreaUnits.""" @@ -11362,8 +11494,8 @@ def getMSXCompiler(self): vc: Visual C++ compiler Example: - d = epanet('net2-cl2.inp'); - d.loadMSXFile('net2-cl2.msx'); + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') d.getMSXCompiler() See also setMSXCompilerNONE, setMSXCompilerVC, @@ -11381,12 +11513,12 @@ def getMSXCoupling(self): rate expressions is computed. Example: - d = epanet('net2-cl2.inp'); - d.loadMSXFile('net2-cl2.msx'); + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') d.getMSXCoupling() See also setMSXCouplingFULL, setMSXCouplingNONE.""" - return self.getMSXOptions("COUPLING") + return self.getMSXOptions("COUPLING") def getMSXSolver(self): """ Retrieves the solver method. @@ -11397,8 +11529,8 @@ def getMSXSolver(self): ROS2 = 2nd order Rosenbrock integrator. Example: - d=epanet('net2-cl2.inp'); - d.loadMSXFile('net2-cl2.msx'); + d=epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') d.getMSXSolver() See also setMSXSolverEUL, setMSXSolverRK5, setMSXSolverROS2.""" @@ -11408,8 +11540,8 @@ def getMSXAtol(self): """ Retrieves the absolute tolerance. Example: - d = epanet('net2-cl2.inp'); - d.loadMSXFile('net2-cl2.msx'); + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') d.getMSXAtol() See also getMSXRtol.""" @@ -11419,8 +11551,8 @@ def getMSXRtol(self): """ Retrieves the relative accuracy level. Example: - d = epanet('net2-cl2.inp'); - d.loadMSXFile('net2-cl2.msx'); + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') d.getMSXRtol() See also getMSXAtol.""" @@ -11430,8 +11562,8 @@ def getMSXConstantsNameID(self, varagin=None): """ Retrieves the constant's ID. Example: - d = epanet('Net3-NH2CL.inp'); - d.loadMSXFile('Net3-NH2CL.msx'); + d = epanet('Net3-NH2CL.inp') + d.loadMSXFile('Net3-NH2CL.msx') d.getMSXConstantsNameID() Retrieves the IDs of all the constants. d.getMSXConstantsNameID({1}) Retrieves the ID of the first constant. d.getMSXConstantsNameID{[1,2]} Retrieves the IDs of the first two constants. @@ -11456,11 +11588,11 @@ def getMSXParametersNameID(self, varagin=None): """ Retrieves the parameter's ID. Example: - d = epanet('Net3-NH2CL.inp'); - d.loadMSXFile('Net3-NH2CL.msx'); + d = epanet('Net3-NH2CL.inp') + d.loadMSXFile('Net3-NH2CL.msx') d.getMSXParametersNameID() % Retrieves the IDs of all the parameters. d.getMSXParametersNameID(1) % Retrieves the ID of the first parameter. - d.getMSXParametersNameID([1:3]) % Retrieves the IDs of the first three parameters. + d.getMSXParametersNameID([1,3]) % Retrieves the IDs of the first and third parrameters. See also getMSXParametersCount, getMSXParametersIndex, getMSXParametersTanksValue, getMSXParametersPipesValue.""" @@ -11482,15 +11614,15 @@ def getMSXPatternsNameID(self, varagin=None): """ Retrieves the patterns ID. Example: - d = epanet('net2-cl2.inp'); - d.loadMSXFile('net2-cl2.msx'); - d.addMSXPattern('P1', [1.0, 0.0 1.0]); - d.addMSXPattern('P2', [0.0, 0.0 2.0]); - d.addMSXPattern('P3', [0.0, 1.0 2.0]); - d.addMSXPattern('P4', [1.0, 1.0 2.0]); + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') + d.addMSXPattern('P1', [1.0, 0.0 1.0]) + d.addMSXPattern('P2', [0.0, 0.0 2.0]) + d.addMSXPattern('P3', [0.0, 1.0 2.0]) + d.addMSXPattern('P4', [1.0, 1.0 2.0]) d.getMSXPatternsNameID() Retrieves the IDs of all the patterns. d.getMSXPatternsNameID(1) Retrieves the ID of the first pattern. - d.getMSXPatternsNameID(1:3) Retrieves the IDs of the first three patterns. + d.getMSXPatternsNameID([1,3]) Retrieves the IDs of the first and third patterns. See also getMSXPattern, getMSXPatternsIndex, getMSXPatternsLengths, setMSXPattern, setMSXPatternMatrix, setMSXPatternValue.""" @@ -11512,8 +11644,8 @@ def getMSXSpeciesNameID(self, varagin=None): """Retrieves the species' ID. Example: - d = epanet('Net3-NH2CL.inp'); - d.loadMSXFile('Net3-NH2CL.msx'); + d = epanet('Net3-NH2CL.inp') + d.loadMSXFile('Net3-NH2CL.msx') d.getMSXSpeciesNameID() Retrieves the IDs of all the species. d.getMSXSpeciesNameID(1) Retrieves the IDs of the first specie. d.getMSXSpeciesNameID([1:3]) Retrieves the IDs of the first three species. @@ -11539,8 +11671,8 @@ def getMSXParametersIndex(self, varagin=None): """ Retrieves the parameter's indices. Example: - d = epanet('Net3-NH2CL.inp'); - d.loadMSXFile('Net3-NH2CL.msx'); + d = epanet('Net3-NH2CL.inp') + d.loadMSXFile('Net3-NH2CL.msx') d.getMSXParametersIndex() Retrieves the indices of all the parameters. d.getMSXParametersIndex(['k1']) Retrieves the index of the first parameter. d.getMSXParametersIndex(['k1', 'k3', 'kDOC1']) Retrieves the indices of the @@ -11567,8 +11699,8 @@ def getMSXSpeciesIndex(self, varagin=None): """ Retrieves the species' index. Example: - d = epanet('Net3-NH2CL.inp'); - d.loadMSXFile('Net3-NH2CL.msx'); + d = epanet('Net3-NH2CL.inp') + d.loadMSXFile('Net3-NH2CL.msx') d.getMSXSpeciesIndex() Retrieves the index of all the species. d.getMSXSpeciesIndex(['Na']) Retrieves the index of the Na. d.getMSXSpeciesIndex(['CL2', 'Nb', 'Na']) Retrieves the indices of CL2, Nb and Na. @@ -11595,12 +11727,12 @@ def getMSXPatternsIndex(self, varagin=None): """ Retrieves the patterns index. Example: - d = epanet('net2-cl2.inp'); - d.loadMSXFile('net2-cl2.msx'); - d.addMSXPattern('P1', [1.0, 0.0 1.0]); - d.addMSXPattern('P2', [0.0, 0.0 2.0]); - d.addMSXPattern('P3', [0.0, 1.0 2.0]); - d.addMSXPattern('P4', [1.0, 1.0 2.0]); + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') + d.addMSXPattern('P1', [1.0, 0.0 1.0]) + d.addMSXPattern('P2', [0.0, 0.0 2.0]) + d.addMSXPattern('P3', [0.0, 1.0 2.0]) + d.addMSXPattern('P4', [1.0, 1.0 2.0]) d.getMSXPatternsIndex() Retrieves the indices of all the patterns. d.getMSXPatternsIndex(['P1']) Retrieves the index of the first pattern. d.getMSXPatternsIndex(['P1', 'P2', 'P3']) Retrieves the indices of the first three patterns. @@ -11626,8 +11758,8 @@ def getMSXConstantsIndex(self, varagin=None): """ Retrieves the constant's index. Example: - d = epanet('Net3-NH2CL.inp'); - d.loadMSXFile('Net3-NH2CL.msx'); + d = epanet('Net3-NH2CL.inp') + d.loadMSXFile('Net3-NH2CL.msx') d.getMSXConstantsIndex() Retrieves the index of all the species. d.getMSXConstantsIndex(['S1']) Retrieves the index of S1. @@ -11652,9 +11784,9 @@ def getMSXConstantsValue(self, varagin=None): """ Retrieves the constant's value. Example: - d = epanet('net3-bio.inp'); - d.loadMSXFile('net3-bio.msx'); - d.getMSXConstantsValue Retrieves the values of all the constants. + d = epanet('net3-bio.inp') + d.loadMSXFile('net3-bio.msx') + d.getMSXConstantsValue() Retrieves the values of all the constants. d.getMSXConstantsValue{1} Retrieves the value of the first constant. d.getMSXConstantsValue{[1,2]} Retrieves the values of the first two constants. @@ -11676,8 +11808,8 @@ def getMSXParametersPipesValue(self): """ Retrieves the parameters pipes value. Example: - d = epanet('net2-cl2.inp'); - d.loadMSXFile('net2-cl2.msx'); + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') d.getMSXParametersPipesValue() See also setMSXParametersPipesValue, getMSXParametersTanksValue, @@ -11697,33 +11829,34 @@ def getMSXParametersTanksValue(self): """ Retrieves the parameters tanks value. Example: - d = epanet('net2-cl2.inp'); - d.loadMSXFile('net2-cl2.msx'); - tankIndex = d.getNodeTankIndex + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') + tankIndex = d.getNodeTankIndex() d.getMSXParametersTanksValue{tankIndex} Retrieves the value of the first tank. See also setMSXParametersTanksValue, getMSXParametersCount, getMSXParametersIndex, getMSXParametersPipesValue.""" x = self.getNodeTankIndex() y = self.getMSXParametersCount() - value = {} + value = [None] * max(x) for i in x: - value[i] = [] - for j in range(1, y + 1): - param = self.msx.MSXgetparameter(0, i, j) - value[i].append(param) - output = list(value.values()) - return output + value[i - 1] = [] + for j in range(y): + param = self.msx.MSXgetparameter(0, i, j + 1) + value[i - 1].append(param) + + return value + def getMSXPatternsLengths(self, varagin=None): """ Retrieves the pattern lengths. Example: - d = epanet('net2-cl2.inp'); - d.loadMSXFile('net2-cl2.msx'); - d.addMSXPattern('P1', [1.0, 0.0 1.0]); - d.addMSXPattern('P2', 1.0); - d.addMSXPattern('P3', [0.0, 1.0 2.0]); - d.addMSXPattern('P4', [1.0, 2.0]); + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') + d.addMSXPattern('P1', [1.0, 0.0 1.0]) + d.addMSXPattern('P2', 1.0) + d.addMSXPattern('P3', [0.0, 1.0 2.0]) + d.addMSXPattern('P4', [1.0, 2.0]) d.getMSXPatternsLengths() Retrieves the lengths of all the patterns. d.getMSXPatternsLengths([]1) Retrieves the length of the first pattern. x=d.getMSXPatternsLengths([1,2]) Retrieves the lengths of the first two patterns. @@ -11745,32 +11878,33 @@ def getMSXPattern(self): """ Retrieves the time patterns. Example: - d = epanet('net2-cl2.inp'); - d.loadMSXFile('net2-cl2.msx'); - d.addMSXPattern('P1', [1.0 0.0 1.0]); - d.addMSXPattern('P2', [1.0 0.0 1.0]); - d.addMSXPattern('P3', [0.0 1.0 2.0]); - d.addMSXPattern('P4', [1.0 2.0 2.5]); + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') + d.addMSXPattern('P1', [1.0 0.0 1.0]) + d.addMSXPattern('P2', [1.0 0.0 1.0]) + d.addMSXPattern('P3', [0.0 1.0 2.0]) + d.addMSXPattern('P4', [1.0 2.0 2.5]) patterns = d.getMSXPattern() Retrieves all the patterns. See also setMSXPattern, setMSXPatternMatrix, setMSXPatternValue, getMSXPatternsIndex, getMSXPatternsNameID,.""" z = self.getMSXPatternsCount() - if z == 0 : + if z == 0: return val = self.getMSXPatternsLengths() y = val tmpmaxlen = max(y) - value = [[0]*tmpmaxlen for _ in range(self.getMSXPatternsCount())] + value = [[0] * tmpmaxlen for _ in range(self.getMSXPatternsCount())] for i in range(1, self.getMSXPatternsCount() + 1): z = self.getMSXPatternsLengths([i]) tmplength = z - for j in range(1, tmplength[0] +1): - value[i-1][j-1] = self.msx.MSXgetpatternvalue(i, j) + for j in range(1, tmplength[0] + 1): + value[i - 1][j - 1] = self.msx.MSXgetpatternvalue(i, j) + if tmplength[0] < tmpmaxlen: - for j in range(tmplength + 1, tmpmaxlen + 1): - value[i - 1][j - 1] = value[i - 1][j - tmplength - 1] + for j in range(tmplength[0] + 1, tmpmaxlen + 1): + value[i - 1][j - 1] = value[i - 1][j - tmplength[0] - 1] return value @@ -11778,8 +11912,8 @@ def getMSXSpeciesType(self, varagin=None): """ Retrieves the species' type. Example: - d = epanet('net3-bio.inp'); - d.loadMSXFile('net3-bio.msx'); + d = epanet('net3-bio.inp') + d.loadMSXFile('net3-bio.msx') d.getMSXSpeciesType Retrieves the type of all the species. d.getMSXSpeciesType{1} Retrieves the type of the first specie. d.getMSXSpeciesType{[5,7]} Retrieves the type of the 5th and 7th specie. @@ -11806,8 +11940,8 @@ def getMSXSpeciesUnits(self, varagin=None): """ Retrieves the species' units. Example: - d = epanet('net3-bio.inp'); - d.loadMSXFile('net3-bio.msx'); + d = epanet('net3-bio.inp') + d.loadMSXFile('net3-bio.msx') d.getMSXSpeciesUnits Retrieves the units of all the species. d.getMSXSpeciesUnits{1} Retrieves the units of the first specie. d.getMSXSpeciesUnits{[1,16]} Retrieves the units of the species with @@ -11889,8 +12023,8 @@ def getMSXEquationsTerms(self): """ Retrieves equation terms. Example: - d = epanet('net2-cl2.inp'); - d.loadMSXFile('net2-cl2.msx'); + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') d.getMSXEquationsTerms() See also getMSXEquationsPipes, getMSXEquationsTanks.""" @@ -11902,8 +12036,8 @@ def getMSXEquationsPipes(self): """ Retrieves equation for pipes. Example: - d = epanet('net2-cl2.inp'); - d.loadMSXFile('net2-cl2.msx'); + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') d.getMSXEquationsPipes() See also getMSXEquationsTerms, getMSXEquationsTanks.""" @@ -11915,8 +12049,8 @@ def getMSXEquationsTanks(self): """ Retrieves equation for tanks. Example: - d = epanet('net2-cl2.inp'); - d.loadMSXfile('net2-cl2.msx'); + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') d.getMSXEquationsTanks() See also getMSXEquationsTerms, getMSXEquationsPipes.""" @@ -11938,8 +12072,8 @@ def getMSXSourceType(self, varagin=None): """ Retrieves the sources type. Example: - d = epanet('net2-cl2.inp'); - d.loadMSXFile('net2-cl2.msx'); + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') d.getMSXSourceType() Retrieves all the source types. d.getMSXSourceType{1} Retrieves the first node source type. d.getMSXSourceType{[1,2]} Retrieves the source type of nodes 1 and 2 @@ -11970,8 +12104,8 @@ def getMSXSourceLevel(self, varagin=None): """ Retrieves the sources level. Example: - d = epanet('net2-cl2.inp'); - d.loadMSXFile('net2-cl2.msx'); + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') d.getMSXSourceLevel() Retrieves all the source level. d.getMSXSourceLevel({1}) Retrieves the first node source level. d.getMSXSourceLevel([1,5]) Retrieves the source level @@ -12003,11 +12137,11 @@ def getMSXSourcePatternIndex(self, varagin=None): """ Retrieves the sources pattern index. Example: - d = epanet('net2-cl2.inp'); - d.loadMSXFile('net2-cl2.msx'); + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') d.getMSXSourcePatternIndex() Retrieves all the source pattern index. d.getMSXSourcePatternIndex({1} ) Retrieves the first node source pattern index. - d.getMSXSourcePatternIndex([1,5]]) Retrieves the source pattern index of nodes 1 and 5 + d.getMSXSourcePatternIndex([1,5]) Retrieves the source pattern index of nodes 1 and 5 See also getMSXSources, getMSXSourceNodeNameID getMSXSourceType, getMSXSourceLevel.""" @@ -12035,8 +12169,8 @@ def getMSXLinkInitqualValue(self, varagin=None): """ Retrieves the links initial quality value. Example: - d = epanet('net2-cl2.inp'); - d.loadMSXFile('net2-cl2.msx'); + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') d.getMSXLinkInitqualValue() Retrieves the initial quality of all links. d.getMSXLinkInitqualValue({1}) Retrieves the initial quality of the first link. d.getMSXLinkInitqualValue([1,3]) Retrieves the initial quality of 1 and 3. @@ -12063,8 +12197,8 @@ def getMSXNodeInitqualValue(self, varagin=None): """ Retrieves the nodes initial quality value. Example: - d = epanet('net2-cl2.inp'); - d.loadMSXFile('net2-cl2.msx'); + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') d.getMSXNodeInitqualValue() Retrieves the initial quality of all nodes. d.getMSXNodeInitqualValue({1}) Retrieves the initial quality of the first node. d.getMSXNodeInitqualValue([1,3]) Retrieves the initial quality of one and three. @@ -12091,15 +12225,15 @@ def getMSXSpeciesATOL(self): """ Retrieves the species' absolute tolerance. Example: - d = epanet('net3-bio.inp'); - d.loadMSXFile('net3-bio.msx'); + d = epanet('net3-bio.inp') + d.loadMSXFile('net3-bio.msx') d.getMSXSpeciesATOL() See also getMSXSpeciesIndex, getMSXSpeciesCount, getMSXSpeciesConcentration, getMSXSpeciesType, getMSXSpeciesNameID, getMSXSpeciesUnits, getMSXSpeciesRTOL.""" value = [] - for i in range(1, self.getMSXSpeciesCount()): + for i in range(1, self.getMSXSpeciesCount() + 1): Atol = [] value.append(self.msx.MSXgetspecies(i)) Atol.append([item[2] for item in value]) @@ -12109,25 +12243,53 @@ def getMSXSpeciesRTOL(self): """ Retrieves the species' relative accuracy level. Example: - d = epanet('net3-bio.inp'); - d.loadMSXFile('net3-bio.msx'); + d = epanet('net3-bio.inp') + d.loadMSXFile('net3-bio.msx') d.getMSXSpeciesRTOL() See also getMSXSpeciesIndex, getMSXSpeciesCount, getMSXSpeciesConcentration, getMSXSpeciesType, getMSXSpeciesNameID, getMSXSpeciesUnits, getMSXSpeciesATOL.""" value = [] - for i in range(1, self.getMSXSpeciesCount()): + for i in range(1, self.getMSXSpeciesCount() + 1): Rtol = [] value.append(self.msx.MSXgetspecies(i)) Rtol.append([item[3] for item in value]) return Rtol[0] def getMSXSpeciesConcentration(self, type, index, species): + """ Returns the node/link concentration for specific specie. + + type options: + node = 0 + link = 1 + + Example: + d = epanet('net2-cl2.inp'); + d.loadMSXFile('net2-cl2.msx'); + d.getMSXComputedQualitySpecie('CL2') + speciesIndex = d.getMSXSpeciesIndex('CL2') + d.getMSXSpeciesConcentration(0, 1, spIndex) Retrieves the CL2 concentration of the first node. + d.getMSXSpeciesConcentration(1, 1, spIndex) Retrieves the CL2 concentration of the first link. + + See also getMSXSpeciesIndex, getMSXSpeciesNameID, + getMSXSpeciesCount, getMSXSpeciesType, + getMSXSpeciesUnits, getMSXSpeciesATOL, + getMSXSpeciesRTOL.""" return self.msx.MSXgetqual(type, index, species) def getMSXSourceNodeNameID(self): - + """ Retrieves the sources node ID. + + Example: + d = epanet('net2-cl2.inp'); + d.loadMSXFile('net2-cl2.msx'); + d.getMSXSourceNodeNameID Retrieves all the source node IDs. + + + + See also getMSXSources, getMSXSourceType + getMSXSourceLevel, getMSXSourcePatternIndex.""" nodes = [] for i in range(1, self.getNodeCount() + 1): source = [] @@ -12142,70 +12304,20 @@ def getMSXSourceNodeNameID(self): source.append([item[0] for item in k]) for sublist in source: for item in sublist: - if item!='NOSOURCE': + if item != 'NOSOURCE': flag = 1 break if flag == 1: nodes.append(i) return nodes - def MSXPythonSetup(self, msxname): - - self.msxname = msxname[:-4] + '_temp.msx' - copyfile(msxname,self.msxname) - - self.msx.MSXopen(self.msxname) - - self.MSXEquationsTerms = self.getMSXEquationsTerms() - self.MSXEquationsPipes = self.getMSXEquationsPipes() - self.MSXEquationsTanks = self.getMSXEquationsTanks() - self.MSXSpeciesCount = self.getMSXSpeciesCount() - self.MSXConstantsCount = self.getMSXConstantsCount() - self.MSXParametersCount = self.getMSXParametersCount() - self.MSXPatternsCount = self.getMSXPatternsCount() - self.MSXSpeciesIndex = self.getMSXSpeciesIndex() - self.MSXSpeciesNameID = self.getMSXSpeciesNameID() - self.MSXSpeciesType = self.getMSXSpeciesType() - self.MSXSpeciesUnits = self.getMSXSpeciesUnits() - self.MSXSpeciesATOL = self.getMSXSpeciesATOL() - self.MSXSpeciesRTOL = self.getMSXSpeciesRTOL() - self.MSXConstantsNameID = self.getMSXConstantsNameID() - self.MSXConstantsValue = self.getMSXConstantsValue() - self.MSXConstantsIndex = self.getMSXConstantsIndex() - self.MSXParametersNameID = self.getMSXParametersNameID() - self.MSXParametersIndex = self.getMSXParametersIndex() - self.MSXParametersTanksValue = self.getMSXParametersTanksValue() - self.MSXParametersPipesValue = self.getMSXParametersPipesValue() - self.MSXPatternsNameID = self.getMSXPatternsNameID() - self.MSXPatternsIndex = self.getMSXPatternsIndex() - self.MSXPatternsLengths = self.getMSXPatternsLengths() - self.MSXNodeInitqualValue = self.getMSXNodeInitqualValue() - self.MSXLinkInitqualValue = self.getMSXLinkInitqualValue() - self.MSXSources = self.getMSXSources() - self.MSXSourceType = self.getMSXSourceType() - self.MSXSourceLevel = self.getMSXSourceLevel() - self.MSXSourcePatternIndex = self.getMSXSourcePatternIndex() - self.MSXSourceNodeNameID = self.getMSXSourceNodeNameID() - self.MSXPattern = self.getMSXPattern() - - #options - self.solver = self.getMSXSolver() - self.areaunits = self.getMSXAreaUnits() - self.rateunits = self.getMSXRateUnits() - self.rtol = self.getMSXRtol() - self.atol = self.getMSXAtol() - self.timestep = self.getMSXTimeStep() - self.coupling = self.getMSXCoupling() - self.compiler = self.getMSXCompiler() - def setMSXOptions(self, *args): - for i in range(len(args) // 2): argument = args[2 * i].lower() if argument == 'areaunits': self.areaunits = args[2 * i + 1] - self.changeMSXOptions("AREA_UNITS",args[2 * i + 1]) + self.changeMSXOptions("AREA_UNITS", args[2 * i + 1]) elif argument == 'rateunits': self.rateunits = args[2 * i + 1] self.changeMSXOptions("RATE_UNITS", args[2 * i + 1]) @@ -12232,94 +12344,400 @@ def setMSXOptions(self, *args): return def changeMSXOptions(self, param, change): - msxname=self.msxname + msxname = self.msxname f = open(msxname, 'r+') lines = f.readlines() + flag = 0 for i, line in enumerate(lines): - + if line.strip() == '[OPTIONS]': + options_index = i if line.startswith(param): - lines[i] = param + "\t" + str(change) + "\n" - + flag = 1 + if flag == 0: + lines = list(lines) + lines.insert(options_index + 1, param + "\t" + str(change) + "\n") f.seek(0) f.writelines(lines) f.close() def setMSXAreaUnitsCM2(self): - self.changeMSXOptions("AREA_UNITS","CM2") + """ Sets the area units to square centimeters. + + The default is FT2. + + Example: + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') + d.getMSXAreaUnits() + d.setMSXAreaUnitsCM2() + d.getMSXAreaUnits() + + See also setMSXAreaUnitsFT2, setMSXAreaUnitsM2.""" + self.changeMSXOptions("AREA_UNITS", "CM2") + def setMSXAreaUnitsFT2(self): + """ Sets the area units to square feet. + + The default is FT2. + + Example: + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') + d.getMSXAreaUnits() + d.setMSXAreaUnitsFT2() + d.getMSXAreaUnits() + + See also setMSXAreaUnitsM2, setMSXAreaUnitsCM2.""" self.changeMSXOptions("AREA_UNITS", "FT2") def setMSXAreaUnitsM2(self): + """ Sets the area units to square meters. + + The default is FT2. + + Example: + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') + d.getMSXAreaUnits() + d.setMSXAreaUnitsM2() + d.getMSXAreaUnits() + + See also setMSXAreaUnitsFT2, setMSXAreaUnitsCM2.""" self.changeMSXOptions("AREA_UNITS", "M2") def setMSXAtol(self, value): + """ Sets the absolute tolerance used to determine when two concentration levels of a + species are the same. + + If no ATOL option is specified then it defaults to 0.01 + (regardless of species concentration units). + + Example: + d = epanet('net2-cl2.inp'); + d.loadMSXFile('net2-cl2.msx'); + d.getMSXAtol() + d.setMSXAtol(2e-3); + d.getMSXAtol() + + % See also setMSXRtol.""" self.changeMSXOptions("ATOL", value) def setMSXRtol(self, value): + """Sets the relative accuracy level on a species’ concentration + used to adjust time steps in the RK5 and ROS2 integration methods. + + If no RTOL option is specified then it defaults to 0.001. + + Example: + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') + d.getMSXRtol() + d.setMSXRtol(2e-3) + d.getMSXRtol() + + See also setMSXAtol.""" self.changeMSXOptions("RTOL", value) def setMSXCompilerGC(self): + """ Sets chemistry function compiler code to GC. + + Example: + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2-vc.msx') + d.getMSXCompiler() + d.setMSXCompilerGC() + d.getMSXCompiler() + + See also setMSXCompilerNONE, setMSXCompilerVC.""" self.changeMSXOptions("COMPILER", "GC") def setMSXCompilerVC(self): + """ Sets chemistry function compiler code to VC. + + Example: + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') + d.getMSXCompiler() + d.setMSXCompilerVC() + d.getMSXCompiler() + + See also setMSXCompilerNONE, setMSXCompilerGC.""" self.changeMSXOptions("COMPILER", "VC") def setMSXCompilerNONE(self): + """ Sets chemistry function compiler code to NONE. + + Example: + d = epanet('net2-cl2.inp'); + d.loadMSXFile('net2-cl2.msx'); + d.getMSXCompiler() + d.setMSXCompilerNONE() + d.getMSXCompiler() + + See also setMSXCompilerVC, setMSXCompilerGC.""" self.changeMSXOptions("COMPILER", "NONE") def setMSXCouplingFULL(self): + """ Sets coupling to FULL. + + COUPLING determines to what degree the solution of any algebraic + equilibrium equations is coupled to the integration of the reaction + rate equations. With FULL coupling the updating is done whenever a + new set of values for the rate-dependent variables in the reaction + rate expressions is computed. The default is FULL coupling. + + Example: + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') + d.getMSXCoupling() + d.setMSXCouplingFULL() + d.getMSXCoupling() + + See also setMSXCouplingNONE.""" self.changeMSXOptions("COUPLING", "FULL") def setMSXCouplingNONE(self): + """ Sets coupling to NONE. + + COUPLING determines to what degree the solution of any algebraic + equilibrium equations is coupled to the integration of the reaction + rate equations. If coupling is NONE then the solution to the + algebraic equations is only updated at the end of each + integration time step. The default is FULL coupling. + + Example: + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') + d.getMSXCoupling() + d.setMSXCouplingFULL() + d.getMSXCoupling() + + See also setMSXCouplingFULL.""" self.changeMSXOptions("COUPLING", "NONE") def setMSXRateUnitsDAY(self): + """ Sets the rate units to days. + + The default units are hours (HR) + + Example: + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') + d.getMSXRateUnits() + d.setMSXRateUnitsDAY() + d.getMSXRateUnits() + + See also setMSXRateUnitsSEC, setMSXRateUnitsMIN + setMSXRateUnitsHR.""" self.changeMSXOptions("RATE_UNITS", "DAY") def setMSXRateUnitsHR(self): + """ Sets the rate units to hours. + + The default units are hours (HR) + + Example: + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') + d.getMSXRateUnits() + d.setMSXRateUnitsHR() + d.getMSXRateUnits() + + See also setMSXRateUnitsSEC, setMSXRateUnitsMIN + setMSXRateUnitsDAY.""" self.changeMSXOptions("RATE_UNITS", "HR") def setMSXRateUnitsMIN(self): + """ Sets the rate units to minutes. + + The default units are hours (HR) + + Example: + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') + d.getMSXRateUnits() + d.setMSXRateUnitsMIN() + d.getMSXRateUnits() + + See also setMSXRateUnitsSEC, setMSXRateUnitsHR, + setMSXRateUnitsDAY.""" self.changeMSXOptions("RATE_UNITS", "MIN") def setMSXRateUnitsSEC(self): + """ Sets the rate units to seconds. + + The default units are hours (HR) + + Example: + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') + d.getMSXRateUnits() + d.setMSXRateUnitsSEC() + d.getMSXRateUnits() + + See also setMSXRateUnitsMIN, setMSXRateUnitsHR, + setMSXRateUnitsDAY.""" self.changeMSXOptions("RATE_UNITS", "SEC") def setMSXSolverEUL(self): + """ Sets the numerical integration method to solve the reaction + system to standard Euler integrator (EUL). + + The default solver is EUL. + + Example: + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') + d.getMSXSolver() + d.setMSXSolverEUL() + d.getMSXSolver() + + See also setMSXSolverRK5, setMSXSolverROS2.""" self.changeMSXOptions("SOLVER", "EUL") def setMSXSolverRK5(self): + """ Sets the numerical integration method to solve the reaction + system to Runge-Kutta 5th order integrator (RK5). + + The default solver is EUL. + + Example: + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') + d.getMSXSolver() + d.setMSXSolverRK5() + d.getMSXSolver() + + % See also setMSXSolverEUL, setMSXSolverROS2.""" self.changeMSXOptions("SOLVER", "RK5") def setMSXSolverROS2(self): + """ Sets the numerical integration method to solve the reaction + system to 2nd order Rosenbrock integrator (ROS2). + + The default solver is EUL. + + Example: + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') + d.getMSXSolver() + d.setMSXSolverROS2() + d.getMSXSolver() + + See also setMSXSolverEUL, setMSXSolverRK5.""" self.changeMSXOptions("SOLVER", "ROS2") def setMSXTimeStep(self, value): + """ Sets the time step. + + The default timestep is 300 seconds (5 minutes). + + Example: + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') + d.getMSXTimeStep() + d.setMSXTimeStep(3600) + d.getMSXTimeStep() + + See also getMSXTimeStep.""" self.changeMSXOptions("TIMESTEP", value) def setMSXPatternValue(self, index, patternTimeStep, patternFactor): + """ Sets the pattern factor for an index for a specific time step. + + Example: + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') + d.addMSXPattern('P1', [2.0 2.0 2.0 2.0]) + d.getMSXPatternValue(1,1) + d.setMSXPatternValue(1,1,3.0) Sets the first timestep of the first pattern to 3.0. + d.getMSXPatternValue(1,1) + + See also getMSXPatternValue, getMSXPattern, addMSXPattern.""" self.msx.MSXsetpatternvalue(index, patternTimeStep, patternFactor) def setMSXPattern(self, index, patternVector): + """ Sets the multiplier at a specific time period for a given pattern. + + Example: + d = epanet('net2-cl2.inp') + d.loadMSXFile('net2-cl2.msx') + d.addMSXPattern('Pl', [1.0 2.0 1.5 1.0]) + d.getMSXPattern() + d.setMSXPattern(1, [1.0 0.0 3.0]); + d.getMSXPattern() + + See also getMSXPattern, addMSXPattern.""" nfactors = len(patternVector) self.msx.MSXsetpattern(index, patternVector, nfactors) def setMSXParametersTanksValue(self, NodeTankIndex, paramindex, value): + """Assigns a value to a particular reaction parameter for a given tank within the pipe network. + + Example: + d = epanet('net2-cl2.inp'); + d.loadMSXFile('net2-cl2.msx'); + x=d.getMSXParametersTanksValue() + print(x[96]) + d.setMSXParametersTanksValue(97,1,5) + x=d.getMSXParametersTanksValue() + print(x[96]) + See also getMSXParametersTanksValue, setMSXParametersPipesValue, + getMSXParametersPipesValue, getMSXParametersCount, + getMSXParametersIndex.""" self.msx.MSXsetparameter(0, NodeTankIndex, paramindex, value) def setMSXParametersPipesValue(self, pipeIndex, value): + """Assigns a value to a particular reaction parameter + for a given pipe within the pipe network. + + Example: + d = epanet('net2-cl2.inp'); + d.loadMSXFile('net2-cl2.msx'); + x=d.getMSXParametersPipesValue() + print(x[1]) + d.setMSXParametersPipesValue(1,[1.5 , 2]) + x=d.getMSXParametersPipesValue() + print(x[0]) + See also getMSXParametersPipesValue, setMSXParametersTanksValue, + getMSXParametersTanksValue, getMSXParametersCount, + getMSXParametersIndex.""" for i in range(len(value)): - self.msx.MSXsetparameter(1, pipeIndex, i+1, value[i]) + self.msx.MSXsetparameter(1, pipeIndex, i + 1, value[i]) def setMSXConstantsValue(self, value): + """ Sets the values of constants. + + Example: + d = epanet('net3-bio.inp') + d.loadMSXFile('net3-bio.msx') + d.getMSXConstantsValue() + d.setMSXConstantsValue([1, 2, 3]) Set the values of the first three constants. + d.getMSXConstantsValue() + + See also getMSXConstantsCount, getMSXConstantsIndex, + getMSXConstantsNameID.""" for i in range(len(value)): - self.msx.MSXsetconstant(i+1, value[i]) + self.msx.MSXsetconstant(i + 1, value[i]) - def addMSXpattern(self, *args): + def addMSXPattern(self, *args): + """ Adds new time pattern + + Example: + d = epanet('net2-cl2.inp'); + d.loadMSXFile('net2-cl2.msx'); + print(d.getMSXPatternsNameID()) + mult = [0.5, 0.8, 1.2, 1.0, 0.7, 0.3] + d.addMSXPattern('Pattern1', mult) + print(d.getMSXPattern()) + print(d.getMSXPatternsNameID()) + + See also getMSXPattern, setMSXPattern.""" index = -1 MSX_PATTERN = self.ToolkitConstants.MSX_PATTERN if len(args) == 1: + self.msx.MSXaddpattern(args[0]) index = self.msx.MSXgetindex(MSX_PATTERN, args[0]) elif len(args) == 2: @@ -12332,12 +12750,12 @@ def getMSXComputedQualitySpecie(self, *args): if self.getMSXSpeciesCount() == 0: return 0 if not args: - specie = self.getMSXspeciesNameID() + specie = self.getMSXSpeciesNameID() else: specie = args[0] - link_indices = range(1, self.getLinkCount() + 1) - node_indices = range(1, self.getNodeCount() + 1) + link_indices = np.arange(1, self.getLinkCount() + 1) + node_indices = np.arange(1, self.get_node_count() + 1) speciename = self.getMSXSpeciesIndex(specie) node_quality = np.empty((1, len(node_indices), len(speciename))) @@ -12354,7 +12772,7 @@ def getMSXComputedQualitySpecie(self, *args): for i in range(len(speciename)): for lnk in link_indices: print(lnk) - link_quality[k, lnk - 1, i] = self.getMSXLinkInitqualValue([lnk])[(speciename)[1]] + link_quality[k, lnk - 1, i] = self.getMSXNodeInitqualValue([lnk])[speciename[i]] if lnk < node_indices[-1] + 1: node_quality[k, lnk - 1, i] = self.getMSXNodeInitqualValue([lnk])[speciename[i]] else: @@ -12362,7 +12780,7 @@ def getMSXComputedQualitySpecie(self, *args): for lnk in node_indices: node_quality[k, lnk - 1, i] = self.MSXNodeInitqualValue([lnk])[speciename[i]] if lnk < link_indices[-1] + 1: - link_quality[k, lnk - 1, i]= self.getMSXLinkInitqualValue([lnk])[speciename[i]] + link_quality[k, lnk - 1, i] = self.getMSXLinkInitqualValue([lnk])[speciename[i]] time_sim = self.getTimeSimulationDuration() while tleft > 0 and time_sim != t: k = k + 1 @@ -12370,7 +12788,7 @@ def getMSXComputedQualitySpecie(self, *args): for i in range(len(speciename)): if node_indices[-1] < link_indices[-1]: for lnk in link_indices: - link_quality[k, lnk -1, i] = self.getMSXSpeciesConcentration(1, lnk, speciename[i]) + link_quality[k, lnk - 1, i] = self.getMSXSpeciesConcentration(1, lnk, speciename[i]) if lnk < node_indices[-1] + 1: node_quality[k, lnk - 1, i] = self.getMSXSpeciesConcentration(0, lnk, speciename[i]) else: @@ -12379,7 +12797,7 @@ def getMSXComputedQualitySpecie(self, *args): if lnk < link_indices[-1] + 1: link_quality[k, lnk - 1, i] = self.getMSXSpeciesConcentration(1, lnk, speciename[i]) time.append(t) - return {'NodeQuality': node_quality, 'LinkQuality': link_quality, 'Time' : np.array(time)} + return {'NodeQuality': node_quality, 'LinkQuality': link_quality, 'Time': np.array(time)} class epanetapi: @@ -12403,15 +12821,11 @@ def __init__(self, version=2.2, msx=False): self.binfile = None # Check platform and Load epanet library - libname = f"epanet{str(version).replace('.', '_')}" + # libname = f"epanet{str(version).replace('.', '_')}" + libname = f"epanet2" ops = platform.system().lower() if ops in ["windows"]: - if "32" in str(platform.architecture()): - self.LibEPANET = resource_filename("epyt", os.path.join("libraries", "win", libname, '32bit', - f"{libname[:-2]}.dll")) - elif "64" in str(platform.architecture()): - self.LibEPANET = resource_filename("epyt", os.path.join("libraries", "win", libname, '64bit', - f"{libname[:-2]}.dll")) + self.LibEPANET = resource_filename("epyt", os.path.join("libraries", "win", f"{libname}.dll")) elif ops in ["darwin"]: self.LibEPANET = resource_filename("epyt", os.path.join("libraries", f"mac/lib{libname}.dylib")) else: @@ -12420,10 +12834,8 @@ def __init__(self, version=2.2, msx=False): self._lib = cdll.LoadLibrary(self.LibEPANET) self.LibEPANETpath = os.path.dirname(self.LibEPANET) - if float(version) >= 2.2 and '64' in str(platform.architecture()) and not msx: + if float(version) >= 2.2 and not msx: self._ph = c_uint64() - elif float(version) >= 2.2 and not msx: - self._ph = c_uint32() else: self._ph = None @@ -13008,13 +13420,14 @@ def ENgetcurve(self, index): """ out_id = create_string_buffer(self.EN_MAXID) nPoints = c_int() - xValues = (c_double * self.ENgetcurvelen(index))() - yValues = (c_double * self.ENgetcurvelen(index))() - if self._ph is not None: + xValues = (c_double * self.ENgetcurvelen(index))() + yValues = (c_double * self.ENgetcurvelen(index))() self.errcode = self._lib.EN_getcurve(self._ph, index, byref(out_id), byref(nPoints), byref(xValues), byref(yValues)) else: + xValues = (c_float * self.ENgetcurvelen(index))() + yValues = (c_float * self.ENgetcurvelen(index))() self.errcode = self._lib.ENgetcurve(index, byref(out_id), byref(nPoints), byref(xValues), byref(yValues)) @@ -13133,12 +13546,13 @@ def ENgetcurvevalue(self, index, period): x the point's x-value. y the point's y-value. """ - x = c_double() - y = c_double() - if self._ph is not None: + x = c_double() + y = c_double() self.errcode = self._lib.EN_getcurvevalue(self._ph, int(index), period, byref(x), byref(y)) else: + x = c_float() + y = c_float() self.errcode = self._lib.ENgetcurvevalue(int(index), period, byref(x), byref(y)) self.ENgeterror() @@ -13436,11 +13850,12 @@ def ENgetlinkvalue(self, index, paramcode): OWA-EPANET Toolkit: http://wateranalytics.org/EPANET/group___links.html """ - fValue = c_double() if self._ph is not None: + fValue = c_double() self.errcode = self._lib.EN_getlinkvalue(self._ph, int(index), paramcode, byref(fValue)) else: + fValue = c_float() self.errcode = self._lib.ENgetlinkvalue(int(index), paramcode, byref(fValue)) self.ENgeterror() @@ -13658,11 +14073,11 @@ def ENgetpatternvalue(self, index, period): Returns: value the pattern factor for the given time period. """ - value = c_double() - if self._ph is not None: + value = c_double() self.errcode = self._lib.EN_getpatternvalue(self._ph, int(index), period, byref(value)) else: + value = c_float() self.errcode = self._lib.ENgetpatternvalue(int(index), period, byref(value)) self.ENgeterror() @@ -14152,8 +14567,6 @@ def ENopen(self, inpname=None, repname=None, binname=None): if self._ph is not None: self._lib.EN_createproject(byref(self._ph)) - - if self._ph is not None: self.errcode = self._lib.EN_open(self._ph, self.inpfile, self.rptfile, self.binfile) else: self.errcode = self._lib.ENopen(self.inpfile, self.rptfile, self.binfile) @@ -14710,7 +15123,7 @@ def ENsetlinkvalue(self, index, paramcode, value): c_double(value)) else: self.errcode = self._lib.ENsetlinkvalue(c_int(index), c_int(paramcode), - c_double(value)) + c_float(value)) self.ENgeterror() return @@ -14791,7 +15204,7 @@ def ENsetpattern(self, index, factors, nfactors): if self._ph is not None: self.errcode = self._lib.EN_setpattern(self._ph, int(index), (c_double * nfactors)(*factors), nfactors) else: - self.errcode = self._lib.ENsetpattern(int(index), (c_double * nfactors)(*factors), + self.errcode = self._lib.ENsetpattern(int(index), (c_float * nfactors)(*factors), nfactors) self.ENgeterror() @@ -15238,61 +15651,46 @@ def ENwriteline(self, line): class epanetmsxapi: """example msx = epanetmsxapi()""" - def __init__(self, filename=None): - ops = platform.system().lower() - if ops in ["windows"]: - dll_path1 = resource_filename("epyt", os.path.join("libraries", "win", 'epanet2_2', '64bit', - f"epanetmsx.dll")) - elif ops in ["darwin"]: - dll_path1 = resource_filename("epyt", os.path.join("libraries", "mac", 'epanet2_2', '64bit', - f"epanetmsx.dll")) - else: - dll_path1 = resource_filename("epyt", os.path.join("libraries", "glnx", 'epanet2_2', '64bit', - f"epanetmsx.dll")) - - self.msx_lib = cdll.LoadLibrary(dll_path1) - # msx opens starts here - if filename is not None: - """ Open .msx file - msx.MSXopen(filename) - msx.MSXopen(Arsenite.msx)""" - """ filename example : Arsinite.msx or use full path """ - print("Opening MSX file:", filename) - if not os.path.exists(filename): - raise FileNotFoundError(f"File not found: {filename}") - - filename = c_char_p(filename.encode('utf-8')) - err = self.msx_lib.MSXopen(filename) - if err != 0: - self.MSXerror(err) - if err == 503: - print("Error 503 may indicate a problem with the MSX file or the MSX library.") + def __init__(self, msxfile='', loadlib=True, ignore_msxfile=False): + if loadlib: + ops = platform.system().lower() + if ops in ["windows"]: + self.MSXLibEPANET = resource_filename("epyt", os.path.join("libraries", "win", "epanetmsx.dll")) + elif ops in ["darwin"]: + self.MSXLibEPANET = resource_filename("epyt", os.path.join("libraries", "mac", "epanetmsx.dylib")) else: - print("MSX file opened successfully.") - # msx open ends here - - # Error ~ function - self.msx_error = self.msx_lib.MSXgeterror - self.msx_error.argtypes = [c_int, c_char_p, c_int] - - def MSXopen(self, filename): - """ Open .msx file - msx.MSXopen(filename) - msx.MSXopen(Arsenite.msx)""" - """ filename example : Arsinite.msx or use full path """ - print("Opening MSX file:", filename) - if not os.path.exists(filename): - raise FileNotFoundError(f"File not found: {filename}") - - filename = c_char_p(filename.encode('utf-8')) - err = self.msx_lib.MSXopen(filename) + self.MSXLibEPANET = resource_filename("epyt", os.path.join("libraries", "glnx", "epanetmsx.so")) + + self.msx_lib = cdll.LoadLibrary(self.MSXLibEPANET) + self.MSXLibEPANETPath = os.path.dirname(self.MSXLibEPANET) + + self.msx_error = self.msx_lib.MSXgeterror + self.msx_error.argtypes = [c_int, c_char_p, c_int] + + if not ignore_msxfile: + self.MSXopen(msxfile) + + def MSXopen(self, msxfile): + """ + Open MSX file + filename - Arsenite.msx or use full path + + Example: + msx.MSXopen(filename) + msx.MSXopen(Arsenite.msx) + """ + if not os.path.exists(msxfile): + raise FileNotFoundError(f"File not found: {msxfile}") + + print("Opening MSX file:", msxfile) + msxbasename = os.path.basename(msxfile) + err = self.msx_lib.MSXopen(c_char_p(msxfile.encode('utf-8'))) if err != 0: self.MSXerror(err) if err == 503: print("Error 503 may indicate a problem with the MSX file or the MSX library.") else: - print("MSX file opened successfully.") - # msx open ends here + print(f"MSX file {msxbasename} loaded successfully.") def MSXclose(self): """ Close .msx file diff --git a/epyt/libraries/glnx/epanetmsx b/epyt/libraries/glnx/epanetmsx deleted file mode 100644 index c02afe4..0000000 Binary files a/epyt/libraries/glnx/epanetmsx and /dev/null differ diff --git a/epyt/libraries/glnx/epanetmsx.so b/epyt/libraries/glnx/epanetmsx.so index 6e66934..bb761b5 100644 Binary files a/epyt/libraries/glnx/epanetmsx.so and b/epyt/libraries/glnx/epanetmsx.so differ diff --git a/epyt/libraries/glnx/libepanet2.so b/epyt/libraries/glnx/libepanet2.so new file mode 100644 index 0000000..8e9d341 Binary files /dev/null and b/epyt/libraries/glnx/libepanet2.so differ diff --git a/epyt/libraries/glnx/libepanet2_2 b/epyt/libraries/glnx/libepanet2_2 deleted file mode 100644 index 78f3110..0000000 Binary files a/epyt/libraries/glnx/libepanet2_2 and /dev/null differ diff --git a/epyt/libraries/glnx/libepanet2_2.so b/epyt/libraries/glnx/libepanet2_2.so deleted file mode 100644 index d0da2ba..0000000 Binary files a/epyt/libraries/glnx/libepanet2_2.so and /dev/null differ diff --git a/epyt/libraries/mac/epanetmsx.dylib b/epyt/libraries/mac/epanetmsx.dylib new file mode 100644 index 0000000..e691a67 Binary files /dev/null and b/epyt/libraries/mac/epanetmsx.dylib differ diff --git a/epyt/libraries/mac/libepanet2.dylib b/epyt/libraries/mac/libepanet2.dylib new file mode 100644 index 0000000..5a458dd Binary files /dev/null and b/epyt/libraries/mac/libepanet2.dylib differ diff --git a/epyt/libraries/mac/libepanet2_2 b/epyt/libraries/mac/libepanet2_2 deleted file mode 100644 index 78f3110..0000000 Binary files a/epyt/libraries/mac/libepanet2_2 and /dev/null differ diff --git a/epyt/libraries/mac/libepanet2_2.dylib b/epyt/libraries/mac/libepanet2_2.dylib deleted file mode 100644 index 1f6813f..0000000 Binary files a/epyt/libraries/mac/libepanet2_2.dylib and /dev/null differ diff --git a/epyt/libraries/win/epanet2_2/64bit/epanet2.dll b/epyt/libraries/win/epanet2.dll similarity index 100% rename from epyt/libraries/win/epanet2_2/64bit/epanet2.dll rename to epyt/libraries/win/epanet2.dll diff --git a/epyt/libraries/win/epanet2_2/64bit/epanet2.exe b/epyt/libraries/win/epanet2.exe similarity index 100% rename from epyt/libraries/win/epanet2_2/64bit/epanet2.exe rename to epyt/libraries/win/epanet2.exe diff --git a/epyt/libraries/win/epanet2_2/32bit/epanet2.dll b/epyt/libraries/win/epanet2_2/32bit/epanet2.dll deleted file mode 100644 index 1828580..0000000 Binary files a/epyt/libraries/win/epanet2_2/32bit/epanet2.dll and /dev/null differ diff --git a/epyt/libraries/win/epanet2_2/32bit/epanet2.exe b/epyt/libraries/win/epanet2_2/32bit/epanet2.exe deleted file mode 100644 index c48b134..0000000 Binary files a/epyt/libraries/win/epanet2_2/32bit/epanet2.exe and /dev/null differ diff --git a/epyt/libraries/win/epanet2_2/64bit/epanetmsx.dll b/epyt/libraries/win/epanet2_2/64bit/epanetmsx.dll deleted file mode 100644 index e48ed3d..0000000 Binary files a/epyt/libraries/win/epanet2_2/64bit/epanetmsx.dll and /dev/null differ diff --git a/epyt/libraries/win/epanetmsx.dll b/epyt/libraries/win/epanetmsx.dll new file mode 100644 index 0000000..939b31f Binary files /dev/null and b/epyt/libraries/win/epanetmsx.dll differ diff --git a/epyt/libraries/win/epanet2_2/64bit/epanetmsx.exe b/epyt/libraries/win/epanetmsx.exe similarity index 100% rename from epyt/libraries/win/epanet2_2/64bit/epanetmsx.exe rename to epyt/libraries/win/epanetmsx.exe diff --git a/epyt/tests/net1_unit_test.py b/epyt/tests/net1_unit_test.py index 6f62f36..bdbbb92 100644 --- a/epyt/tests/net1_unit_test.py +++ b/epyt/tests/net1_unit_test.py @@ -191,7 +191,7 @@ def testStepByStepAnalysis(self): 9.452347598503036e-07, 9.28221894076609e-07, 9.084721628771827e-07, 2.416368471024177, 2.4073945733540967, 2.3857323225219194]) - np.testing.assert_array_almost_equal(velocity, v_desired, err_msg="Wrong Velocity output") + np.testing.assert_array_almost_equal(velocity, v_desired, decimal=3, err_msg="Wrong Velocity output") h_desired = np.array( [19.117018607743262, 18.784557106294415, 18.575821630530413, 18.350323106559813, 18.247536420722895, 18.125096976393024, 18.12282340051479, 18.099494697653654, 17.95951292501252, 17.843745116056084, @@ -202,9 +202,9 @@ def testStepByStepAnalysis(self): 2.637534635141492e-11, 2.5352164811920375e-11, 20.08353269330769, 19.945617762391066, 19.61450487894149]) - np.testing.assert_array_almost_equal(head_loss, h_desired, err_msg="Wrong HeadLoss output") - f_desired = [np.array(1866.17582999), np.array(1848.5811499), np.array(1837.46107838)] - np.testing.assert_array_almost_equal(flow[0:3], f_desired, err_msg="Wrong Flows output") + np.testing.assert_array_almost_equal(head_loss, h_desired, decimal=3, err_msg="Wrong HeadLoss output") + f_desired = [np.array(1866.17578125), np.array(1848.58117676), np.array(1837.46105957)] + np.testing.assert_array_almost_equal(flow[0:3], f_desired, decimal=3, err_msg="Wrong Flows output") """ ------------------------------------------------------------------------- """ @@ -274,20 +274,21 @@ def testSetLinkRoughnessCoefficientIndex(self): def testSetLinkMinorLossCoefficientAll(self): self.epanetClass.setLinkMinorLossCoeff([1.2 for _ in self.epanetClass.getLinkMinorLossCoeff()]) - assert all(self.epanetClass.getLinkMinorLossCoeff() == [1.2, 1.2000000000000002, 1.2000000000000002, - 1.2000000000000002, 1.2, 1.2, - 1.2, 1.2000000000000002, 1.2, 1.2, 1.2, 1.2, - 0.0]), "Wrong set minor loss output" + expected_values = [1.2, 1.2000000000000002, 1.2000000000000002, 1.2000000000000002, 1.2, 1.2, + 1.2, 1.2000000000000002, 1.2, 1.2, 1.2, 1.2, 0.0] + actual_values = self.epanetClass.getLinkMinorLossCoeff() + assert np.isclose(actual_values, expected_values).all(), "Wrong set minor loss output" def testSetLinkMinorLossCoefficientIndices(self): - self.epanetClass.setLinkMinorLossCoeff([2, 3, 4], [1.01, 1.02, 1.01]) # index, value - assert all(self.epanetClass.getLinkMinorLossCoeff([2, 3, 4]) == [1.01, 1.02, - 1.01]), "Wrong set minor loss output" + expected_values = [1.01, 1.02, 1.01] + self.epanetClass.setLinkMinorLossCoeff([2, 3, 4], expected_values) # index, value + actual_values = self.epanetClass.getLinkMinorLossCoeff([2, 3, 4]) + for expected, actual in zip(expected_values, actual_values): + self.assertAlmostEqual(expected, actual, places=2, msg="Wrong set minor loss output") def testSetLinkMinorLossCoefficientIndex(self): self.epanetClass.setLinkMinorLossCoeff(2, 1.01) # index, value - assert self.epanetClass.getLinkMinorLossCoeff(2) == 1.01, "Wrong set minor loss output" - + assert np.isclose(self.epanetClass.getLinkMinorLossCoeff(2), 1.01, atol=1e-6), "Wrong set minor loss output" """ ------------------------------------------------------------------------- """ def testSetLinkInitialStatusAll(self): @@ -306,28 +307,35 @@ def testSetLinkInitialStatusIndex(self): def testSetLinkBulkReactionCoefficientAll(self): self.epanetClass.setLinkBulkReactionCoeff([i - 0.055 for i in self.epanetClass.getLinkBulkReactionCoeff()]) - assert all( - self.epanetClass.getLinkBulkReactionCoeff() == [-0.555, -0.555, -0.555, -0.555, -0.555, -0.555, -0.555, - -0.555, -0.555, -0.555, -0.555, -0.555, - 0.0]), "Wrong set link bulk reaction output" + + def assert_almost_equal(actual, expected, tolerance, message): + for a, e in zip(actual, expected): + assert abs(a - e) <= tolerance, message + + expected_values = [-0.555, -0.555, -0.555, -0.555, -0.555, -0.555, -0.555, + -0.555, -0.555, -0.555, -0.555, -0.555, 0.0] + actual_values = self.epanetClass.getLinkBulkReactionCoeff() + assert_almost_equal(actual_values, expected_values, tolerance=1e-3, message="Wrong set link bulk reaction " + "output") def testSetLinkBulkReactionCoefficientIndices(self): self.epanetClass.setLinkBulkReactionCoeff([2, 3, 13], [0.1] * 3) # index, value - assert all(self.epanetClass.getLinkBulkReactionCoeff([2, 3, 13]) == [0.1, 0.1, - 0.0]), "Wrong set link bulk reaction " \ - "output" + expected_values = np.array([0.1, 0.1, 0.0]) + actual_values = self.epanetClass.getLinkBulkReactionCoeff([2, 3, 13]) + assert np.isclose(actual_values, expected_values).all(), "Wrong set link bulk reaction output" def testSetLinkBulkReactionCoefficientIndex(self): self.epanetClass.setLinkBulkReactionCoeff(1, 0.2) # index, value - assert self.epanetClass.getLinkBulkReactionCoeff(1) == 0.2, "Wrong set link bulk reaction output" + assert np.isclose(self.epanetClass.getLinkBulkReactionCoeff(1), + 0.2).all(), "Wrong set link bulk reaction output" """ ------------------------------------------------------------------------- """ def testSetLinkWallReactionCoefficientAll(self): self.epanetClass.setLinkWallReactionCoeff([i * (-1.1) for i in self.epanetClass.getLinkWallReactionCoeff()]) - assert all(self.epanetClass.getLinkWallReactionCoeff() == [1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, - 1.1, 1.1, - 0.0]), "Wrong set link wall reaction output" + expected_values = [1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 0.0] + actual_values = self.epanetClass.getLinkWallReactionCoeff() + assert np.isclose(actual_values, expected_values).all(), "Wrong set link wall reaction output" def testSetLinkWallReactionCoefficientIndices(self): self.epanetClass.setLinkWallReactionCoeff([2, 3, 13], [-2] * 3) # index, value diff --git a/epyt/tests/testMSXunit.py b/epyt/tests/test_unit_MSX.py similarity index 52% rename from epyt/tests/testMSXunit.py rename to epyt/tests/test_unit_MSX.py index 6c01d30..fb04820 100644 --- a/epyt/tests/testMSXunit.py +++ b/epyt/tests/test_unit_MSX.py @@ -1,18 +1,19 @@ -from epyt.epanet import epanet, epanetmsxapi -import numpy as np +from epyt import epanet, networks import unittest import os +DIRNAME = os.path.dirname(networks.__file__) + class MSXtest(unittest.TestCase): def setUp(self): """Call before every test case.""" # Create EPANET object using the INP file - inpname = os.path.join(os.getcwd(), 'epyt', 'networks', 'msx-examples', 'Net3-NH2CL.inp') + inpname = os.path.join(DIRNAME, 'msx-examples', 'Net3-NH2CL.inp') + msxfile = os.path.join(DIRNAME, 'msx-examples', 'Net3-NH2CL.msx') self.epanetClass = epanet(inpname, msx=True) - file_path = os.path.join(os.getcwd(), 'epyt', 'networks', 'msx-examples', 'Net3-NH2CL.msx') - self.msxClass = epanetmsxapi(file_path) + self.msxClass = self.epanetClass.loadMSXFile(msxfile) def tearDown(self): """Call after every test case.""" @@ -22,14 +23,14 @@ def tearDown(self): """ ------------------------------------------------------------------------- """ def test_MSXgetsource(self): - self.assertEqual(self.msxClass.MSXgetsource(1, 14), - ('SETPOINT', 2.0, 0), 'Wrong source comment output') - self.assertEqual(self.msxClass.MSXgetsource(2, 1), - ('CONCEN', 0.8, 0), 'Wrong source comment output') - self.assertEqual(self.msxClass.MSXgetsource(3, 2), - ('MASS', 0.5, 0), 'Wrong source comment output') - self.assertEqual(self.msxClass.MSXgetsource(4, 3), - ('FLOWPACED', 4.5, 0), 'Wrong source comment output') + self.assertEqual(self.msxClass.MSXgetsource(1, 14), + ('SETPOINT', 2.0, 0), 'Wrong source comment output') + self.assertEqual(self.msxClass.MSXgetsource(2, 1), + ('CONCEN', 0.8, 0), 'Wrong source comment output') + self.assertEqual(self.msxClass.MSXgetsource(3, 2), + ('MASS', 0.5, 0), 'Wrong source comment output') + self.assertEqual(self.msxClass.MSXgetsource(4, 3), + ('FLOWPACED', 4.5, 0), 'Wrong source comment output') def test_MSXsetsource(self): self.msxClass.MSXsetsource(1, 1, -1, 10.565, 1) @@ -51,6 +52,7 @@ def test_MSXsetsource(self): self.msxClass.MSXsetsource(1, 1, 3, 10, 1) self.assertEqual(self.msxClass.MSXgetsource(1, 1), ('FLOWPACED', 10, 1), 'Wrong source comment output') + def test_MSXgetspecies(self): self.assertEqual(self.msxClass.MSXgetspecies(1), ('BULK', 'MMOL', 1.0e-8, 0.0001), 'Wrong species comment output') @@ -63,154 +65,149 @@ def test_MSXgetspecies(self): self.assertEqual(self.msxClass.MSXgetspecies(5), ('BULK', 'MMOL', 1.0e-8, 0.0001), 'Wrong species comment output') - def test_MSXgetconstant(self): - self.assertEqual(self.msxClass.MSXgetconstant(1), 0.02, + self.assertEqual(self.msxClass.MSXgetconstant(1), 0.02, 'Wrong constant comment output') - self.assertEqual(self.msxClass.MSXgetconstant(2), 0.50, + self.assertEqual(self.msxClass.MSXgetconstant(2), 0.50, 'Wrong constant comment output') - def test_MSXsetconstant(self): - # set an integer value - self.msxClass.MSXsetconstant(1, 69) - self.assertEqual(self.msxClass.MSXgetconstant(1), 69, - 'Wrong set/get constant comment output') - # set a float value - self.msxClass.MSXsetconstant(1, 69.420) - self.assertEqual(self.msxClass.MSXgetconstant(1), 69.420, - 'Wrong set/get constant comment output') + # set an integer value + self.msxClass.MSXsetconstant(1, 69) + self.assertEqual(self.msxClass.MSXgetconstant(1), 69, + 'Wrong set/get constant comment output') + # set a float value + self.msxClass.MSXsetconstant(1, 69.420) + self.assertEqual(self.msxClass.MSXgetconstant(1), 69.420, + 'Wrong set/get constant comment output') def testMSXgetinitqual(self): - self.assertEqual(self.msxClass.MSXgetinitqual(1, 1, 9), 2.818e-08, - 'Wrong get init qual comment output') - self.assertEqual(self.msxClass.MSXgetinitqual(1, 1, 10), 3.55e-7, - 'Wrong get init qual comment output') - self.assertEqual(self.msxClass.MSXgetinitqual(1, 1, 8), 0.004, - 'Wrong get init qual comment output') - self.assertEqual(self.msxClass.MSXgetinitqual(0, 1, 9), 2.818e-08, - 'Wrong get init qual comment output') - self.assertEqual(self.msxClass.MSXgetinitqual(0, 1, 10), 3.55e-7, - 'Wrong get init qual comment output') - self.assertEqual(self.msxClass.MSXgetinitqual(0, 1, 8), 0.004, - 'Wrong get init qual comment output') + self.assertEqual(self.msxClass.MSXgetinitqual(1, 1, 9), 2.818e-08, + 'Wrong get init qual comment output') + self.assertEqual(self.msxClass.MSXgetinitqual(1, 1, 10), 3.55e-7, + 'Wrong get init qual comment output') + self.assertEqual(self.msxClass.MSXgetinitqual(1, 1, 8), 0.004, + 'Wrong get init qual comment output') + self.assertEqual(self.msxClass.MSXgetinitqual(0, 1, 9), 2.818e-08, + 'Wrong get init qual comment output') + self.assertEqual(self.msxClass.MSXgetinitqual(0, 1, 10), 3.55e-7, + 'Wrong get init qual comment output') + self.assertEqual(self.msxClass.MSXgetinitqual(0, 1, 8), 0.004, + 'Wrong get init qual comment output') def testMSXsetinitqual(self): - # set value as integer testMSXsetinitqual - self.msxClass.MSXsetinitqual(1, 1, 1, 69) - self.assertEqual(self.msxClass.MSXgetinitqual(1, 1, 1), 69, - 'Wrong set/get init qual comment output') - # set value as float testMSXsetinitqual - self.msxClass.MSXsetinitqual(1, 1, 1, 69.420) - self.assertEqual(self.msxClass.MSXgetinitqual(1, 1, 1), 69.420, - 'Wrong set/get init qual comment output') + # set value as integer testMSXsetinitqual + self.msxClass.MSXsetinitqual(1, 1, 1, 69) + self.assertEqual(self.msxClass.MSXgetinitqual(1, 1, 1), 69, + 'Wrong set/get init qual comment output') + # set value as float testMSXsetinitqual + self.msxClass.MSXsetinitqual(1, 1, 1, 69.420) + self.assertEqual(self.msxClass.MSXgetinitqual(1, 1, 1), 69.420, + 'Wrong set/get init qual comment output') def test_MSXsetinitqual(self): - #set value as integer test_MSXsetinitqual - self.msxClass.MSXsetinitqual(1,1,1,69) - self.assertEqual(self.msxClass.MSXgetinitqual(1, 1, 1), 69, - 'Wrong set/get init qual comment output') - #set value as float test_MSXsetinitqual - self.msxClass.MSXsetinitqual(1, 1, 1, 69.420) - self.assertEqual(self.msxClass.MSXgetinitqual(1, 1, 1), 69.420, - 'Wrong set/get init qual comment output') + # set value as integer test_MSXsetinitqual + self.msxClass.MSXsetinitqual(1, 1, 1, 69) + self.assertEqual(self.msxClass.MSXgetinitqual(1, 1, 1), 69, + 'Wrong set/get init qual comment output') + # set value as float test_MSXsetinitqual + self.msxClass.MSXsetinitqual(1, 1, 1, 69.420) + self.assertEqual(self.msxClass.MSXgetinitqual(1, 1, 1), 69.420, + 'Wrong set/get init qual comment output') def test_MSXsetpatternvalue(self): - #set value as integer test_MSXsetpatternvalue - self.msxClass.MSXsetpatternvalue(1,1,69) - self.assertEqual(self.msxClass.MSXgetpatternvalue(1, 1), 69, - 'Wrong set/get patternvalue comment output') - #set value as float test_MSXsetpatternvalue - self.msxClass.MSXsetpatternvalue(1, 1, 69.420) - self.assertEqual(self.msxClass.MSXgetpatternvalue(1, 1), 69.420, - 'Wrong set/get init patternvalue comment output') - + # set value as integer test_MSXsetpatternvalue + self.msxClass.MSXsetpatternvalue(1, 1, 69) + self.assertEqual(self.msxClass.MSXgetpatternvalue(1, 1), 69, + 'Wrong set/get patternvalue comment output') + # set value as float test_MSXsetpatternvalue + self.msxClass.MSXsetpatternvalue(1, 1, 69.420) + self.assertEqual(self.msxClass.MSXgetpatternvalue(1, 1), 69.420, + 'Wrong set/get init patternvalue comment output') def test_MSXgetIDlen(self): - self.assertEqual(self.msxClass.MSXgetIDlen(3, 1), 4, - 'Wrong get ID len comment output') - self.assertEqual(self.msxClass.MSXgetIDlen(3, 2), 3, - 'Wrong get ID len comment output') - self.assertEqual(self.msxClass.MSXgetIDlen(3, 3), 5, - 'Wrong get ID len comment output') + self.assertEqual(self.msxClass.MSXgetIDlen(3, 1), 4, + 'Wrong get ID len comment output') + self.assertEqual(self.msxClass.MSXgetIDlen(3, 2), 3, + 'Wrong get ID len comment output') + self.assertEqual(self.msxClass.MSXgetIDlen(3, 3), 5, + 'Wrong get ID len comment output') def test_MSXgetID(self): - self.assertEqual(self.msxClass.MSXgetID(3, 1,4), 'HOCL', - 'Wrong get ID comment output') - self.assertEqual(self.msxClass.MSXgetID(3, 2,3), 'NH3', - 'Wrong get ID comment output') - self.assertEqual(self.msxClass.MSXgetID(3, 3,5), 'NH2CL', - 'Wrong get ID comment output') - + self.assertEqual(self.msxClass.MSXgetID(3, 1, 4), 'HOCL', + 'Wrong get ID comment output') + self.assertEqual(self.msxClass.MSXgetID(3, 2, 3), 'NH3', + 'Wrong get ID comment output') + self.assertEqual(self.msxClass.MSXgetID(3, 3, 5), 'NH2CL', + 'Wrong get ID comment output') def test_MSXgeterror(self): - self.assertEqual(self.msxClass.MSXgeterror(516), 'Error 516 - reference made to an illegal object index.', - 'Wrong error comment output') - self.assertEqual(self.msxClass.MSXgeterror(505), 'Error 505 - could not read hydraulic results file.', - 'Wrong error comment output') - self.assertEqual(self.msxClass.MSXgeterror(503), 'Error 503 - could not open MSX input file.', - 'Wrong error comment output') - + self.assertEqual(self.msxClass.MSXgeterror(516), 'Error 516 - reference made to an illegal object index.', + 'Wrong error comment output') + self.assertEqual(self.msxClass.MSXgeterror(505), 'Error 505 - could not read hydraulic results file.', + 'Wrong error comment output') + self.assertEqual(self.msxClass.MSXgeterror(503), 'Error 503 - could not open MSX input file.', + 'Wrong error comment output') def test_MSXgetparameter(self): - self.assertEqual(self.msxClass.MSXgetparameter(1,1,2), 0.076, + self.assertEqual(self.msxClass.MSXgetparameter(1, 1, 2), 0.076, 'Wrong error comment output') - self.assertEqual(self.msxClass.MSXgetparameter(1, 1,4), 2.3e-3, + self.assertEqual(self.msxClass.MSXgetparameter(1, 1, 4), 2.3e-3, 'Wrong error comment output') def test_MSXsetparameter(self): - #set value as integer test_MSXsetparameter - self.msxClass.MSXsetparameter(1,1,1,69) + # set value as integer test_MSXsetparameter + self.msxClass.MSXsetparameter(1, 1, 1, 69) self.assertEqual(self.msxClass.MSXgetparameter(1, 1, 1), 69, 'Wrong error comment output') - #set value as float test_MSXsetparameter + # set value as float test_MSXsetparameter self.msxClass.MSXsetparameter(1, 1, 1, 69.420) self.assertEqual(self.msxClass.MSXgetparameter(1, 1, 1), 69.420, 'Wrong error comment output') def test_MSXgetcount(self): - #for species + # for species self.assertEqual(self.msxClass.MSXgetcount(3), 16, 'Wrong error get count output') - #for parameters + # for parameters self.assertEqual(self.msxClass.MSXgetcount(5), 11, 'Wrong error get count output') - #for constants + # for constants self.assertEqual(self.msxClass.MSXgetcount(6), 2, 'Wrong error get count output') - #for patterns + # for patterns self.assertEqual(self.msxClass.MSXgetcount(7), 2, 'Wrong error get count output') def test_MSXgetindex(self): - #testing 4 species (number 3) first , last, 1 char & more than 1 char and middle - self.assertEqual(self.msxClass.MSXgetindex(3,"HOCL"), 1, + # testing 4 species (number 3) first , last, 1 char & more than 1 char and middle + self.assertEqual(self.msxClass.MSXgetindex(3, "HOCL"), 1, 'Wrong error get count output') - self.assertEqual(self.msxClass.MSXgetindex(3,"cNH2CL"), 16, + self.assertEqual(self.msxClass.MSXgetindex(3, "cNH2CL"), 16, 'Wrong error get count output') - self.assertEqual(self.msxClass.MSXgetindex(3,"H"), 9, + self.assertEqual(self.msxClass.MSXgetindex(3, "H"), 9, 'Wrong error get count output') - self.assertEqual(self.msxClass.MSXgetindex(3,"OH"), 10, + self.assertEqual(self.msxClass.MSXgetindex(3, "OH"), 10, 'Wrong error get count output') - #testing parameters (number 5) first , last and one middle case + # testing parameters (number 5) first , last and one middle case self.assertEqual(self.msxClass.MSXgetindex(5, "k1"), 1, 'Wrong error get count output') self.assertEqual(self.msxClass.MSXgetindex(5, "kDOC2"), 11, 'Wrong error get count output') self.assertEqual(self.msxClass.MSXgetindex(5, "k6"), 5, 'Wrong error get count output') - #testing constants (number 6) + # testing constants (number 6) self.assertEqual(self.msxClass.MSXgetindex(6, "S1"), 1, 'Wrong error get count output') self.assertEqual(self.msxClass.MSXgetindex(6, "S2"), 2, 'Wrong error get count output') - #testing paterns (number 7) + # testing paterns (number 7) self.assertEqual(self.msxClass.MSXgetindex(7, "PAT1"), 1, 'Wrong error get count output') self.assertEqual(self.msxClass.MSXgetindex(7, "PAT2"), 2, @@ -218,9 +215,9 @@ def test_MSXgetindex(self): def test_MSXaddpattern(self): - y=self.msxClass.MSXgetcount(7) + y = self.msxClass.MSXgetcount(7) self.msxClass.MSXaddpattern("Johnnys") - self.assertEqual(self.msxClass.MSXgetcount(7), y+1, + self.assertEqual(self.msxClass.MSXgetcount(7), y + 1, 'Wrong error add patter output') def test_MSXsetpatter(self): @@ -251,15 +248,14 @@ def test_MSXsavesmsxfile(self): else: print(f"The file {filename} does not exist in the current directory.") - def test_MSXgetqual(self): self.msxClass.MSXclose() self.epanetClass.unload() - inpname = os.path.join(os.getcwd(), 'epyt', 'networks', 'msx-examples', 'net2-cl2.inp') + inpname = os.path.join(DIRNAME, 'msx-examples', 'net2-cl2.inp') self.epanetClass = epanet(inpname, msx=True) - file_path = os.path.join(os.getcwd(), 'epyt', 'networks', 'msx-examples', 'net2-cl2.msx') - self.msxClass = epanetmsxapi(file_path) + file_path = os.path.join(DIRNAME, 'msx-examples', 'net2-cl2.msx') + self.msxClass = self.epanetClass.loadMSXFile(file_path) self.msxClass.MSXsolveH() self.msxClass.MSXsolveQ() @@ -268,22 +264,20 @@ def test_MSXgetqual(self): self.msxClass.MSXinit(0) c = 0 while True: - t, tleft = self.msxClass.MSXstep() - c = c + 1 - if c == 1: - self.assertEqual(self.msxClass.MSXgetqual(0, 1,1), 0.8000000188349043, + t, tleft = self.msxClass.MSXstep() + c = c + 1 + if c == 1: + self.assertEqual(self.msxClass.MSXgetqual(0, 1, 1), 0.8, 'Wrong get qual comment output') - if c == 85: - self.assertEqual(self.msxClass.MSXgetqual(0,1,1), 0.7991662288393907, + if c == 85: + self.assertEqual(self.msxClass.MSXgetqual(0, 1, 1), 0.7991662288393907, 'Wrong get qual comment output') - if c == 660: - self.assertEqual(self.msxClass.MSXgetqual(0,1,1), 0.7999999830262526, + if c == 660: + self.assertEqual(self.msxClass.MSXgetqual(0, 1, 1), 0.7999999830262526, 'Wrong get qual comment output') - if tleft <= 0: + if tleft <= 0: break - - if __name__ == "__main__": - unittest.main() # run all tests + unittest.main() diff --git a/setup.py b/setup.py index e208100..362d078 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,7 @@ from setuptools import setup import os + # python setup.py bdist_wheel # python setup.py sdist # twine upload dist/* --config-file .pypirc @@ -18,6 +19,7 @@ def read_version_from_init(file_path="epyt/__init__.py"): else: raise RuntimeError("Unable to find version string.") + __version__ = read_version_from_init() module_name = 'epyt' data = list()