From e55eb43dbd8449e17a6c8ccab9e3f9297a44d227 Mon Sep 17 00:00:00 2001 From: ahobeost Date: Tue, 13 Jun 2023 11:15:58 +0200 Subject: [PATCH 01/56] Initial test for regime table reader --- tests/trnsysGUI/data/regimes.csv | 3 + tests/trnsysGUI/pythonInterface/__init__.py | 0 .../regimeExporter/__init__.py | 0 .../regimeExporter/testGetDesiredRegimes.py | 24 ++++++ trnsysGUI/pythonInterface/__init__.py | 0 .../regimeExporter/__init__.py | 0 .../regimeExporter/getDesiredRegimes.py | 15 ++++ .../renderDiagramOnPDFfromPython.py | 74 +++++++++++++++++++ 8 files changed, 116 insertions(+) create mode 100644 tests/trnsysGUI/data/regimes.csv create mode 100644 tests/trnsysGUI/pythonInterface/__init__.py create mode 100644 tests/trnsysGUI/pythonInterface/regimeExporter/__init__.py create mode 100644 tests/trnsysGUI/pythonInterface/regimeExporter/testGetDesiredRegimes.py create mode 100644 trnsysGUI/pythonInterface/__init__.py create mode 100644 trnsysGUI/pythonInterface/regimeExporter/__init__.py create mode 100644 trnsysGUI/pythonInterface/regimeExporter/getDesiredRegimes.py create mode 100644 trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py diff --git a/tests/trnsysGUI/data/regimes.csv b/tests/trnsysGUI/data/regimes.csv new file mode 100644 index 00000000..6a21a789 --- /dev/null +++ b/tests/trnsysGUI/data/regimes.csv @@ -0,0 +1,3 @@ +regimeNames,pump1,pump2,pump3,valve1,valve2 +"name1",500,0,0,0,0 +"name2",0,500,0,0,1 \ No newline at end of file diff --git a/tests/trnsysGUI/pythonInterface/__init__.py b/tests/trnsysGUI/pythonInterface/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/__init__.py b/tests/trnsysGUI/pythonInterface/regimeExporter/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testGetDesiredRegimes.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testGetDesiredRegimes.py new file mode 100644 index 00000000..c8c84724 --- /dev/null +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testGetDesiredRegimes.py @@ -0,0 +1,24 @@ +import pandas as _pd +import pathlib as _pl + +import trnsysGUI.pythonInterface.regimeExporter.getDesiredRegimes as _gdr +import trnsysGUI as _GUI + +_DATA_DIR_ = _pl.Path(_GUI.__file__).parent / "..\\tests\\trnsysGUI\\data" + + +class TestGetDesiredRegimes: + def testRegimes(self): + fileName = _DATA_DIR_ / "regimes.csv" + df1 = _gdr.getRegimesFromFile(fileName) + df2 = _pd.DataFrame( + { + "regimeNames": ["name1", "name2"], + "pump1": [500, 0], + "pump2": [0, 500], + "pump3": [0, 0], + "valve1": [0, 0], + "valve2": [0, 1], + } + ) + assert df1.equals(df2) diff --git a/trnsysGUI/pythonInterface/__init__.py b/trnsysGUI/pythonInterface/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/trnsysGUI/pythonInterface/regimeExporter/__init__.py b/trnsysGUI/pythonInterface/regimeExporter/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/trnsysGUI/pythonInterface/regimeExporter/getDesiredRegimes.py b/trnsysGUI/pythonInterface/regimeExporter/getDesiredRegimes.py new file mode 100644 index 00000000..0075915c --- /dev/null +++ b/trnsysGUI/pythonInterface/regimeExporter/getDesiredRegimes.py @@ -0,0 +1,15 @@ +import pandas as _pd + + +def getRegimesFromFile(fileName): + df = _pd.read_csv(fileName) + return df + + +# +# +# regimeName, name1, name2, name3 +# regime, value1, value2, value3 +# +# if isPump(name): +# if isValve(name): \ No newline at end of file diff --git a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py new file mode 100644 index 00000000..6729ade8 --- /dev/null +++ b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py @@ -0,0 +1,74 @@ +import PyQt5.QtGui as _qtg +import PyQt5.QtPrintSupport as _qtp + +from tests.trnsysGUI.diagram import _testHelper as _th +import trnsysGUI.project as _prj + + +def printDiagramToPDF(self, fileName): + if fileName != "": + printer = _qtp.QPrinter(_qtp.QPrinter.HighResolution) + printer.setOrientation(_qtp.QPrinter.Landscape) + printer.setOutputFormat(_qtp.QPrinter.PdfFormat) + printer.setOutputFileName(fileName) + painter = _qtg.QPainter(printer) + self.diagramScene.render(painter) + painter.end() + self.logger.info("File exported to %s" % fileName) + +# regimeValue = {regimeName: "", pumps: [], valves [] } +# regimeValues = df[] +# for regimeRow in df: + + + +PROJECT_NAME = "PCM_reverseable_airsource_HP_reduced" +PROJECT_FOLDER = "." + +def printRegimesAndCopyFiles(): + mainWindow = self._createMainWindow(PROJECT_FOLDER, PROJECT_NAME, qtbot, monkeypatch) + + regimeValues = getRegimesValues() + for regimeRow in regimeValues.rows(): + adjustPumpsAndValves() + runMassFlowSolver() + copyMFRandTfiles() + adjustSlider(steps=2) + printDiagramToPDF() + + + +def runMassFlowSolver(self, PROJECT_NAME, PROJECT_FOLDER, qtbot, monkeypatch) -> None: + + self._exportMassFlowSolverDeckAndRunTrnsys(mainWindow.editor) + + # massFlowSolverDeckFileName = f"{PROJECT_NAME}_mfs.dck" + + # copyMFRandTfiles(NAME, regimeName) + # massFlowRatesPrintFileName = f"{PROJECT_NAME}_Mfr.prt" + # temperaturesPintFileName = f"{PROJECT_NAME}_T.prt" + + # moveSlider(steps=2) + # printDiagramToPDF() + + +def _createMainWindow(PROJECT_FOLDER, PROJECT_NAME, qtbot, monkeypatch): + def patchedCloseEvent(_, closeEvent): + return closeEvent.accept() + + monkeypatch.setattr( + _mw.MainWindow, # type: ignore[attr-defined] + _mw.MainWindow.closeEvent.__name__, # type: ignore[attr-defined] + patchedCloseEvent, + ) + + projectJsonFilePath = PROJECT_FOLDER / f"{PROJECT_NAME}.json" + project = _prj.LoadProject(projectJsonFilePath) + + logger = _ulog.getOrCreateCustomLogger("root", "DEBUG") # type: ignore[attr-defined] + + mainWindow = _mw.MainWindow(logger, project) # type: ignore[attr-defined] + + qtbot.addWidget(mainWindow) + + return mainWindow From 094258fe65c505b01bd2151059f59a1d9865892a Mon Sep 17 00:00:00 2001 From: ahobeost Date: Tue, 13 Jun 2023 11:36:15 +0200 Subject: [PATCH 02/56] Added simple json case with two working regimes and one regime that throws an error. --- .../diagramForRegimes/ddck/generic/end.ddck | 14 + .../diagramForRegimes/ddck/generic/head.ddck | 110 ++++ .../diagramForRegimes/diagramForRegimes.json | 592 ++++++++++++++++++ .../diagramForRegimes_name1_Mfr.prt | 32 + .../diagramForRegimes_name1_T.prt | 32 + .../diagramForRegimes_name2_Mfr.prt | 32 + .../diagramForRegimes_name2_T.prt | 32 + .../expectedPDFs/diagramForRegimes_name1.pdf | Bin 0 -> 33140 bytes .../expectedPDFs/diagramForRegimes_name2.pdf | Bin 0 -> 46458 bytes tests/trnsysGUI/data/regimes.csv | 5 +- .../regimeExporter/testGetDesiredRegimes.py | 14 +- 11 files changed, 854 insertions(+), 9 deletions(-) create mode 100644 tests/trnsysGUI/data/diagramForRegimes/ddck/generic/end.ddck create mode 100644 tests/trnsysGUI/data/diagramForRegimes/ddck/generic/head.ddck create mode 100644 tests/trnsysGUI/data/diagramForRegimes/diagramForRegimes.json create mode 100644 tests/trnsysGUI/data/diagramForRegimes/expectedMfsResults/diagramForRegimes_name1_Mfr.prt create mode 100644 tests/trnsysGUI/data/diagramForRegimes/expectedMfsResults/diagramForRegimes_name1_T.prt create mode 100644 tests/trnsysGUI/data/diagramForRegimes/expectedMfsResults/diagramForRegimes_name2_Mfr.prt create mode 100644 tests/trnsysGUI/data/diagramForRegimes/expectedMfsResults/diagramForRegimes_name2_T.prt create mode 100644 tests/trnsysGUI/data/diagramForRegimes/expectedPDFs/diagramForRegimes_name1.pdf create mode 100644 tests/trnsysGUI/data/diagramForRegimes/expectedPDFs/diagramForRegimes_name2.pdf diff --git a/tests/trnsysGUI/data/diagramForRegimes/ddck/generic/end.ddck b/tests/trnsysGUI/data/diagramForRegimes/ddck/generic/end.ddck new file mode 100644 index 00000000..86bc6bfd --- /dev/null +++ b/tests/trnsysGUI/data/diagramForRegimes/ddck/generic/end.ddck @@ -0,0 +1,14 @@ +******************************* +**BEGIN Head.ddck +******************************* + +***************************************** +** Contact person: Dani Carbonell +** Date: 30.09.2016 +***************************************** + +END + +******************************* +**END End.ddck +******************************* diff --git a/tests/trnsysGUI/data/diagramForRegimes/ddck/generic/head.ddck b/tests/trnsysGUI/data/diagramForRegimes/ddck/generic/head.ddck new file mode 100644 index 00000000..b20348bd --- /dev/null +++ b/tests/trnsysGUI/data/diagramForRegimes/ddck/generic/head.ddck @@ -0,0 +1,110 @@ +******************************* +**BEGIN Head.ddck +******************************* + +***************************************** +** Contact person: Dani Carbonell +** Date: 30.09.2016 +***************************************** + +*************************************************************************** +** Description: +** Basic TRNSYS variables including fluid properties +*************************************************************************** + +VERSION 17 + +************************************** +***Simulation time ****** +************************************** + +CONSTANTS 3 +START = 0 +STOP = 8760 +dtSim = 1/30. ! time step in hours + +************************************** +***TRNSYS SIMULATION constants ****** +************************************** + +CONSTANTS 13 +nIteTrnsys = 30 ! TRNSYS Limit of iterations +nWarnTrnsys = 12000 ! TRNSYS Limit of warnings +nCallTraceTrnys = 31 ! TRNSYS limit of calls to a component before it will be traced +FrInte_Tol = 0.003 ! TRNSYS solver tolerances +FrConv_Tol = 0.0005 ! TRNSYS solver tolerances +nan_check_bool = 1 ! TRNSYS nan check boolean +time_report = 1 ! TRNSYS time report +solver_equation = 0 ! TRNSYS EQUATION SOLVER statement +debug_statement = 0 ! TRNSYS Overwrite DEBUG statement +solver_statement = 0 ! TRNSYS Solver statement +min_relax_factor = 1 ! TRNSYS Minimum relaxation factor +max_relac_factor = 1 ! TRNSYS Maximum relaxation factor +solver_integration = 1 ! TRNSYS numerical integration solver method + + +************************************** +***TRNSYS SIMULATION SET-UP ****** +************************************** + +SIMULATION START STOP dtSim +TOLERANCES FrInte_Tol FrConv_Tol +LIMITS nIteTrnsys nWarnTrnsys nCallTraceTrnys ! Limit of Iterations, limit of warnings, limit of calls to a component before it will be traced +DFQ solver_integration ! TRNSYS numerical integration solver method +WIDTH 132 ! TRNSYS output file width, number of characters +LIST ! NOLIST statement + +SOLVER solver_statement min_relax_factor max_relac_factor ! Solver statement, Minimum relaxation factor, Maximum relaxation factor +NAN_CHECK nan_check_bool ! Nan DEBUG statement +OVERWRITE_CHECK debug_statement ! Overwrite DEBUG statement +EQSOLVER solver_equation ! EQUATION SOLVER statement +TIME_REPORT time_report + + +************************************** +*** MASS FLOW SOLVER CONSTANTS ****** +************************************** + +CONSTANTS 3 +mfrSolverAbsTol = 1e-8 +mfrSolverRelTol = 1e-8 +mfrTolSwitchThreshold = 1e2 + +************************************** +***User defined printer settings****** +************************************** + +CONSTANTS 3 + +tStrtUser = START ! START start time of user defined printer +tEndUser = STOP ! END time of user defined printer +dtPrUser = dtSim ! timestep of user defined printer + +************************************** +***Generic Constants ****** +************************************** + +CONSTANTS 6 +versionDeck = 1 !can be changed from config file to adapt processes and so on +PI = 3.1415926 +Zero = 0 +Nix = 0 +notused = 0 +NPlotsPerSim = 18 + +************************************** +***Constant fluid properties ****** +************************************** + +CONSTANTS 7 +CPBRI = 3.8160 ! spec. heat of Glycol [kJ/kgK]; Value for an average pipe temperature with 55 °C Tyfocor LS +RHOBRI = 1016.0 ! density Glycol [kg/m³]; Value for an average pipe temperature with 55 °C Tyfocor L +CPWAT = 4.19 ! spec. heat of Water [kJ/kgK] at 20 °C +RHOWAT = 998.0 ! density of Water [kg/m³] at20 °C +LAMWAT = 0.58 ! heat conductivity W/(mK) +CPWAT_SI = CPWAT*1000 ! J/(kgK) +CPBRI_SI = CPBRI*1000 ! J/(kgK) + +******************************* +**END Head.dck +******************************* diff --git a/tests/trnsysGUI/data/diagramForRegimes/diagramForRegimes.json b/tests/trnsysGUI/data/diagramForRegimes/diagramForRegimes.json new file mode 100644 index 00000000..f69b1ab1 --- /dev/null +++ b/tests/trnsysGUI/data/diagramForRegimes/diagramForRegimes.json @@ -0,0 +1,592 @@ +{ + "Blocks": { + ".__BlockDct__": true, + "Block-1": { + ".__BlockDict__": true, + "BlockDisplayName": "Pump2", + "BlockName": "Pump", + "Id": 1, + "__version__": "9552365f-ef11-4fac-ba35-644e94b54088", + "blockPosition": [ + -600.0, + -200.0 + ], + "flippedH": false, + "flippedV": false, + "massFlowRateInKgPerH": 0, + "portsIdsIn": [ + 2 + ], + "portsIdsOut": [ + 3 + ], + "rotationN": 5, + "trnsysId": 1 + }, + "Block-10": { + ".__BlockDict__": true, + "BlockDisplayName": "Valve1", + "BlockName": "TVentil", + "Id": 10, + "IsTempering": false, + "PositionForMassFlowSolver": "0.0", + "__version__": "3fff9a8a-d40e-42e2-824d-c015116d0a1d", + "blockPosition": [ + -740.0, + -240.0 + ], + "flippedH": false, + "flippedV": false, + "portsIdsIn": [ + 13 + ], + "portsIdsOut": [ + 11, + 12 + ], + "rotationN": 2, + "trnsysId": 4 + }, + "Block-14": { + ".__BlockDict__": true, + "BlockDisplayName": "Valve2", + "BlockName": "TVentil", + "Id": 14, + "IsTempering": false, + "PositionForMassFlowSolver": "0.0", + "__version__": "3fff9a8a-d40e-42e2-824d-c015116d0a1d", + "blockPosition": [ + -600.0, + -240.0 + ], + "flippedH": false, + "flippedV": false, + "portsIdsIn": [ + 17 + ], + "portsIdsOut": [ + 15, + 16 + ], + "rotationN": 2, + "trnsysId": 5 + }, + "Block-18": { + ".__BlockDict__": true, + "BlockDisplayName": "Ashp18", + "BlockName": "AirSourceHP", + "Id": 18, + "__version__": "bbc03f36-d1a1-4d97-a9c0-d212ea3a0203", + "blockPosition": [ + -1060.0, + -280.0 + ], + "flippedH": false, + "flippedV": false, + "portsIdsIn": [ + 19 + ], + "portsIdsOut": [ + 20 + ], + "rotationN": 0, + "trnsysId": 6 + }, + "Block-26": { + ".__BlockDict__": true, + "BlockDisplayName": "Tee26", + "BlockName": "TeePiece", + "Id": 26, + "__version__": "3fff9a8a-d40e-42e2-824d-c015116d0a1d", + "blockPosition": [ + -640.0, + -120.0 + ], + "flippedH": false, + "flippedV": false, + "portsIdsIn": [ + 27 + ], + "portsIdsOut": [ + 28, + 29 + ], + "rotationN": 0, + "trnsysId": 12 + }, + "Block-33": { + ".__BlockDict__": true, + "BlockDisplayName": "Tee33", + "BlockName": "TeePiece", + "Id": 33, + "__version__": "3fff9a8a-d40e-42e2-824d-c015116d0a1d", + "blockPosition": [ + -780.0, + -120.0 + ], + "flippedH": false, + "flippedV": false, + "portsIdsIn": [ + 34 + ], + "portsIdsOut": [ + 35, + 36 + ], + "rotationN": 0, + "trnsysId": 16 + }, + "Block-4": { + ".__BlockDict__": true, + "BlockDisplayName": "Pump3", + "BlockName": "Pump", + "Id": 4, + "__version__": "9552365f-ef11-4fac-ba35-644e94b54088", + "blockPosition": [ + -540.0, + -280.0 + ], + "flippedH": false, + "flippedV": false, + "massFlowRateInKgPerH": 500, + "portsIdsIn": [ + 5 + ], + "portsIdsOut": [ + 6 + ], + "rotationN": 0, + "trnsysId": 2 + }, + "Block-7": { + ".__BlockDict__": true, + "BlockDisplayName": "Pump1", + "BlockName": "Pump", + "Id": 7, + "__version__": "9552365f-ef11-4fac-ba35-644e94b54088", + "blockPosition": [ + -900.0, + -280.0 + ], + "flippedH": false, + "flippedV": false, + "massFlowRateInKgPerH": 500, + "portsIdsIn": [ + 8 + ], + "portsIdsOut": [ + 9 + ], + "rotationN": 0, + "trnsysId": 3 + }, + "Connection-21": { + ".__ConnectionDict__": true, + "__version__": "74032e79-2abc-4fcf-9328-5d697ef31023", + "connectionId": 1, + "diameterInCm": { + "name": "loop1Dia" + }, + "fromPortId": 20, + "id": 21, + "labelPos": [ + -934.0, + -259.0 + ], + "lengthInM": { + "name": "loop1Len" + }, + "massFlowLabelPos": [ + -934.0, + -259.0 + ], + "name": "Ashp18_Pump7", + "segmentsCorners": [ + [ + -908.5, + -260.0 + ], + [ + -908.5, + -260.0 + ] + ], + "shallBeSimulated": true, + "toPortId": 8, + "trnsysId": 7, + "uValueInWPerM2K": { + "name": "loop1UVal" + } + }, + "Connection-22": { + ".__ConnectionDict__": true, + "__version__": "74032e79-2abc-4fcf-9328-5d697ef31023", + "connectionId": 2, + "diameterInCm": { + "name": "loop1Dia" + }, + "fromPortId": 9, + "id": 22, + "labelPos": [ + -863.0, + -263.0 + ], + "lengthInM": { + "name": "loop1Len" + }, + "massFlowLabelPos": [ + -863.0, + -263.0 + ], + "name": "Pump7_Val10", + "segmentsCorners": [ + [ + -821.5, + -260.0 + ], + [ + -821.5, + -260.0 + ] + ], + "shallBeSimulated": true, + "toPortId": 13, + "trnsysId": 8, + "uValueInWPerM2K": { + "name": "loop1UVal" + } + }, + "Connection-23": { + ".__ConnectionDict__": true, + "__version__": "74032e79-2abc-4fcf-9328-5d697ef31023", + "connectionId": 3, + "diameterInCm": { + "name": "loop1Dia" + }, + "fromPortId": 11, + "id": 23, + "labelPos": [ + -737.0, + -257.0 + ], + "lengthInM": { + "name": "loop1Len" + }, + "massFlowLabelPos": [ + -737.0, + -257.0 + ], + "name": "Val10_Val14", + "segmentsCorners": [ + [ + -687.0, + -260.0 + ], + [ + -687.0, + -260.0 + ] + ], + "shallBeSimulated": true, + "toPortId": 17, + "trnsysId": 9, + "uValueInWPerM2K": { + "name": "loop1UVal" + } + }, + "Connection-24": { + ".__ConnectionDict__": true, + "__version__": "74032e79-2abc-4fcf-9328-5d697ef31023", + "connectionId": 4, + "diameterInCm": { + "name": "loop1Dia" + }, + "fromPortId": 15, + "id": 24, + "labelPos": [ + -597.0, + -257.0 + ], + "lengthInM": { + "name": "loop1Len" + }, + "massFlowLabelPos": [ + -597.0, + -257.0 + ], + "name": "Val14_Pump4", + "segmentsCorners": [ + [ + -568.5, + -260.0 + ], + [ + -568.5, + -260.0 + ] + ], + "shallBeSimulated": true, + "toPortId": 5, + "trnsysId": 10, + "uValueInWPerM2K": { + "name": "loop1UVal" + } + }, + "Connection-30": { + ".__ConnectionDict__": true, + "__version__": "74032e79-2abc-4fcf-9328-5d697ef31023", + "connectionId": 6, + "diameterInCm": { + "name": "loop1Dia" + }, + "fromPortId": 16, + "id": 30, + "labelPos": [ + -617.0, + -237.0 + ], + "lengthInM": { + "name": "loop1Len" + }, + "massFlowLabelPos": [ + -617.0, + -237.0 + ], + "name": "Val14_Pump1", + "segmentsCorners": [ + [ + -620.0, + -200.0 + ] + ], + "shallBeSimulated": true, + "toPortId": 2, + "trnsysId": 13, + "uValueInWPerM2K": { + "name": "loop1UVal" + } + }, + "Connection-31": { + ".__ConnectionDict__": true, + "__version__": "74032e79-2abc-4fcf-9328-5d697ef31023", + "connectionId": 7, + "diameterInCm": { + "name": "loop1Dia" + }, + "fromPortId": 6, + "id": 31, + "labelPos": [ + 0.0, + 0.0 + ], + "lengthInM": { + "name": "loop1Len" + }, + "massFlowLabelPos": [ + 0.0, + 0.0 + ], + "name": "Pump4_Tee26", + "segmentsCorners": [ + [ + -473.0, + -260.0 + ], + [ + -473.0, + -99.0 + ], + [ + -573.0, + -99.0 + ], + [ + -573.0, + -100.0 + ] + ], + "shallBeSimulated": true, + "toPortId": 28, + "trnsysId": 14, + "uValueInWPerM2K": { + "name": "loop1UVal" + } + }, + "Connection-32": { + ".__ConnectionDict__": true, + "__version__": "74032e79-2abc-4fcf-9328-5d697ef31023", + "connectionId": 8, + "diameterInCm": { + "name": "loop1Dia" + }, + "fromPortId": 3, + "id": 32, + "labelPos": [ + -617.0, + -163.0 + ], + "lengthInM": { + "name": "loop1Len" + }, + "massFlowLabelPos": [ + -617.0, + -163.0 + ], + "name": "Pump1_Tee26", + "segmentsCorners": [ + [ + -620.0, + -120.0 + ] + ], + "shallBeSimulated": true, + "toPortId": 29, + "trnsysId": 15, + "uValueInWPerM2K": { + "name": "loop1UVal" + } + }, + "Connection-37": { + ".__ConnectionDict__": true, + "__version__": "74032e79-2abc-4fcf-9328-5d697ef31023", + "connectionId": 9, + "diameterInCm": { + "name": "loop1Dia" + }, + "fromPortId": 27, + "id": 37, + "labelPos": [ + -643.0, + -103.0 + ], + "lengthInM": { + "name": "loop1Len" + }, + "massFlowLabelPos": [ + -643.0, + -103.0 + ], + "name": "Tee26_Tee33", + "segmentsCorners": [ + [ + -693.0, + -100.0 + ], + [ + -693.0, + -100.0 + ] + ], + "shallBeSimulated": true, + "toPortId": 35, + "trnsysId": 17, + "uValueInWPerM2K": { + "name": "loop1UVal" + } + }, + "Connection-38": { + ".__ConnectionDict__": true, + "__version__": "74032e79-2abc-4fcf-9328-5d697ef31023", + "connectionId": 10, + "diameterInCm": { + "name": "loop1Dia" + }, + "fromPortId": 12, + "id": 38, + "labelPos": [ + -757.0, + -237.0 + ], + "lengthInM": { + "name": "loop1Len" + }, + "massFlowLabelPos": [ + -757.0, + -237.0 + ], + "name": "Val10_Tee33", + "segmentsCorners": [ + [ + -760.0, + -120.0 + ] + ], + "shallBeSimulated": true, + "toPortId": 36, + "trnsysId": 18, + "uValueInWPerM2K": { + "name": "loop1UVal" + } + }, + "Connection-39": { + ".__ConnectionDict__": true, + "__version__": "74032e79-2abc-4fcf-9328-5d697ef31023", + "connectionId": 11, + "diameterInCm": { + "name": "loop1Dia" + }, + "fromPortId": 34, + "id": 39, + "labelPos": [ + -783.0, + -103.0 + ], + "lengthInM": { + "name": "loop1Len" + }, + "massFlowLabelPos": [ + -783.0, + -103.0 + ], + "name": "Tee33_Ashp18", + "segmentsCorners": [ + [ + -863.0, + -100.0 + ], + [ + -863.0, + -180.0 + ] + ], + "shallBeSimulated": true, + "toPortId": 19, + "trnsysId": 19, + "uValueInWPerM2K": { + "name": "loop1UVal" + } + }, + "IDs": { + "GlobalId": 50, + "__idDct__": true, + "globalConnID": 22, + "trnsysID": 30 + }, + "Strings": { + "DiagramName": "diagramForRegimes.json", + "ProjectFolder": "C:\\Users\\alex.hobe\\Projects\\pytrnsys_gui\\tests\\trnsysGUI\\data\\diagramForRegimes", + "__nameDct__": true + } + }, + "hydraulicLoops": [ + { + "__version__": "990b8023-eb4b-408e-8d54-23caa5916b2a", + "connectionsTrnsysId": [ + 7, + 8, + 9, + 10, + 13, + 14, + 15, + 17, + 18, + 19 + ], + "fluidName": "water", + "hasUserDefinedName": false, + "name": "loop1", + "useLoopWideDefaults": true + } + ] +} \ No newline at end of file diff --git a/tests/trnsysGUI/data/diagramForRegimes/expectedMfsResults/diagramForRegimes_name1_Mfr.prt b/tests/trnsysGUI/data/diagramForRegimes/expectedMfsResults/diagramForRegimes_name1_Mfr.prt new file mode 100644 index 00000000..f59a6d54 --- /dev/null +++ b/tests/trnsysGUI/data/diagramForRegimes/expectedMfsResults/diagramForRegimes_name1_Mfr.prt @@ -0,0 +1,32 @@ + TIME xFracValve1 xFracValve2 MAshp18_Pump7 MPump7_Val10 MVal10_Val14 MVal14_Pump4 MVal14_Pump1 MPump4_Tee26 MPump1_Tee26 MTee26_Tee33 MVal10_Tee33 MTee33_Ashp18 + +0.0000000000000000E+00 +0.0000000000000000E+00 +0.0000000000000000E+00 +0.0000000000000000E+00 +0.0000000000000000E+00 +0.0000000000000000E+00 +0.0000000000000000E+00 +0.0000000000000000E+00 +0.0000000000000000E+00 +0.0000000000000000E+00 +0.0000000000000000E+00 +0.0000000000000000E+00 +0.0000000000000000E+00 + +3.3333333333333333E-02 +0.0000000000000000E+00 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +6.6666666666666666E-02 +0.0000000000000000E+00 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +1.0000000000000001E-01 +0.0000000000000000E+00 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +1.3333333333333333E-01 +0.0000000000000000E+00 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +1.6666666666666666E-01 +0.0000000000000000E+00 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +2.0000000000000001E-01 +0.0000000000000000E+00 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +2.3333333333333334E-01 +0.0000000000000000E+00 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +2.6666666666666666E-01 +0.0000000000000000E+00 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +2.9999999999999999E-01 +0.0000000000000000E+00 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +3.3333333333333331E-01 +0.0000000000000000E+00 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +3.6666666666666664E-01 +0.0000000000000000E+00 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +4.0000000000000002E-01 +0.0000000000000000E+00 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +4.3333333333333335E-01 +0.0000000000000000E+00 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +4.6666666666666667E-01 +0.0000000000000000E+00 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +5.0000000000000000E-01 +0.0000000000000000E+00 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +5.3333333333333333E-01 +0.0000000000000000E+00 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +5.6666666666666665E-01 +0.0000000000000000E+00 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +5.9999999999999998E-01 +0.0000000000000000E+00 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +6.3333333333333330E-01 +0.0000000000000000E+00 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +6.6666666666666663E-01 +0.0000000000000000E+00 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +6.9999999999999996E-01 +0.0000000000000000E+00 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +7.3333333333333328E-01 +0.0000000000000000E+00 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +7.6666666666666672E-01 +0.0000000000000000E+00 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +8.0000000000000004E-01 +0.0000000000000000E+00 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +8.3333333333333337E-01 +0.0000000000000000E+00 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +8.6666666666666670E-01 +0.0000000000000000E+00 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +9.0000000000000002E-01 +0.0000000000000000E+00 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +9.3333333333333335E-01 +0.0000000000000000E+00 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +9.6666666666666667E-01 +0.0000000000000000E+00 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +1.0000000000000000E+00 +0.0000000000000000E+00 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 diff --git a/tests/trnsysGUI/data/diagramForRegimes/expectedMfsResults/diagramForRegimes_name1_T.prt b/tests/trnsysGUI/data/diagramForRegimes/expectedMfsResults/diagramForRegimes_name1_T.prt new file mode 100644 index 00000000..112af959 --- /dev/null +++ b/tests/trnsysGUI/data/diagramForRegimes/expectedMfsResults/diagramForRegimes_name1_T.prt @@ -0,0 +1,32 @@ + TIME TAshp18_Pump7 TPump7_Val10 TVal10_Val14 TVal14_Pump4 TVal14_Pump1 TPump4_Tee26 TPump1_Tee26 TTee26_Tee33 TVal10_Tee33 TTee33_Ashp18 + +0.0000000000000000E+00 +2.0000000000000000E+01 +2.0000000000000000E+01 +2.0000000000000000E+01 +2.0000000000000000E+01 +2.0000000000000000E+01 +2.0000000000000000E+01 +2.0000000000000000E+01 +2.0000000000000000E+01 +2.0000000000000000E+01 +2.0000000000000000E+01 + +3.3333333333333333E-02 +1.7147862462601666E+00 +2.4025558105305271E+00 +3.0643298387964131E+00 +3.7010908809222935E+00 +1.9954637228363087E+01 +4.3137843494642931E+00 +1.9954637228363087E+01 +4.9033199233441662E+00 +1.9954637228363087E+01 +5.4705728984687845E+00 + +6.6666666666666666E-02 +1.0000000000000000E+00 +1.0268880743306343E+00 +1.0786316529548894E+00 +1.1533134030103593E+00 +1.9864200381467953E+01 +1.2491254213367506E+00 +1.9864200381467953E+01 +1.3643637013837289E+00 +1.9864200381467953E+01 +1.4974228620542513E+00 + +1.0000000000000001E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0010114471913700E+00 +1.0039311001550246E+00 +1.9774195029155266E+01 +1.0095496986021537E+00 +1.9774195029155266E+01 +1.0185600869665319E+00 +1.9774195029155266E+01 +1.0315648228124557E+00 + +1.3333333333333333E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000380475525450E+00 +1.9684619112667114E+01 +1.0001844854493140E+00 +1.9684619112667114E+01 +1.0005367429562979E+00 +1.9684619112667114E+01 +1.0012146295086954E+00 + +1.6666666666666666E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.9595470583068366E+01 +1.0000014312326604E+00 +1.9595470583068366E+01 +1.0001844522558356E+00 +1.9595470583068366E+01 +1.0005366463830139E+00 + +2.0000000000000001E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.9506747401199846E+01 +1.0000000000000000E+00 +1.9506747401199846E+01 +1.0000083169153973E+00 +1.9506747401199846E+01 +1.0001976711679461E+00 + +2.3333333333333334E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.9418447537631643E+01 +1.0000000000000000E+00 +1.9418447537631643E+01 +1.0000000538385991E+00 +1.9418447537631643E+01 +1.0000149410922496E+00 + +2.6666666666666666E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.9330568972616724E+01 +1.0000000000000000E+00 +1.9330568972616724E+01 +1.0000000000000000E+00 +1.9330568972616724E+01 +1.0000003646606110E+00 + +2.9999999999999999E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.9243109696044733E+01 +1.0000000000000000E+00 +1.9243109696044733E+01 +1.0000000000000000E+00 +1.9243109696044733E+01 +1.0000000020252435E+00 + +3.3333333333333331E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.9156067707395987E+01 +1.0000000000000000E+00 +1.9156067707395987E+01 +1.0000000000000000E+00 +1.9156067707395987E+01 +1.0000000000000000E+00 + +3.6666666666666664E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.9069441015695737E+01 +1.0000000000000000E+00 +1.9069441015695737E+01 +1.0000000000000000E+00 +1.9069441015695737E+01 +1.0000000000000000E+00 + +4.0000000000000002E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8983227639468634E+01 +1.0000000000000000E+00 +1.8983227639468634E+01 +1.0000000000000000E+00 +1.8983227639468634E+01 +1.0000000000000000E+00 + +4.3333333333333335E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8897425606693385E+01 +1.0000000000000000E+00 +1.8897425606693385E+01 +1.0000000000000000E+00 +1.8897425606693385E+01 +1.0000000000000000E+00 + +4.6666666666666667E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8812032954757658E+01 +1.0000000000000000E+00 +1.8812032954757658E+01 +1.0000000000000000E+00 +1.8812032954757658E+01 +1.0000000000000000E+00 + +5.0000000000000000E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8727047730413187E+01 +1.0000000000000000E+00 +1.8727047730413187E+01 +1.0000000000000000E+00 +1.8727047730413187E+01 +1.0000000000000000E+00 + +5.3333333333333333E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8642467989731092E+01 +1.0000000000000000E+00 +1.8642467989731092E+01 +1.0000000000000000E+00 +1.8642467989731092E+01 +1.0000000000000000E+00 + +5.6666666666666665E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8558291798057422E+01 +1.0000000000000000E+00 +1.8558291798057422E+01 +1.0000000000000000E+00 +1.8558291798057422E+01 +1.0000000000000000E+00 + +5.9999999999999998E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8474517229968882E+01 +1.0000000000000000E+00 +1.8474517229968882E+01 +1.0000000000000000E+00 +1.8474517229968882E+01 +1.0000000000000000E+00 + +6.3333333333333330E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8391142369228827E+01 +1.0000000000000000E+00 +1.8391142369228827E+01 +1.0000000000000000E+00 +1.8391142369228827E+01 +1.0000000000000000E+00 + +6.6666666666666663E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8308165308743387E+01 +1.0000000000000000E+00 +1.8308165308743387E+01 +1.0000000000000000E+00 +1.8308165308743387E+01 +1.0000000000000000E+00 + +6.9999999999999996E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8225584150517886E+01 +1.0000000000000000E+00 +1.8225584150517886E+01 +1.0000000000000000E+00 +1.8225584150517886E+01 +1.0000000000000000E+00 + +7.3333333333333328E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8143397005613387E+01 +1.0000000000000000E+00 +1.8143397005613387E+01 +1.0000000000000000E+00 +1.8143397005613387E+01 +1.0000000000000000E+00 + +7.6666666666666672E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8061601994103530E+01 +1.0000000000000000E+00 +1.8061601994103530E+01 +1.0000000000000000E+00 +1.8061601994103530E+01 +1.0000000000000000E+00 + +8.0000000000000004E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.7980197245031487E+01 +1.0000000000000000E+00 +1.7980197245031487E+01 +1.0000000000000000E+00 +1.7980197245031487E+01 +1.0000000000000000E+00 + +8.3333333333333337E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.7899180896367206E+01 +1.0000000000000000E+00 +1.7899180896367206E+01 +1.0000000000000000E+00 +1.7899180896367206E+01 +1.0000000000000000E+00 + +8.6666666666666670E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.7818551094964779E+01 +1.0000000000000000E+00 +1.7818551094964779E+01 +1.0000000000000000E+00 +1.7818551094964779E+01 +1.0000000000000000E+00 + +9.0000000000000002E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.7738305996520090E+01 +1.0000000000000000E+00 +1.7738305996520090E+01 +1.0000000000000000E+00 +1.7738305996520090E+01 +1.0000000000000000E+00 + +9.3333333333333335E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.7658443765528617E+01 +1.0000000000000000E+00 +1.7658443765528617E+01 +1.0000000000000000E+00 +1.7658443765528617E+01 +1.0000000000000000E+00 + +9.6666666666666667E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.7578962575243423E+01 +1.0000000000000000E+00 +1.7578962575243423E+01 +1.0000000000000000E+00 +1.7578962575243423E+01 +1.0000000000000000E+00 + +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.7499860607633416E+01 +1.0000000000000000E+00 +1.7499860607633416E+01 +1.0000000000000000E+00 +1.7499860607633416E+01 +1.0000000000000000E+00 diff --git a/tests/trnsysGUI/data/diagramForRegimes/expectedMfsResults/diagramForRegimes_name2_Mfr.prt b/tests/trnsysGUI/data/diagramForRegimes/expectedMfsResults/diagramForRegimes_name2_Mfr.prt new file mode 100644 index 00000000..22981fb9 --- /dev/null +++ b/tests/trnsysGUI/data/diagramForRegimes/expectedMfsResults/diagramForRegimes_name2_Mfr.prt @@ -0,0 +1,32 @@ + TIME xFracValve1 xFracValve2 MAshp18_Pump7 MPump7_Val10 MVal10_Val14 MVal14_Pump4 MVal14_Pump1 MPump4_Tee26 MPump1_Tee26 MTee26_Tee33 MVal10_Tee33 MTee33_Ashp18 + +0.0000000000000000E+00 +0.0000000000000000E+00 +1.0000000000000000E+00 +0.0000000000000000E+00 +0.0000000000000000E+00 +0.0000000000000000E+00 +0.0000000000000000E+00 +0.0000000000000000E+00 +0.0000000000000000E+00 +0.0000000000000000E+00 +0.0000000000000000E+00 +0.0000000000000000E+00 +0.0000000000000000E+00 + +3.3333333333333333E-02 +0.0000000000000000E+00 +1.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +6.6666666666666666E-02 +0.0000000000000000E+00 +1.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +1.0000000000000001E-01 +0.0000000000000000E+00 +1.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +1.3333333333333333E-01 +0.0000000000000000E+00 +1.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +1.6666666666666666E-01 +0.0000000000000000E+00 +1.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +2.0000000000000001E-01 +0.0000000000000000E+00 +1.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +2.3333333333333334E-01 +0.0000000000000000E+00 +1.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +2.6666666666666666E-01 +0.0000000000000000E+00 +1.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +2.9999999999999999E-01 +0.0000000000000000E+00 +1.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +3.3333333333333331E-01 +0.0000000000000000E+00 +1.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +3.6666666666666664E-01 +0.0000000000000000E+00 +1.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +4.0000000000000002E-01 +0.0000000000000000E+00 +1.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +4.3333333333333335E-01 +0.0000000000000000E+00 +1.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +4.6666666666666667E-01 +0.0000000000000000E+00 +1.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +5.0000000000000000E-01 +0.0000000000000000E+00 +1.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +5.3333333333333333E-01 +0.0000000000000000E+00 +1.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +5.6666666666666665E-01 +0.0000000000000000E+00 +1.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +5.9999999999999998E-01 +0.0000000000000000E+00 +1.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +6.3333333333333330E-01 +0.0000000000000000E+00 +1.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +6.6666666666666663E-01 +0.0000000000000000E+00 +1.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +6.9999999999999996E-01 +0.0000000000000000E+00 +1.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +7.3333333333333328E-01 +0.0000000000000000E+00 +1.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +7.6666666666666672E-01 +0.0000000000000000E+00 +1.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +8.0000000000000004E-01 +0.0000000000000000E+00 +1.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +8.3333333333333337E-01 +0.0000000000000000E+00 +1.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +8.6666666666666670E-01 +0.0000000000000000E+00 +1.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +9.0000000000000002E-01 +0.0000000000000000E+00 +1.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +9.3333333333333335E-01 +0.0000000000000000E+00 +1.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +9.6666666666666667E-01 +0.0000000000000000E+00 +1.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 + +1.0000000000000000E+00 +0.0000000000000000E+00 +1.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 +5.0000000000000000E+02 +0.0000000000000000E+00 +5.0000000000000000E+02 diff --git a/tests/trnsysGUI/data/diagramForRegimes/expectedMfsResults/diagramForRegimes_name2_T.prt b/tests/trnsysGUI/data/diagramForRegimes/expectedMfsResults/diagramForRegimes_name2_T.prt new file mode 100644 index 00000000..61f292fb --- /dev/null +++ b/tests/trnsysGUI/data/diagramForRegimes/expectedMfsResults/diagramForRegimes_name2_T.prt @@ -0,0 +1,32 @@ + TIME TAshp18_Pump7 TPump7_Val10 TVal10_Val14 TVal14_Pump4 TVal14_Pump1 TPump4_Tee26 TPump1_Tee26 TTee26_Tee33 TVal10_Tee33 TTee33_Ashp18 + +0.0000000000000000E+00 +2.0000000000000000E+01 +2.0000000000000000E+01 +2.0000000000000000E+01 +2.0000000000000000E+01 +2.0000000000000000E+01 +2.0000000000000000E+01 +2.0000000000000000E+01 +2.0000000000000000E+01 +2.0000000000000000E+01 +2.0000000000000000E+01 + +3.3333333333333333E-02 +1.7147862462601666E+00 +2.4025558105305271E+00 +3.0643298387964131E+00 +1.9954637228363087E+01 +3.7010908809222935E+00 +1.9954637228363087E+01 +4.3137843494642931E+00 +4.9033199233441662E+00 +1.9954637228363087E+01 +5.4705728984687845E+00 + +6.6666666666666666E-02 +1.0000000000000000E+00 +1.0268880743306343E+00 +1.0786316529548894E+00 +1.9864200381467953E+01 +1.1533134030103593E+00 +1.9864200381467953E+01 +1.2491254213367506E+00 +1.3643637013837289E+00 +1.9864200381467953E+01 +1.4974228620542513E+00 + +1.0000000000000001E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0010114471913700E+00 +1.9774195029155266E+01 +1.0039311001550246E+00 +1.9774195029155266E+01 +1.0095496986021537E+00 +1.0185600869665319E+00 +1.9774195029155266E+01 +1.0315648228124557E+00 + +1.3333333333333333E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.9684619112667114E+01 +1.0000380475525450E+00 +1.9684619112667114E+01 +1.0001844854493140E+00 +1.0005367429562979E+00 +1.9684619112667114E+01 +1.0012146295086954E+00 + +1.6666666666666666E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.9595470583068366E+01 +1.0000000000000000E+00 +1.9595470583068366E+01 +1.0000014312326604E+00 +1.0001844522558356E+00 +1.9595470583068366E+01 +1.0005366463830139E+00 + +2.0000000000000001E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.9506747401199846E+01 +1.0000000000000000E+00 +1.9506747401199846E+01 +1.0000000000000000E+00 +1.0000083169153973E+00 +1.9506747401199846E+01 +1.0001976711679461E+00 + +2.3333333333333334E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.9418447537631643E+01 +1.0000000000000000E+00 +1.9418447537631643E+01 +1.0000000000000000E+00 +1.0000000538385991E+00 +1.9418447537631643E+01 +1.0000149410922496E+00 + +2.6666666666666666E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.9330568972616724E+01 +1.0000000000000000E+00 +1.9330568972616724E+01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.9330568972616724E+01 +1.0000003646606110E+00 + +2.9999999999999999E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.9243109696044733E+01 +1.0000000000000000E+00 +1.9243109696044733E+01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.9243109696044733E+01 +1.0000000020252435E+00 + +3.3333333333333331E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.9156067707395987E+01 +1.0000000000000000E+00 +1.9156067707395987E+01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.9156067707395987E+01 +1.0000000000000000E+00 + +3.6666666666666664E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.9069441015695737E+01 +1.0000000000000000E+00 +1.9069441015695737E+01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.9069441015695737E+01 +1.0000000000000000E+00 + +4.0000000000000002E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8983227639468634E+01 +1.0000000000000000E+00 +1.8983227639468634E+01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8983227639468634E+01 +1.0000000000000000E+00 + +4.3333333333333335E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8897425606693385E+01 +1.0000000000000000E+00 +1.8897425606693385E+01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8897425606693385E+01 +1.0000000000000000E+00 + +4.6666666666666667E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8812032954757658E+01 +1.0000000000000000E+00 +1.8812032954757658E+01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8812032954757658E+01 +1.0000000000000000E+00 + +5.0000000000000000E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8727047730413187E+01 +1.0000000000000000E+00 +1.8727047730413187E+01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8727047730413187E+01 +1.0000000000000000E+00 + +5.3333333333333333E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8642467989731092E+01 +1.0000000000000000E+00 +1.8642467989731092E+01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8642467989731092E+01 +1.0000000000000000E+00 + +5.6666666666666665E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8558291798057422E+01 +1.0000000000000000E+00 +1.8558291798057422E+01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8558291798057422E+01 +1.0000000000000000E+00 + +5.9999999999999998E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8474517229968882E+01 +1.0000000000000000E+00 +1.8474517229968882E+01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8474517229968882E+01 +1.0000000000000000E+00 + +6.3333333333333330E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8391142369228827E+01 +1.0000000000000000E+00 +1.8391142369228827E+01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8391142369228827E+01 +1.0000000000000000E+00 + +6.6666666666666663E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8308165308743387E+01 +1.0000000000000000E+00 +1.8308165308743387E+01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8308165308743387E+01 +1.0000000000000000E+00 + +6.9999999999999996E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8225584150517886E+01 +1.0000000000000000E+00 +1.8225584150517886E+01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8225584150517886E+01 +1.0000000000000000E+00 + +7.3333333333333328E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8143397005613387E+01 +1.0000000000000000E+00 +1.8143397005613387E+01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8143397005613387E+01 +1.0000000000000000E+00 + +7.6666666666666672E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8061601994103530E+01 +1.0000000000000000E+00 +1.8061601994103530E+01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.8061601994103530E+01 +1.0000000000000000E+00 + +8.0000000000000004E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.7980197245031487E+01 +1.0000000000000000E+00 +1.7980197245031487E+01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.7980197245031487E+01 +1.0000000000000000E+00 + +8.3333333333333337E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.7899180896367206E+01 +1.0000000000000000E+00 +1.7899180896367206E+01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.7899180896367206E+01 +1.0000000000000000E+00 + +8.6666666666666670E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.7818551094964779E+01 +1.0000000000000000E+00 +1.7818551094964779E+01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.7818551094964779E+01 +1.0000000000000000E+00 + +9.0000000000000002E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.7738305996520090E+01 +1.0000000000000000E+00 +1.7738305996520090E+01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.7738305996520090E+01 +1.0000000000000000E+00 + +9.3333333333333335E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.7658443765528617E+01 +1.0000000000000000E+00 +1.7658443765528617E+01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.7658443765528617E+01 +1.0000000000000000E+00 + +9.6666666666666667E-01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.7578962575243423E+01 +1.0000000000000000E+00 +1.7578962575243423E+01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.7578962575243423E+01 +1.0000000000000000E+00 + +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.7499860607633416E+01 +1.0000000000000000E+00 +1.7499860607633416E+01 +1.0000000000000000E+00 +1.0000000000000000E+00 +1.7499860607633416E+01 +1.0000000000000000E+00 diff --git a/tests/trnsysGUI/data/diagramForRegimes/expectedPDFs/diagramForRegimes_name1.pdf b/tests/trnsysGUI/data/diagramForRegimes/expectedPDFs/diagramForRegimes_name1.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b9a67a3d5d0f83ad048d5d1c8955515b7896d9c6 GIT binary patch literal 33140 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 literal 0 HcmV?d00001 diff --git a/tests/trnsysGUI/data/diagramForRegimes/expectedPDFs/diagramForRegimes_name2.pdf b/tests/trnsysGUI/data/diagramForRegimes/expectedPDFs/diagramForRegimes_name2.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c9c0fa4ad70d93b35dffdfdd74681d0d7fb94604 GIT binary patch literal 46458 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 Date: Tue, 13 Jun 2023 12:50:08 +0200 Subject: [PATCH 03/56] refactored file location --- tests/trnsysGUI/data/{ => diagramForRegimes}/regimes.csv | 0 .../pythonInterface/regimeExporter/testGetDesiredRegimes.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/trnsysGUI/data/{ => diagramForRegimes}/regimes.csv (100%) diff --git a/tests/trnsysGUI/data/regimes.csv b/tests/trnsysGUI/data/diagramForRegimes/regimes.csv similarity index 100% rename from tests/trnsysGUI/data/regimes.csv rename to tests/trnsysGUI/data/diagramForRegimes/regimes.csv diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testGetDesiredRegimes.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testGetDesiredRegimes.py index fb7a608c..3d7f6293 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testGetDesiredRegimes.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testGetDesiredRegimes.py @@ -4,7 +4,7 @@ import trnsysGUI.pythonInterface.regimeExporter.getDesiredRegimes as _gdr import trnsysGUI as _GUI -_DATA_DIR_ = _pl.Path(_GUI.__file__).parent / "..\\tests\\trnsysGUI\\data" +_DATA_DIR_ = _pl.Path(_GUI.__file__).parent / "..\\tests\\trnsysGUI\\data\\diagramForRegimes" class TestGetDesiredRegimes: From fb2e8c7c3c0fa97f1de2f18f7776b19c5557572f Mon Sep 17 00:00:00 2001 From: ahobeost Date: Tue, 13 Jun 2023 13:06:48 +0200 Subject: [PATCH 04/56] added error handling for column name --- tests/trnsysGUI/data/diagramForRegimes/regimes.csv | 2 +- .../data/diagramForRegimes/regimes_incorrect.csv | 4 ++++ .../regimeExporter/testGetDesiredRegimes.py | 13 +++++++++++-- .../regimeExporter/getDesiredRegimes.py | 10 ++++++++-- 4 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 tests/trnsysGUI/data/diagramForRegimes/regimes_incorrect.csv diff --git a/tests/trnsysGUI/data/diagramForRegimes/regimes.csv b/tests/trnsysGUI/data/diagramForRegimes/regimes.csv index ccd6c142..e2a6af09 100644 --- a/tests/trnsysGUI/data/diagramForRegimes/regimes.csv +++ b/tests/trnsysGUI/data/diagramForRegimes/regimes.csv @@ -1,4 +1,4 @@ -regimeNames,pump1,pump2,pump3,valve1,valve2 +regimeName,pump1,pump2,pump3,valve1,valve2 "name1",500,0,500,0,0 "name2",500,500,0,0,1 "throws",0,0,500,0,1 \ No newline at end of file diff --git a/tests/trnsysGUI/data/diagramForRegimes/regimes_incorrect.csv b/tests/trnsysGUI/data/diagramForRegimes/regimes_incorrect.csv new file mode 100644 index 00000000..dcea12fc --- /dev/null +++ b/tests/trnsysGUI/data/diagramForRegimes/regimes_incorrect.csv @@ -0,0 +1,4 @@ +regimes,pump1,pump2,pump3,valve1,valve2 +"name1",500,0,500,0,0 +"name2",500,500,0,0,1 +"throws",0,0,500,0,1 \ No newline at end of file diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testGetDesiredRegimes.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testGetDesiredRegimes.py index 3d7f6293..fae75fd1 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testGetDesiredRegimes.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testGetDesiredRegimes.py @@ -1,19 +1,22 @@ import pandas as _pd import pathlib as _pl +import pytest as _pt import trnsysGUI.pythonInterface.regimeExporter.getDesiredRegimes as _gdr import trnsysGUI as _GUI _DATA_DIR_ = _pl.Path(_GUI.__file__).parent / "..\\tests\\trnsysGUI\\data\\diagramForRegimes" +_COL_NAME_ = "regimeName" + class TestGetDesiredRegimes: - def testgetRegimesFromFile(self): + def testGetRegimesFromFile(self): fileName = _DATA_DIR_ / "regimes.csv" df1 = _gdr.getRegimesFromFile(fileName) df2 = _pd.DataFrame( { - "regimeNames": ["name1", "name2", "throws"], + _COL_NAME_: ["name1", "name2", "throws"], "pump1": [500, 500, 0], "pump2": [0, 500, 0], "pump3": [500, 0, 500], @@ -22,3 +25,9 @@ def testgetRegimesFromFile(self): } ) assert df1.equals(df2) + + def testColumnNameIncorrectRaises(self): + fileName = _DATA_DIR_ / "regimes_incorrect.csv" + with _pt.raises(ValueError, match=f"Column name '{_COL_NAME_}' not found."): + _gdr.getRegimesFromFile(fileName) + diff --git a/trnsysGUI/pythonInterface/regimeExporter/getDesiredRegimes.py b/trnsysGUI/pythonInterface/regimeExporter/getDesiredRegimes.py index 0075915c..732c90a4 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/getDesiredRegimes.py +++ b/trnsysGUI/pythonInterface/regimeExporter/getDesiredRegimes.py @@ -1,11 +1,17 @@ import pandas as _pd +# dealing with files where the regimeName column is not provided correctly + def getRegimesFromFile(fileName): df = _pd.read_csv(fileName) - return df - + _COL_NAME_ = "regimeName" + if _COL_NAME_ in df.keys(): + return df + raise ValueError(f"Column name '{_COL_NAME_}' not found.") +# error handling? +# - will throw "fileNotFoundError" as it is. # # # regimeName, name1, name2, name3 From 5661464bffa2a1252b758fd2139b1c62d7bf6a59 Mon Sep 17 00:00:00 2001 From: ahobeost Date: Tue, 13 Jun 2023 14:06:46 +0200 Subject: [PATCH 05/56] Working version of both the massFlow solver and the pdf creation --- .../testPrintRegimesAndCopyFiles.py | 37 ++++++++ trnsysGUI/mainWindow.py | 26 ++--- .../renderDiagramOnPDFfromPython.py | 94 ++++++++++--------- 3 files changed, 104 insertions(+), 53 deletions(-) create mode 100644 tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py new file mode 100644 index 00000000..366c18c7 --- /dev/null +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py @@ -0,0 +1,37 @@ +import pathlib as _pl + +import pytrnsys.utils.log as _ulog + +import trnsysGUI as _GUI +import trnsysGUI.mainWindow as _mw +import trnsysGUI.project as _prj +import trnsysGUI.pythonInterface.regimeExporter.renderDiagramOnPDFfromPython as _rdopfp + +_PROJECT_NAME_ = "diagramForRegimes" +_DATA_DIR_ = _pl.Path(_GUI.__file__).parent / "..\\tests\\trnsysGUI\\data\\diagramForRegimes" +_DATA_FILENAME_ = "regimes.csv" + + +def _createMainWindow(PROJECT_FOLDER, PROJECT_NAME, qtbot): + projectJsonFilePath = PROJECT_FOLDER / f"{PROJECT_NAME}.json" + project = _prj.LoadProject(projectJsonFilePath) + + logger = _ulog.getOrCreateCustomLogger("root", "DEBUG") # type: ignore[attr-defined] + + mainWindow = _mw.MainWindow(logger, project) # type: ignore[attr-defined] + + qtbot.addWidget(mainWindow) + mainWindow.showBoxOnClose = False + + return mainWindow + + +class TestPrintRegimesAndCopyFiles: + def testUsingQtBot(self, qtbot): + mainWindow = _createMainWindow(_DATA_DIR_, _PROJECT_NAME_, qtbot) + _rdopfp.printRegimesAndCopyFiles(_DATA_DIR_, _PROJECT_NAME_, _DATA_FILENAME_, mainWindow) + assert True is False + +# massFlowSolver should raise error when issue encountered. +# rest of workflow should be ignored for this regime, instead a warning should be issued +# non-qtbot solution? \ No newline at end of file diff --git a/trnsysGUI/mainWindow.py b/trnsysGUI/mainWindow.py index 3940cc3a..b2f2eac9 100644 --- a/trnsysGUI/mainWindow.py +++ b/trnsysGUI/mainWindow.py @@ -43,6 +43,7 @@ def __init__(self, logger, project: _prj.Project, parent=None): self.labelVisState = False self.calledByVisualizeMf = False self.currentFile = "Untitled" + self.showBoxOnClose = True # Toolbar actions saveDiaAction = _qtw.QAction(_img.INBOX_PNG.icon(), "Save", self) @@ -545,17 +546,20 @@ def exportPDF(self): self.editor.printPDF() def closeEvent(self, e): - qmb = _qtw.QMessageBox() - qmb.setText("Do you want to save the current state of the project before closing the program?") - qmb.setStandardButtons(_qtw.QMessageBox.Save | _qtw.QMessageBox.Close | _qtw.QMessageBox.Cancel) - qmb.setDefaultButton(_qtw.QMessageBox.Cancel) - ret = qmb.exec() - if ret == _qtw.QMessageBox.Cancel: - e.ignore() - elif ret == _qtw.QMessageBox.Close: - e.accept() - elif ret == _qtw.QMessageBox.Save: - self.editor.save() + if self.showBoxOnClose: + qmb = _qtw.QMessageBox() + qmb.setText("Do you want to save the current state of the project before closing the program?") + qmb.setStandardButtons(_qtw.QMessageBox.Save | _qtw.QMessageBox.Close | _qtw.QMessageBox.Cancel) + qmb.setDefaultButton(_qtw.QMessageBox.Cancel) + ret = qmb.exec() + if ret == _qtw.QMessageBox.Cancel: + e.ignore() + elif ret == _qtw.QMessageBox.Close: + e.accept() + elif ret == _qtw.QMessageBox.Save: + self.editor.save() + e.accept() + else: e.accept() def ensureSettingsExist(self): diff --git a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py index 6729ade8..4270a23e 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py +++ b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py @@ -1,46 +1,46 @@ +import os as _os +import pathlib as _pl +import pytest as _pt +import subprocess as _sp + import PyQt5.QtGui as _qtg import PyQt5.QtPrintSupport as _qtp from tests.trnsysGUI.diagram import _testHelper as _th import trnsysGUI.project as _prj +import trnsysGUI as _GUI +import trnsysGUI.pythonInterface.regimeExporter.getDesiredRegimes as _gdr +import trnsysGUI.mainWindow as _mw +import trnsysGUI.diagram.Editor as _de -def printDiagramToPDF(self, fileName): - if fileName != "": - printer = _qtp.QPrinter(_qtp.QPrinter.HighResolution) - printer.setOrientation(_qtp.QPrinter.Landscape) - printer.setOutputFormat(_qtp.QPrinter.PdfFormat) - printer.setOutputFileName(fileName) - painter = _qtg.QPainter(printer) - self.diagramScene.render(painter) - painter.end() - self.logger.info("File exported to %s" % fileName) - # regimeValue = {regimeName: "", pumps: [], valves [] } # regimeValues = df[] # for regimeRow in df: +def printRegimesAndCopyFiles(_DATA_DIR_, _PROJECT_NAME_, _DATA_FILENAME_, mainWindow): + regimeValues = _gdr.getRegimesFromFile(_DATA_DIR_ / _DATA_FILENAME_) + for ix in regimeValues.index: + regimeRow = regimeValues.loc[ix] + regimeName = regimeRow["regimeName"] + print(regimeName) + # adjustPumpsAndValves() + runMassFlowSolver(mainWindow) + # copyMFRandTfiles() + # adjustSlider(steps=2) -PROJECT_NAME = "PCM_reverseable_airsource_HP_reduced" -PROJECT_FOLDER = "." - -def printRegimesAndCopyFiles(): - mainWindow = self._createMainWindow(PROJECT_FOLDER, PROJECT_NAME, qtbot, monkeypatch) - - regimeValues = getRegimesValues() - for regimeRow in regimeValues.rows(): - adjustPumpsAndValves() - runMassFlowSolver() - copyMFRandTfiles() - adjustSlider(steps=2) - printDiagramToPDF() - + pdfName = str(_DATA_DIR_) + "\\" + _PROJECT_NAME_ + "_" + regimeName + ".pdf" + print(pdfName) + printDiagramToPDF(pdfName, mainWindow) + break -def runMassFlowSolver(self, PROJECT_NAME, PROJECT_FOLDER, qtbot, monkeypatch) -> None: - - self._exportMassFlowSolverDeckAndRunTrnsys(mainWindow.editor) +def runMassFlowSolver(mainWindow) -> None: + try: + _exportMassFlowSolverDeckAndRunTrnsys(mainWindow.editor) + except Exception: + raise # massFlowSolverDeckFileName = f"{PROJECT_NAME}_mfs.dck" @@ -52,23 +52,33 @@ def runMassFlowSolver(self, PROJECT_NAME, PROJECT_FOLDER, qtbot, monkeypatch) -> # printDiagramToPDF() -def _createMainWindow(PROJECT_FOLDER, PROJECT_NAME, qtbot, monkeypatch): - def patchedCloseEvent(_, closeEvent): - return closeEvent.accept() +def _exportMassFlowSolverDeckAndRunTrnsys(editor: _de.Editor): # type: ignore[name-defined] + exportedFilePath = _exportHydraulic(editor, _format="mfs") + + trnExePath = _getTrnExePath() + + _sp.run([str(trnExePath), str(exportedFilePath), "/H"], check=True) - monkeypatch.setattr( - _mw.MainWindow, # type: ignore[attr-defined] - _mw.MainWindow.closeEvent.__name__, # type: ignore[attr-defined] - patchedCloseEvent, - ) - projectJsonFilePath = PROJECT_FOLDER / f"{PROJECT_NAME}.json" - project = _prj.LoadProject(projectJsonFilePath) +def _exportHydraulic(editor: _de.Editor, *, _format) -> str: # type: ignore[name-defined] + exportedFilePath = editor.exportHydraulics(exportTo=_format) + return exportedFilePath - logger = _ulog.getOrCreateCustomLogger("root", "DEBUG") # type: ignore[attr-defined] - mainWindow = _mw.MainWindow(logger, project) # type: ignore[attr-defined] +def _getTrnExePath(): + isRunDuringCi = _os.environ.get("CI") == "true" + if isRunDuringCi: + return _pl.PureWindowsPath(r"C:\CI-Progams\TRNSYS18\Exe\TrnEXE.exe") - qtbot.addWidget(mainWindow) + return _pl.PureWindowsPath(r"C:\TRNSYS18\Exe\TrnEXE.exe") - return mainWindow + +def printDiagramToPDF(fileName, mainWindow): + if fileName != "": + printer = _qtp.QPrinter(_qtp.QPrinter.HighResolution) + printer.setOrientation(_qtp.QPrinter.Landscape) + printer.setOutputFormat(_qtp.QPrinter.PdfFormat) + printer.setOutputFileName(fileName) + painter = _qtg.QPainter(printer) + mainWindow.editor.diagramScene.render(painter) + painter.end() From e1034741591ea0e2f7b6830cb50eca9c92c06c5b Mon Sep 17 00:00:00 2001 From: ahobeost Date: Wed, 14 Jun 2023 11:28:12 +0200 Subject: [PATCH 06/56] Working version of the regime exporter, without tests for the PDFS --- .../diagramForRegimes/diagramForRegimes.json | 10 +- .../testPrintRegimesAndCopyFiles.py | 2 - .../renderDiagramOnPDFfromPython.py | 94 +++++++++++++++---- 3 files changed, 80 insertions(+), 26 deletions(-) diff --git a/tests/trnsysGUI/data/diagramForRegimes/diagramForRegimes.json b/tests/trnsysGUI/data/diagramForRegimes/diagramForRegimes.json index f69b1ab1..7623c84c 100644 --- a/tests/trnsysGUI/data/diagramForRegimes/diagramForRegimes.json +++ b/tests/trnsysGUI/data/diagramForRegimes/diagramForRegimes.json @@ -3,7 +3,7 @@ ".__BlockDct__": true, "Block-1": { ".__BlockDict__": true, - "BlockDisplayName": "Pump2", + "BlockDisplayName": "pump2", "BlockName": "Pump", "Id": 1, "__version__": "9552365f-ef11-4fac-ba35-644e94b54088", @@ -25,7 +25,7 @@ }, "Block-10": { ".__BlockDict__": true, - "BlockDisplayName": "Valve1", + "BlockDisplayName": "valve1", "BlockName": "TVentil", "Id": 10, "IsTempering": false, @@ -49,7 +49,7 @@ }, "Block-14": { ".__BlockDict__": true, - "BlockDisplayName": "Valve2", + "BlockDisplayName": "valve2", "BlockName": "TVentil", "Id": 14, "IsTempering": false, @@ -138,7 +138,7 @@ }, "Block-4": { ".__BlockDict__": true, - "BlockDisplayName": "Pump3", + "BlockDisplayName": "pump3", "BlockName": "Pump", "Id": 4, "__version__": "9552365f-ef11-4fac-ba35-644e94b54088", @@ -160,7 +160,7 @@ }, "Block-7": { ".__BlockDict__": true, - "BlockDisplayName": "Pump1", + "BlockDisplayName": "pump1", "BlockName": "Pump", "Id": 7, "__version__": "9552365f-ef11-4fac-ba35-644e94b54088", diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py index 366c18c7..ad296040 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py @@ -32,6 +32,4 @@ def testUsingQtBot(self, qtbot): _rdopfp.printRegimesAndCopyFiles(_DATA_DIR_, _PROJECT_NAME_, _DATA_FILENAME_, mainWindow) assert True is False -# massFlowSolver should raise error when issue encountered. -# rest of workflow should be ignored for this regime, instead a warning should be issued # non-qtbot solution? \ No newline at end of file diff --git a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py index 4270a23e..9a50c153 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py +++ b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py @@ -2,6 +2,7 @@ import pathlib as _pl import pytest as _pt import subprocess as _sp +import typing as _tp import PyQt5.QtGui as _qtg import PyQt5.QtPrintSupport as _qtp @@ -11,24 +12,59 @@ import trnsysGUI as _GUI import trnsysGUI.pythonInterface.regimeExporter.getDesiredRegimes as _gdr import trnsysGUI.mainWindow as _mw +import trnsysGUI.MassFlowVisualizer as _mfv import trnsysGUI.diagram.Editor as _de # regimeValue = {regimeName: "", pumps: [], valves [] } # regimeValues = df[] # for regimeRow in df: +import trnsysGUI.pump as _pump +import trnsysGUI.TVentil as _tv + + +def getPumpsAndValves(pumpsAndValvesNames, mainWindow): + pumpsAndValves = [] + blockItemsAndConnections = mainWindow.editor.trnsysObj + for blockItem in blockItemsAndConnections: + if isinstance(blockItem, _pump.Pump) or isinstance(blockItem, _tv.TVentil): + if blockItem.displayName in pumpsAndValvesNames: + pumpsAndValves.append(blockItem) + return pumpsAndValves def printRegimesAndCopyFiles(_DATA_DIR_, _PROJECT_NAME_, _DATA_FILENAME_, mainWindow): + # createPDF of diagram only + regimeValues = _gdr.getRegimesFromFile(_DATA_DIR_ / _DATA_FILENAME_) + pumpsAndValvesNames = list(regimeValues.columns) + pumpsAndValvesNames.remove('regimeName') + massFlowRatesPrintFileName = f"{_PROJECT_NAME_}_Mfr.prt" + temperaturesPintFileName = f"{_PROJECT_NAME_}_T.prt" + massFlowRatesPrintFilePath = _DATA_DIR_ / massFlowRatesPrintFileName + temperaturesPrintFilePath = _DATA_DIR_ / temperaturesPintFileName + pumpsAndValves = getPumpsAndValves(pumpsAndValvesNames, mainWindow) + for ix in regimeValues.index: regimeRow = regimeValues.loc[ix] regimeName = regimeRow["regimeName"] - print(regimeName) - # adjustPumpsAndValves() - runMassFlowSolver(mainWindow) - # copyMFRandTfiles() - # adjustSlider(steps=2) + + adjustPumpsAndValves(pumpsAndValves, regimeRow) + + exception = runMassFlowSolver(mainWindow) + + if not exception: + print("massflowSolver ran without issue") + # copyMFRandTfiles() + timeStep = 2 + else: + regimeName = regimeName + "_FAILED" + timeStep = 1 + + massFlowSolverVisualizer = _mfv.MassFlowVisualizer( # type: ignore[attr-defined] # pylint: disable=unused-variable + mainWindow, massFlowRatesPrintFilePath, temperaturesPrintFilePath + ) + massFlowSolverVisualizer.slider.setValue(timeStep) pdfName = str(_DATA_DIR_) + "\\" + _PROJECT_NAME_ + "_" + regimeName + ".pdf" print(pdfName) @@ -36,28 +72,33 @@ def printRegimesAndCopyFiles(_DATA_DIR_, _PROJECT_NAME_, _DATA_FILENAME_, mainWi break -def runMassFlowSolver(mainWindow) -> None: - try: - _exportMassFlowSolverDeckAndRunTrnsys(mainWindow.editor) - except Exception: - raise +def adjustPumpsAndValves(pumpsAndValves, regimeRow): - # massFlowSolverDeckFileName = f"{PROJECT_NAME}_mfs.dck" + for blockItem in pumpsAndValves: + blockItemName = blockItem.displayName + desiredValue = regimeRow[blockItemName] + if isinstance(blockItem, _pump.Pump): + # assert desiredValue meaningful + blockItem.massFlowRateInKgPerH = desiredValue + elif isinstance(blockItem, _tv.TVentil): + # assert desiredValue meaningful + blockItem.positionForMassFlowSolver = desiredValue + else: + raise TypeError(f'Encountered blockItem of type {blockItem}, instead of a pump or a Valve') - # copyMFRandTfiles(NAME, regimeName) - # massFlowRatesPrintFileName = f"{PROJECT_NAME}_Mfr.prt" - # temperaturesPintFileName = f"{PROJECT_NAME}_T.prt" - # moveSlider(steps=2) - # printDiagramToPDF() +def runMassFlowSolver(mainWindow) -> _tp.Optional[Exception]: + exception = _exportMassFlowSolverDeckAndRunTrnsys(mainWindow.editor) + return exception def _exportMassFlowSolverDeckAndRunTrnsys(editor: _de.Editor): # type: ignore[name-defined] - exportedFilePath = _exportHydraulic(editor, _format="mfs") + exportedFilePath = str(_exportHydraulic(editor, _format="mfs")) - trnExePath = _getTrnExePath() + trnExePath = str(_getTrnExePath()) - _sp.run([str(trnExePath), str(exportedFilePath), "/H"], check=True) + skipOther, exception = runDck(trnExePath, exportedFilePath) + return exception def _exportHydraulic(editor: _de.Editor, *, _format) -> str: # type: ignore[name-defined] @@ -82,3 +123,18 @@ def printDiagramToPDF(fileName, mainWindow): painter = _qtg.QPainter(printer) mainWindow.editor.diagramScene.render(painter) painter.end() + + +def runDck(cmd, dckName): + exception = None + try: + if _os.path.isfile(dckName): + _sp.run([cmd, dckName, "/H"], shell=True, check=True) + skipOthers = False + else: + raise FileNotFoundError("File not found: " + dckName) + except Exception as e: + skipOthers = True + exception = e + + return skipOthers, exception From df5a944f0bff3581197e6bf7c8f97e53ef0820e8 Mon Sep 17 00:00:00 2001 From: ahobeost Date: Wed, 14 Jun 2023 14:42:39 +0200 Subject: [PATCH 07/56] Creating diagram only pdf, forcing overwrite, and closing visualizer --- .../regimeExporter/testPrintRegimesAndCopyFiles.py | 1 + trnsysGUI/diagram/Editor.py | 3 ++- .../regimeExporter/renderDiagramOnPDFfromPython.py | 12 +++--------- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py index ad296040..d77d6d8a 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py @@ -22,6 +22,7 @@ def _createMainWindow(PROJECT_FOLDER, PROJECT_NAME, qtbot): qtbot.addWidget(mainWindow) mainWindow.showBoxOnClose = False + mainWindow.editor.forceOverwrite = True return mainWindow diff --git a/trnsysGUI/diagram/Editor.py b/trnsysGUI/diagram/Editor.py index 853c0a68..80fd16ff 100644 --- a/trnsysGUI/diagram/Editor.py +++ b/trnsysGUI/diagram/Editor.py @@ -65,6 +65,7 @@ class Editor(_qtw.QWidget): def __init__(self, parent, projectFolder, jsonPath, loadValue, logger): super().__init__(parent) + self.forceOverwrite = False self.logger = logger self.logger.info("Initializing the diagram editor") @@ -615,7 +616,7 @@ def _isHydraulicConnected(self) -> bool: return True def _doesFileExistAndDontOverwrite(self, folderPath): - if not _pl.Path(folderPath).exists(): + if not _pl.Path(folderPath).exists() or self.forceOverwrite: return False qmb = _qtw.QMessageBox(self) diff --git a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py index 9a50c153..d7ac2e0f 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py +++ b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py @@ -1,24 +1,16 @@ import os as _os import pathlib as _pl -import pytest as _pt import subprocess as _sp import typing as _tp import PyQt5.QtGui as _qtg import PyQt5.QtPrintSupport as _qtp -from tests.trnsysGUI.diagram import _testHelper as _th -import trnsysGUI.project as _prj -import trnsysGUI as _GUI import trnsysGUI.pythonInterface.regimeExporter.getDesiredRegimes as _gdr -import trnsysGUI.mainWindow as _mw import trnsysGUI.MassFlowVisualizer as _mfv import trnsysGUI.diagram.Editor as _de -# regimeValue = {regimeName: "", pumps: [], valves [] } -# regimeValues = df[] -# for regimeRow in df: import trnsysGUI.pump as _pump import trnsysGUI.TVentil as _tv @@ -35,6 +27,8 @@ def getPumpsAndValves(pumpsAndValvesNames, mainWindow): def printRegimesAndCopyFiles(_DATA_DIR_, _PROJECT_NAME_, _DATA_FILENAME_, mainWindow): # createPDF of diagram only + pdfName = str(_DATA_DIR_) + "\\" + _PROJECT_NAME_ + "_diagram.pdf" + printDiagramToPDF(pdfName, mainWindow) regimeValues = _gdr.getRegimesFromFile(_DATA_DIR_ / _DATA_FILENAME_) pumpsAndValvesNames = list(regimeValues.columns) @@ -67,8 +61,8 @@ def printRegimesAndCopyFiles(_DATA_DIR_, _PROJECT_NAME_, _DATA_FILENAME_, mainWi massFlowSolverVisualizer.slider.setValue(timeStep) pdfName = str(_DATA_DIR_) + "\\" + _PROJECT_NAME_ + "_" + regimeName + ".pdf" - print(pdfName) printDiagramToPDF(pdfName, mainWindow) + massFlowSolverVisualizer.close() break From fa08aaf1eacc86161139e552f62d93abf7b5b2e5 Mon Sep 17 00:00:00 2001 From: ahobeost Date: Thu, 22 Jun 2023 16:08:25 +0200 Subject: [PATCH 08/56] added pdf_similar tests --- .../diagramForRegimes_diagram.pdf | Bin 0 -> 47255 bytes .../expectedPDFs/diagramForRegimes_name1.pdf | Bin 33140 -> 33078 bytes .../expectedPDFs/diagramForRegimes_name2.pdf | Bin 46458 -> 33092 bytes .../testPrintRegimesAndCopyFiles.py | 29 +++++++++- trnsysGUI/WTap_main.py | 3 +- .../regimeExporter/getDesiredRegimes.py | 10 +++- .../renderDiagramOnPDFfromPython.py | 54 ++++++++++++++---- 7 files changed, 81 insertions(+), 15 deletions(-) create mode 100644 tests/trnsysGUI/data/diagramForRegimes/expectedPDFs/diagramForRegimes_diagram.pdf diff --git a/tests/trnsysGUI/data/diagramForRegimes/expectedPDFs/diagramForRegimes_diagram.pdf b/tests/trnsysGUI/data/diagramForRegimes/expectedPDFs/diagramForRegimes_diagram.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c0e948010babf277b855b32d159c8350cd29c836 GIT binary patch literal 47255 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

T{CM?h| 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 literal 0 HcmV?d00001 diff --git a/tests/trnsysGUI/data/diagramForRegimes/expectedPDFs/diagramForRegimes_name1.pdf b/tests/trnsysGUI/data/diagramForRegimes/expectedPDFs/diagramForRegimes_name1.pdf index b9a67a3d5d0f83ad048d5d1c8955515b7896d9c6..236fee2f86191da80bc1e336d3f12057c0f6c7e6 100644 GIT binary patch delta 10059 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 diff --git a/tests/trnsysGUI/data/diagramForRegimes/expectedPDFs/diagramForRegimes_name2.pdf b/tests/trnsysGUI/data/diagramForRegimes/expectedPDFs/diagramForRegimes_name2.pdf index c9c0fa4ad70d93b35dffdfdd74681d0d7fb94604..33328c89d4d31355137b8a92c72e6dbd22c63d45 100644 GIT binary patch delta 10839 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 diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py index d77d6d8a..83a40b87 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py @@ -1,4 +1,6 @@ +import unittest as _ut import pathlib as _pl +from diff_pdf_visually import pdf_similar import pytrnsys.utils.log as _ulog @@ -10,6 +12,7 @@ _PROJECT_NAME_ = "diagramForRegimes" _DATA_DIR_ = _pl.Path(_GUI.__file__).parent / "..\\tests\\trnsysGUI\\data\\diagramForRegimes" _DATA_FILENAME_ = "regimes.csv" +_EXPECTED_PDFS_DIR_ = _DATA_DIR_ / "expectedPDFs" def _createMainWindow(PROJECT_FOLDER, PROJECT_NAME, qtbot): @@ -31,6 +34,30 @@ class TestPrintRegimesAndCopyFiles: def testUsingQtBot(self, qtbot): mainWindow = _createMainWindow(_DATA_DIR_, _PROJECT_NAME_, qtbot) _rdopfp.printRegimesAndCopyFiles(_DATA_DIR_, _PROJECT_NAME_, _DATA_FILENAME_, mainWindow) - assert True is False + pdfDiagram = _PROJECT_NAME_ + "_diagram.pdf" + pdfName1 = _PROJECT_NAME_ + "_name1.pdf" + pdfName2 = _PROJECT_NAME_ + "_name2.pdf" + pdfPathDiagram = _DATA_DIR_ / pdfDiagram + pdfPathName1 = _DATA_DIR_ / pdfName1 + pdfPathName2 = _DATA_DIR_ / pdfName2 + assert pdfPathDiagram.is_file() + assert pdfPathName1.is_file() + assert pdfPathName2.is_file() + pdf_similar(pdfPathDiagram, _EXPECTED_PDFS_DIR_ / pdfDiagram) + pdf_similar(pdfPathName1, _EXPECTED_PDFS_DIR_ / pdfName1) + pdf_similar(pdfPathName2, _EXPECTED_PDFS_DIR_ / pdfName2) + + def testUsingQtBotForGivenRegimes(self, qtbot): + onlyTheseRegimes = ["name1"] + mainWindow = _createMainWindow(_DATA_DIR_, _PROJECT_NAME_, qtbot) + _rdopfp.printRegimesAndCopyFiles(_DATA_DIR_, _PROJECT_NAME_, _DATA_FILENAME_, mainWindow, onlyTheseRegimes=onlyTheseRegimes) + pdfName1 = _PROJECT_NAME_ + "_name1.pdf" + pdfName2 = _PROJECT_NAME_ + "_name2.pdf" + pdfPathName1 = _DATA_DIR_ / pdfName1 + pdfPathName2 = _DATA_DIR_ / pdfName2 + assert pdfPathName1.is_file() + assert not pdfPathName2.is_file() + + # non-qtbot solution? \ No newline at end of file diff --git a/trnsysGUI/WTap_main.py b/trnsysGUI/WTap_main.py index 60bb74cb..e1e2f142 100644 --- a/trnsysGUI/WTap_main.py +++ b/trnsysGUI/WTap_main.py @@ -22,6 +22,7 @@ def __init__(self, trnsysType, editor, **kwargs): self._modelSource = _mfn.Source(outputPort) self.changeSize() + self.massFlowRateInKgPerH = 1000 def getDisplayName(self) -> str: return self.displayName @@ -64,7 +65,7 @@ def changeSize(self): return w, h def exportMassFlows(self): - resStr = "Mfr" + self.displayName + " = 1000" + "\n" + resStr = "Mfr" + self.displayName + f" = {self.massFlowRateInKgPerH}" + "\n" equationNr = 1 return resStr, equationNr diff --git a/trnsysGUI/pythonInterface/regimeExporter/getDesiredRegimes.py b/trnsysGUI/pythonInterface/regimeExporter/getDesiredRegimes.py index 732c90a4..612de623 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/getDesiredRegimes.py +++ b/trnsysGUI/pythonInterface/regimeExporter/getDesiredRegimes.py @@ -18,4 +18,12 @@ def getRegimesFromFile(fileName): # regime, value1, value2, value3 # # if isPump(name): -# if isValve(name): \ No newline at end of file +# if isValve(name): + + +def getRegimes(filePath, onlyTheseRegimes): + regimeValues = getRegimesFromFile(filePath) + regimeValues = regimeValues.set_index('regimeName') + if onlyTheseRegimes: + return regimeValues.loc[onlyTheseRegimes] + return regimeValues diff --git a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py index d7ac2e0f..57c2add6 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py +++ b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py @@ -5,6 +5,8 @@ import PyQt5.QtGui as _qtg import PyQt5.QtPrintSupport as _qtp +import PyQt5.QtSvg as _qtsvg +import PyQt5.QtCore as _qtc import trnsysGUI.pythonInterface.regimeExporter.getDesiredRegimes as _gdr import trnsysGUI.MassFlowVisualizer as _mfv @@ -14,36 +16,48 @@ import trnsysGUI.pump as _pump import trnsysGUI.TVentil as _tv +import trnsysGUI.WTap_main as _wtm -def getPumpsAndValves(pumpsAndValvesNames, mainWindow): + +def getPumpsAndValvesAndMainTaps(pumpsAndValvesNames, mainWindow): pumpsAndValves = [] + mainTaps = dict() blockItemsAndConnections = mainWindow.editor.trnsysObj for blockItem in blockItemsAndConnections: if isinstance(blockItem, _pump.Pump) or isinstance(blockItem, _tv.TVentil): if blockItem.displayName in pumpsAndValvesNames: pumpsAndValves.append(blockItem) - return pumpsAndValves + elif isinstance(blockItem, _wtm.WTap_main): + mainTaps[blockItem.displayName] = blockItem + + return pumpsAndValves, mainTaps +# def changeMfrOfTaps(tapNames): +# with in_place.InPlace('data.txt') as file: +# for line in file: +# line = line.replace('test', 'testZ') +# file.write(line) -def printRegimesAndCopyFiles(_DATA_DIR_, _PROJECT_NAME_, _DATA_FILENAME_, mainWindow): + +def printRegimesAndCopyFiles(_DATA_DIR_, _PROJECT_NAME_, _DATA_FILENAME_, mainWindow, pumpTapPairs=None, onlyTheseRegimes=None): # list for onlyTheseRegimes # createPDF of diagram only pdfName = str(_DATA_DIR_) + "\\" + _PROJECT_NAME_ + "_diagram.pdf" printDiagramToPDF(pdfName, mainWindow) - regimeValues = _gdr.getRegimesFromFile(_DATA_DIR_ / _DATA_FILENAME_) + regimeValues = _gdr.getRegimes(_DATA_DIR_ / _DATA_FILENAME_, onlyTheseRegimes) pumpsAndValvesNames = list(regimeValues.columns) - pumpsAndValvesNames.remove('regimeName') + # pumpsAndValvesNames.remove('regimeName') massFlowRatesPrintFileName = f"{_PROJECT_NAME_}_Mfr.prt" temperaturesPintFileName = f"{_PROJECT_NAME_}_T.prt" massFlowRatesPrintFilePath = _DATA_DIR_ / massFlowRatesPrintFileName temperaturesPrintFilePath = _DATA_DIR_ / temperaturesPintFileName - pumpsAndValves = getPumpsAndValves(pumpsAndValvesNames, mainWindow) + pumpsAndValves, mainTaps = getPumpsAndValvesAndMainTaps(pumpsAndValvesNames, mainWindow) - for ix in regimeValues.index: - regimeRow = regimeValues.loc[ix] - regimeName = regimeRow["regimeName"] + for regimeName in regimeValues.index: + regimeRow = regimeValues.loc[regimeName] + # regimeName = regimeRow["regimeName"] - adjustPumpsAndValves(pumpsAndValves, regimeRow) + adjustPumpsAndValves(pumpsAndValves, regimeRow, pumpTapPairs, mainTaps) exception = runMassFlowSolver(mainWindow) @@ -61,12 +75,13 @@ def printRegimesAndCopyFiles(_DATA_DIR_, _PROJECT_NAME_, _DATA_FILENAME_, mainWi massFlowSolverVisualizer.slider.setValue(timeStep) pdfName = str(_DATA_DIR_) + "\\" + _PROJECT_NAME_ + "_" + regimeName + ".pdf" + svgName = str(_DATA_DIR_) + "\\" + _PROJECT_NAME_ + "_" + regimeName + ".svg" printDiagramToPDF(pdfName, mainWindow) + printDiagramToSVG(svgName, mainWindow) massFlowSolverVisualizer.close() - break -def adjustPumpsAndValves(pumpsAndValves, regimeRow): +def adjustPumpsAndValves(pumpsAndValves, regimeRow, pumpTapPairs, mainTaps): for blockItem in pumpsAndValves: blockItemName = blockItem.displayName @@ -74,6 +89,9 @@ def adjustPumpsAndValves(pumpsAndValves, regimeRow): if isinstance(blockItem, _pump.Pump): # assert desiredValue meaningful blockItem.massFlowRateInKgPerH = desiredValue + if pumpTapPairs and (blockItemName in pumpTapPairs): + associatedTap = pumpTapPairs[blockItemName] + mainTaps[associatedTap].massFlowRateInKgPerH = desiredValue elif isinstance(blockItem, _tv.TVentil): # assert desiredValue meaningful blockItem.positionForMassFlowSolver = desiredValue @@ -119,6 +137,18 @@ def printDiagramToPDF(fileName, mainWindow): painter.end() +def printDiagramToSVG(fileName, mainWindow): + # upside down and tiny compared to canvas + if fileName != "": + generator = _qtsvg.QSvgGenerator() + generator.setSize(_qtc.QSize(1600, 1600)) + generator.setViewBox(_qtc.QRect(0, 0, 1600, 1600)) + generator.setFileName(fileName) + painter = _qtg.QPainter(generator) + mainWindow.editor.diagramScene.render(painter) + painter.end() + + def runDck(cmd, dckName): exception = None try: From 0c65ebdaeffa5944bb66c56d154a9cee74fe2725 Mon Sep 17 00:00:00 2001 From: ahobeost Date: Thu, 22 Jun 2023 16:34:27 +0200 Subject: [PATCH 09/56] More accurate tests --- .../regimeExporter/testPrintRegimesAndCopyFiles.py | 14 ++++++++++---- .../regimeExporter/renderDiagramOnPDFfromPython.py | 5 +++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py index 83a40b87..581475dc 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py @@ -1,6 +1,6 @@ import unittest as _ut import pathlib as _pl -from diff_pdf_visually import pdf_similar +import diff_pdf_visually as _dpv import pytrnsys.utils.log as _ulog @@ -43,20 +43,26 @@ def testUsingQtBot(self, qtbot): assert pdfPathDiagram.is_file() assert pdfPathName1.is_file() assert pdfPathName2.is_file() - pdf_similar(pdfPathDiagram, _EXPECTED_PDFS_DIR_ / pdfDiagram) - pdf_similar(pdfPathName1, _EXPECTED_PDFS_DIR_ / pdfName1) - pdf_similar(pdfPathName2, _EXPECTED_PDFS_DIR_ / pdfName2) + _dpv.pdf_similar(pdfPathDiagram, _EXPECTED_PDFS_DIR_ / pdfDiagram) + _dpv.pdf_similar(pdfPathName1, _EXPECTED_PDFS_DIR_ / pdfName1) + _dpv.pdf_similar(pdfPathName2, _EXPECTED_PDFS_DIR_ / pdfName2) def testUsingQtBotForGivenRegimes(self, qtbot): onlyTheseRegimes = ["name1"] mainWindow = _createMainWindow(_DATA_DIR_, _PROJECT_NAME_, qtbot) _rdopfp.printRegimesAndCopyFiles(_DATA_DIR_, _PROJECT_NAME_, _DATA_FILENAME_, mainWindow, onlyTheseRegimes=onlyTheseRegimes) + pdfDiagram = _PROJECT_NAME_ + "_diagram.pdf" pdfName1 = _PROJECT_NAME_ + "_name1.pdf" pdfName2 = _PROJECT_NAME_ + "_name2.pdf" + pdfPathDiagram = _DATA_DIR_ / pdfDiagram pdfPathName1 = _DATA_DIR_ / pdfName1 pdfPathName2 = _DATA_DIR_ / pdfName2 + assert not pdfPathDiagram.is_file() assert pdfPathName1.is_file() assert not pdfPathName2.is_file() + _dpv.pdf_similar(pdfPathName1, _EXPECTED_PDFS_DIR_ / pdfName1) + + diff --git a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py index 57c2add6..7d2ccd43 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py +++ b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py @@ -41,8 +41,9 @@ def getPumpsAndValvesAndMainTaps(pumpsAndValvesNames, mainWindow): def printRegimesAndCopyFiles(_DATA_DIR_, _PROJECT_NAME_, _DATA_FILENAME_, mainWindow, pumpTapPairs=None, onlyTheseRegimes=None): # list for onlyTheseRegimes # createPDF of diagram only - pdfName = str(_DATA_DIR_) + "\\" + _PROJECT_NAME_ + "_diagram.pdf" - printDiagramToPDF(pdfName, mainWindow) + if not onlyTheseRegimes: + pdfName = str(_DATA_DIR_) + "\\" + _PROJECT_NAME_ + "_diagram.pdf" + printDiagramToPDF(pdfName, mainWindow) regimeValues = _gdr.getRegimes(_DATA_DIR_ / _DATA_FILENAME_, onlyTheseRegimes) pumpsAndValvesNames = list(regimeValues.columns) From b900af550d8acaf0564c15aa7def2457b61c6681 Mon Sep 17 00:00:00 2001 From: ahobeost Date: Thu, 22 Jun 2023 16:53:57 +0200 Subject: [PATCH 10/56] refactoring tests --- .../testPrintRegimesAndCopyFiles.py | 49 ++++++++++--------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py index 581475dc..3974094a 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py @@ -14,6 +14,22 @@ _DATA_FILENAME_ = "regimes.csv" _EXPECTED_PDFS_DIR_ = _DATA_DIR_ / "expectedPDFs" +_DIAGRAM_ENDING_ = "_diagram.pdf" +_NAME1_ENDING_ = "_name1.pdf" +_NAME2_ENDING_ = "_name2.pdf" + + +def _getExpectedAndNewPdfPaths(ending): + pdfName = _PROJECT_NAME_ + ending + expectedPdfPath = _EXPECTED_PDFS_DIR_ / pdfName + newPdfPath = _DATA_DIR_ / pdfName + return expectedPdfPath, newPdfPath + + +_EXPECTED_DIAGRAM_PATH_, _NEW_DIAGRAM_PATH_ = _getExpectedAndNewPdfPaths(_DIAGRAM_ENDING_) +_EXPECTED_NAME1_PATH_, _NEW_NAME1_PATH_ = _getExpectedAndNewPdfPaths(_NAME1_ENDING_) +_EXPECTED_NAME2_PATH_, _NEW_NAME2_PATH_ = _getExpectedAndNewPdfPaths(_NAME2_ENDING_) + def _createMainWindow(PROJECT_FOLDER, PROJECT_NAME, qtbot): projectJsonFilePath = PROJECT_FOLDER / f"{PROJECT_NAME}.json" @@ -34,33 +50,22 @@ class TestPrintRegimesAndCopyFiles: def testUsingQtBot(self, qtbot): mainWindow = _createMainWindow(_DATA_DIR_, _PROJECT_NAME_, qtbot) _rdopfp.printRegimesAndCopyFiles(_DATA_DIR_, _PROJECT_NAME_, _DATA_FILENAME_, mainWindow) - pdfDiagram = _PROJECT_NAME_ + "_diagram.pdf" - pdfName1 = _PROJECT_NAME_ + "_name1.pdf" - pdfName2 = _PROJECT_NAME_ + "_name2.pdf" - pdfPathDiagram = _DATA_DIR_ / pdfDiagram - pdfPathName1 = _DATA_DIR_ / pdfName1 - pdfPathName2 = _DATA_DIR_ / pdfName2 - assert pdfPathDiagram.is_file() - assert pdfPathName1.is_file() - assert pdfPathName2.is_file() - _dpv.pdf_similar(pdfPathDiagram, _EXPECTED_PDFS_DIR_ / pdfDiagram) - _dpv.pdf_similar(pdfPathName1, _EXPECTED_PDFS_DIR_ / pdfName1) - _dpv.pdf_similar(pdfPathName2, _EXPECTED_PDFS_DIR_ / pdfName2) + + self._FileExistsAndIsCorrect(_NEW_DIAGRAM_PATH_, _EXPECTED_DIAGRAM_PATH_) + self._FileExistsAndIsCorrect(_NEW_NAME1_PATH_, _EXPECTED_NAME1_PATH_) + self._FileExistsAndIsCorrect(_NEW_NAME2_PATH_, _EXPECTED_NAME2_PATH_) + + def _FileExistsAndIsCorrect(self, producedPdf, expectedPdf): + assert producedPdf.is_file() + _dpv.pdf_similar(producedPdf, expectedPdf) def testUsingQtBotForGivenRegimes(self, qtbot): onlyTheseRegimes = ["name1"] mainWindow = _createMainWindow(_DATA_DIR_, _PROJECT_NAME_, qtbot) _rdopfp.printRegimesAndCopyFiles(_DATA_DIR_, _PROJECT_NAME_, _DATA_FILENAME_, mainWindow, onlyTheseRegimes=onlyTheseRegimes) - pdfDiagram = _PROJECT_NAME_ + "_diagram.pdf" - pdfName1 = _PROJECT_NAME_ + "_name1.pdf" - pdfName2 = _PROJECT_NAME_ + "_name2.pdf" - pdfPathDiagram = _DATA_DIR_ / pdfDiagram - pdfPathName1 = _DATA_DIR_ / pdfName1 - pdfPathName2 = _DATA_DIR_ / pdfName2 - assert not pdfPathDiagram.is_file() - assert pdfPathName1.is_file() - assert not pdfPathName2.is_file() - _dpv.pdf_similar(pdfPathName1, _EXPECTED_PDFS_DIR_ / pdfName1) + self._FileExistsAndIsCorrect(_NEW_NAME1_PATH_, _EXPECTED_NAME1_PATH_) + assert not _NEW_DIAGRAM_PATH_.is_file() + assert not _NEW_NAME2_PATH_.is_file() From e154ff915bc0e69b30e627bd7fc44f13a57f1eb1 Mon Sep 17 00:00:00 2001 From: ahobeost Date: Thu, 22 Jun 2023 17:27:54 +0200 Subject: [PATCH 11/56] Cleanup and using matplotlib instead of pdf_similar --- .../expectedPDFs/diagramForRegimes_name1.svg | 1927 +++++++++++++++++ .../regimeExporter/testGetDesiredRegimes.py | 4 +- .../testPrintRegimesAndCopyFiles.py | 21 +- .../regimeExporter/getDesiredRegimes.py | 10 +- .../renderDiagramOnPDFfromPython.py | 13 +- 5 files changed, 1953 insertions(+), 22 deletions(-) create mode 100644 tests/trnsysGUI/data/diagramForRegimes/expectedPDFs/diagramForRegimes_name1.svg diff --git a/tests/trnsysGUI/data/diagramForRegimes/expectedPDFs/diagramForRegimes_name1.svg b/tests/trnsysGUI/data/diagramForRegimes/expectedPDFs/diagramForRegimes_name1.svg new file mode 100644 index 00000000..a00f9b97 --- /dev/null +++ b/tests/trnsysGUI/data/diagramForRegimes/expectedPDFs/diagramForRegimes_name1.svg @@ -0,0 +1,1927 @@ + + +Qt SVG Document +Generated with Qt + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testGetDesiredRegimes.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testGetDesiredRegimes.py index fae75fd1..56e943c3 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testGetDesiredRegimes.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testGetDesiredRegimes.py @@ -1,5 +1,6 @@ -import pandas as _pd import pathlib as _pl + +import pandas as _pd import pytest as _pt import trnsysGUI.pythonInterface.regimeExporter.getDesiredRegimes as _gdr @@ -30,4 +31,3 @@ def testColumnNameIncorrectRaises(self): fileName = _DATA_DIR_ / "regimes_incorrect.csv" with _pt.raises(ValueError, match=f"Column name '{_COL_NAME_}' not found."): _gdr.getRegimesFromFile(fileName) - diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py index 3974094a..5d4e6d92 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py @@ -1,6 +1,5 @@ -import unittest as _ut import pathlib as _pl -import diff_pdf_visually as _dpv +import matplotlib.testing.compare as _mpltc import pytrnsys.utils.log as _ulog @@ -10,13 +9,14 @@ import trnsysGUI.pythonInterface.regimeExporter.renderDiagramOnPDFfromPython as _rdopfp _PROJECT_NAME_ = "diagramForRegimes" -_DATA_DIR_ = _pl.Path(_GUI.__file__).parent / "..\\tests\\trnsysGUI\\data\\diagramForRegimes" +_DATA_DIR_ = _pl.Path(_GUI.__file__).parent / f"..\\tests\\trnsysGUI\\data\\{_PROJECT_NAME_}" _DATA_FILENAME_ = "regimes.csv" _EXPECTED_PDFS_DIR_ = _DATA_DIR_ / "expectedPDFs" _DIAGRAM_ENDING_ = "_diagram.pdf" _NAME1_ENDING_ = "_name1.pdf" _NAME2_ENDING_ = "_name2.pdf" +_NAME1_SVG_ENDING_ = "_name1.svg" def _getExpectedAndNewPdfPaths(ending): @@ -55,20 +55,21 @@ def testUsingQtBot(self, qtbot): self._FileExistsAndIsCorrect(_NEW_NAME1_PATH_, _EXPECTED_NAME1_PATH_) self._FileExistsAndIsCorrect(_NEW_NAME2_PATH_, _EXPECTED_NAME2_PATH_) - def _FileExistsAndIsCorrect(self, producedPdf, expectedPdf): + @staticmethod + def _FileExistsAndIsCorrect(producedPdf, expectedPdf): assert producedPdf.is_file() - _dpv.pdf_similar(producedPdf, expectedPdf) + _mpltc.compare_images(str(producedPdf), str(expectedPdf), 0, in_decorator=False) def testUsingQtBotForGivenRegimes(self, qtbot): onlyTheseRegimes = ["name1"] mainWindow = _createMainWindow(_DATA_DIR_, _PROJECT_NAME_, qtbot) - _rdopfp.printRegimesAndCopyFiles(_DATA_DIR_, _PROJECT_NAME_, _DATA_FILENAME_, mainWindow, onlyTheseRegimes=onlyTheseRegimes) + _rdopfp.printRegimesAndCopyFiles( + _DATA_DIR_, _PROJECT_NAME_, _DATA_FILENAME_, mainWindow, onlyTheseRegimes=onlyTheseRegimes + ) self._FileExistsAndIsCorrect(_NEW_NAME1_PATH_, _EXPECTED_NAME1_PATH_) + self._FileExistsAndIsCorrect(_NEW_NAME1_PATH_, _EXPECTED_DIAGRAM_PATH_) assert not _NEW_DIAGRAM_PATH_.is_file() assert not _NEW_NAME2_PATH_.is_file() - - - -# non-qtbot solution? \ No newline at end of file +# non-qtbot solution? diff --git a/trnsysGUI/pythonInterface/regimeExporter/getDesiredRegimes.py b/trnsysGUI/pythonInterface/regimeExporter/getDesiredRegimes.py index 612de623..190eef03 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/getDesiredRegimes.py +++ b/trnsysGUI/pythonInterface/regimeExporter/getDesiredRegimes.py @@ -4,11 +4,11 @@ def getRegimesFromFile(fileName): - df = _pd.read_csv(fileName) - _COL_NAME_ = "regimeName" - if _COL_NAME_ in df.keys(): - return df - raise ValueError(f"Column name '{_COL_NAME_}' not found.") + table = _pd.read_csv(fileName) + colName = "regimeName" + if colName in table.keys(): + return table + raise ValueError(f"Column name '{colName}' not found.") # error handling? # - will throw "fileNotFoundError" as it is. diff --git a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py index 7d2ccd43..48cd5d5e 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py +++ b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py @@ -21,10 +21,10 @@ def getPumpsAndValvesAndMainTaps(pumpsAndValvesNames, mainWindow): pumpsAndValves = [] - mainTaps = dict() + mainTaps = {} blockItemsAndConnections = mainWindow.editor.trnsysObj for blockItem in blockItemsAndConnections: - if isinstance(blockItem, _pump.Pump) or isinstance(blockItem, _tv.TVentil): + if isinstance(blockItem, (_pump.Pump, _tv.TVentil)): if blockItem.displayName in pumpsAndValvesNames: pumpsAndValves.append(blockItem) elif isinstance(blockItem, _wtm.WTap_main): @@ -32,6 +32,7 @@ def getPumpsAndValvesAndMainTaps(pumpsAndValvesNames, mainWindow): return pumpsAndValves, mainTaps + # def changeMfrOfTaps(tapNames): # with in_place.InPlace('data.txt') as file: # for line in file: @@ -39,7 +40,9 @@ def getPumpsAndValvesAndMainTaps(pumpsAndValvesNames, mainWindow): # file.write(line) -def printRegimesAndCopyFiles(_DATA_DIR_, _PROJECT_NAME_, _DATA_FILENAME_, mainWindow, pumpTapPairs=None, onlyTheseRegimes=None): # list for onlyTheseRegimes +def printRegimesAndCopyFiles( + _DATA_DIR_, _PROJECT_NAME_, _DATA_FILENAME_, mainWindow, pumpTapPairs=None, onlyTheseRegimes=None +): # list for onlyTheseRegimes # createPDF of diagram only if not onlyTheseRegimes: pdfName = str(_DATA_DIR_) + "\\" + _PROJECT_NAME_ + "_diagram.pdf" @@ -97,7 +100,7 @@ def adjustPumpsAndValves(pumpsAndValves, regimeRow, pumpTapPairs, mainTaps): # assert desiredValue meaningful blockItem.positionForMassFlowSolver = desiredValue else: - raise TypeError(f'Encountered blockItem of type {blockItem}, instead of a pump or a Valve') + raise TypeError(f"Encountered blockItem of type {blockItem}, instead of a pump or a Valve") def runMassFlowSolver(mainWindow) -> _tp.Optional[Exception]: @@ -110,7 +113,7 @@ def _exportMassFlowSolverDeckAndRunTrnsys(editor: _de.Editor): # type: ignore[n trnExePath = str(_getTrnExePath()) - skipOther, exception = runDck(trnExePath, exportedFilePath) + _, exception = runDck(trnExePath, exportedFilePath) return exception From 57e1d54f5b8b60f3972b1bb13c2f3b6d2373858f Mon Sep 17 00:00:00 2001 From: ahobeost Date: Mon, 26 Jun 2023 17:25:20 +0200 Subject: [PATCH 12/56] Added matplotlib tests for svg files --- .../testPrintRegimesAndCopyFiles.py | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py index 5d4e6d92..b4dd6129 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py @@ -19,16 +19,17 @@ _NAME1_SVG_ENDING_ = "_name1.svg" -def _getExpectedAndNewPdfPaths(ending): +def _getExpectedAndNewFilePaths(ending): pdfName = _PROJECT_NAME_ + ending expectedPdfPath = _EXPECTED_PDFS_DIR_ / pdfName newPdfPath = _DATA_DIR_ / pdfName return expectedPdfPath, newPdfPath -_EXPECTED_DIAGRAM_PATH_, _NEW_DIAGRAM_PATH_ = _getExpectedAndNewPdfPaths(_DIAGRAM_ENDING_) -_EXPECTED_NAME1_PATH_, _NEW_NAME1_PATH_ = _getExpectedAndNewPdfPaths(_NAME1_ENDING_) -_EXPECTED_NAME2_PATH_, _NEW_NAME2_PATH_ = _getExpectedAndNewPdfPaths(_NAME2_ENDING_) +_EXPECTED_DIAGRAM_PATH_, _NEW_DIAGRAM_PATH_ = _getExpectedAndNewFilePaths(_DIAGRAM_ENDING_) +_EXPECTED_NAME1_PATH_, _NEW_NAME1_PATH_ = _getExpectedAndNewFilePaths(_NAME1_ENDING_) +_EXPECTED_NAME2_PATH_, _NEW_NAME2_PATH_ = _getExpectedAndNewFilePaths(_NAME2_ENDING_) +_EXPECTED_NAME1_SVG_PATH_, _NEW_NAME1_SVG_PATH_ = _getExpectedAndNewFilePaths(_NAME1_SVG_ENDING_) def _createMainWindow(PROJECT_FOLDER, PROJECT_NAME, qtbot): @@ -47,18 +48,24 @@ def _createMainWindow(PROJECT_FOLDER, PROJECT_NAME, qtbot): class TestPrintRegimesAndCopyFiles: + def testMplInstallation(self): + assert 'pdf' in _mpltc.comparable_formats() + assert 'svg' in _mpltc.comparable_formats() + def testUsingQtBot(self, qtbot): mainWindow = _createMainWindow(_DATA_DIR_, _PROJECT_NAME_, qtbot) _rdopfp.printRegimesAndCopyFiles(_DATA_DIR_, _PROJECT_NAME_, _DATA_FILENAME_, mainWindow) self._FileExistsAndIsCorrect(_NEW_DIAGRAM_PATH_, _EXPECTED_DIAGRAM_PATH_) self._FileExistsAndIsCorrect(_NEW_NAME1_PATH_, _EXPECTED_NAME1_PATH_) + self._FileExistsAndIsCorrect(_NEW_NAME1_SVG_PATH_, _EXPECTED_NAME1_SVG_PATH_) self._FileExistsAndIsCorrect(_NEW_NAME2_PATH_, _EXPECTED_NAME2_PATH_) + @staticmethod - def _FileExistsAndIsCorrect(producedPdf, expectedPdf): - assert producedPdf.is_file() - _mpltc.compare_images(str(producedPdf), str(expectedPdf), 0, in_decorator=False) + def _FileExistsAndIsCorrect(producedFile, expectedFile): + assert producedFile.is_file() + _mpltc.compare_images(str(producedFile), str(expectedFile), 0, in_decorator=False) def testUsingQtBotForGivenRegimes(self, qtbot): onlyTheseRegimes = ["name1"] From 037b65b683cc8b0b2c317fb9ee200a1a56b3634b Mon Sep 17 00:00:00 2001 From: ahobeost Date: Tue, 4 Jul 2023 08:26:00 +0200 Subject: [PATCH 13/56] Working version of regime exporter --- .../expectedCSVs/expectedRegimeTemplate.csv | 2 + .../testExportRegimeTemplate.py | 22 ++++++++++ .../regimeExporter/exportRegimes.py | 43 +++++++++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 tests/trnsysGUI/data/diagramForRegimes/expectedCSVs/expectedRegimeTemplate.csv create mode 100644 tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py create mode 100644 trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py diff --git a/tests/trnsysGUI/data/diagramForRegimes/expectedCSVs/expectedRegimeTemplate.csv b/tests/trnsysGUI/data/diagramForRegimes/expectedCSVs/expectedRegimeTemplate.csv new file mode 100644 index 00000000..411cf016 --- /dev/null +++ b/tests/trnsysGUI/data/diagramForRegimes/expectedCSVs/expectedRegimeTemplate.csv @@ -0,0 +1,2 @@ +regimeName,pump1,pump2,pump3,valve1,valve2 +'dummy regime',500.0,0.0,500.0,0.0,0.0 diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py new file mode 100644 index 00000000..28a0a9fd --- /dev/null +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py @@ -0,0 +1,22 @@ +import pathlib as _pl + +import trnsysGUI as _GUI +import trnsysGUI.pythonInterface.regimeExporter.exportRegimes as _er + +_PROJECT_NAME_ = "diagramForRegimes" +_DATA_DIR_ = _pl.Path(_GUI.__file__).parent / f"..\\tests\\trnsysGUI\\data\\{_PROJECT_NAME_}" +_EXPECTED_CVSS_DIR_ = _DATA_DIR_ / "expectedCSVs" + + +class TestExportRegimeTemplate: + def testExportTemplate(self): + projectJson = _DATA_DIR_ / f"{_PROJECT_NAME_}.json" + regimeFileName = _DATA_DIR_ / "regimeTemplate.csv" + expectedFileName = _EXPECTED_CVSS_DIR_ / "expectedRegimeTemplate.csv" + + _er.exportRegimeTemplate(projectJson, regimeFileName) + + expectedContent = _pl.Path(expectedFileName).read_text() + actualContent = _pl.Path(regimeFileName).read_text() + + assert actualContent == expectedContent diff --git a/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py b/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py new file mode 100644 index 00000000..d00cea5e --- /dev/null +++ b/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py @@ -0,0 +1,43 @@ +import json + +import pandas as _pd + + +def exportRegimeTemplate(projectJson, regimeFileName): + pumpsAndValvesAndValues = getPumpsAndValvesWithValuesFromJson(projectJson) + writeToCsv(pumpsAndValvesAndValues, regimeFileName) + + +def getPumpsAndValvesWithValuesFromJson(projectJson): + f = open(projectJson) + jsonValues = json.load(f) + f.close() + + data = {} + undesiredBlocks = ['.__BlockDct__', 'IDs', 'Strings'] + for i, block in enumerate(jsonValues['Blocks']): + if block not in undesiredBlocks: + curDict = jsonValues['Blocks'][block] + if 'BlockName' in curDict: + curBlockName = curDict['BlockName'] + if curBlockName == 'Pump': + desiredValueName = 'massFlowRateInKgPerH' + data = getData(curDict, data, desiredValueName) + elif curBlockName == 'TVentil': + desiredValueName = 'PositionForMassFlowSolver' + data = getData(curDict, data, desiredValueName) + pumpsAndValvesAndValues = _pd.DataFrame(data, index=["\'dummy regime\'"]) + pumpsAndValvesAndValues.index.name = "regimeName" + return pumpsAndValvesAndValues + + +def getData(curDict, data, desiredValueName): + label = curDict["BlockDisplayName"] + value = float(curDict[desiredValueName]) + data[label] = value + return data + + +def writeToCsv(pumpsAndValvesAndValues, regimeFileName): + pumpsAndValvesAndValues = pumpsAndValvesAndValues.sort_index(axis='columns') + pumpsAndValvesAndValues.to_csv(regimeFileName) From 63ec02f5cef6b7420527a5cf9043b7f3eea83cae Mon Sep 17 00:00:00 2001 From: ahobeost Date: Tue, 4 Jul 2023 09:02:26 +0200 Subject: [PATCH 14/56] Making tests work after each other --- .../testPrintRegimesAndCopyFiles.py | 48 ++++++++++++------- .../regimeExporter/exportRegimes.py | 22 ++++----- .../renderDiagramOnPDFfromPython.py | 20 ++------ 3 files changed, 48 insertions(+), 42 deletions(-) diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py index b4dd6129..f884f6c3 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py @@ -1,5 +1,6 @@ -import pathlib as _pl +import os as _os import matplotlib.testing.compare as _mpltc +import pathlib as _pl import pytrnsys.utils.log as _ulog @@ -12,6 +13,8 @@ _DATA_DIR_ = _pl.Path(_GUI.__file__).parent / f"..\\tests\\trnsysGUI\\data\\{_PROJECT_NAME_}" _DATA_FILENAME_ = "regimes.csv" _EXPECTED_PDFS_DIR_ = _DATA_DIR_ / "expectedPDFs" +_RESULTS_DIR_ = _DATA_DIR_ / "results" +_RESULTS_DIR_2_ = _DATA_DIR_ / "resultsReducedUsage" _DIAGRAM_ENDING_ = "_diagram.pdf" _NAME1_ENDING_ = "_name1.pdf" @@ -19,17 +22,31 @@ _NAME1_SVG_ENDING_ = "_name1.svg" -def _getExpectedAndNewFilePaths(ending): +def _ensureDirExists(dirPath): + if not _os.path.isdir(dirPath): + _os.makedirs(dirPath) + + +_ensureDirExists(_RESULTS_DIR_) +_ensureDirExists(_RESULTS_DIR_2_) + + +def _getExpectedAndNewFilePaths(ending, resultsDir): pdfName = _PROJECT_NAME_ + ending expectedPdfPath = _EXPECTED_PDFS_DIR_ / pdfName - newPdfPath = _DATA_DIR_ / pdfName + newPdfPath = _DATA_DIR_ / resultsDir / pdfName return expectedPdfPath, newPdfPath -_EXPECTED_DIAGRAM_PATH_, _NEW_DIAGRAM_PATH_ = _getExpectedAndNewFilePaths(_DIAGRAM_ENDING_) -_EXPECTED_NAME1_PATH_, _NEW_NAME1_PATH_ = _getExpectedAndNewFilePaths(_NAME1_ENDING_) -_EXPECTED_NAME2_PATH_, _NEW_NAME2_PATH_ = _getExpectedAndNewFilePaths(_NAME2_ENDING_) -_EXPECTED_NAME1_SVG_PATH_, _NEW_NAME1_SVG_PATH_ = _getExpectedAndNewFilePaths(_NAME1_SVG_ENDING_) +_EXPECTED_DIAGRAM_PATH_, _NEW_DIAGRAM_PATH_ = _getExpectedAndNewFilePaths(_DIAGRAM_ENDING_, _RESULTS_DIR_) +_EXPECTED_NAME1_PATH_, _NEW_NAME1_PATH_ = _getExpectedAndNewFilePaths(_NAME1_ENDING_, _RESULTS_DIR_) +_EXPECTED_NAME2_PATH_, _NEW_NAME2_PATH_ = _getExpectedAndNewFilePaths(_NAME2_ENDING_, _RESULTS_DIR_) +_EXPECTED_NAME1_SVG_PATH_, _NEW_NAME1_SVG_PATH_ = _getExpectedAndNewFilePaths(_NAME1_SVG_ENDING_, _RESULTS_DIR_) + +_, _NEW_DIAGRAM_PATH_2_ = _getExpectedAndNewFilePaths(_DIAGRAM_ENDING_, _RESULTS_DIR_2_) +_, _NEW_NAME1_PATH_2_ = _getExpectedAndNewFilePaths(_NAME1_ENDING_, _RESULTS_DIR_2_) +_, _NEW_NAME2_PATH_2_ = _getExpectedAndNewFilePaths(_NAME2_ENDING_, _RESULTS_DIR_2_) +_, _NEW_NAME1_SVG_PATH_2_ = _getExpectedAndNewFilePaths(_NAME1_SVG_ENDING_, _RESULTS_DIR_2_) def _createMainWindow(PROJECT_FOLDER, PROJECT_NAME, qtbot): @@ -49,19 +66,18 @@ def _createMainWindow(PROJECT_FOLDER, PROJECT_NAME, qtbot): class TestPrintRegimesAndCopyFiles: def testMplInstallation(self): - assert 'pdf' in _mpltc.comparable_formats() - assert 'svg' in _mpltc.comparable_formats() + assert "pdf" in _mpltc.comparable_formats() + assert "svg" in _mpltc.comparable_formats() def testUsingQtBot(self, qtbot): mainWindow = _createMainWindow(_DATA_DIR_, _PROJECT_NAME_, qtbot) - _rdopfp.printRegimesAndCopyFiles(_DATA_DIR_, _PROJECT_NAME_, _DATA_FILENAME_, mainWindow) + _rdopfp.printRegimesAndCopyFiles(_DATA_DIR_, _PROJECT_NAME_, _RESULTS_DIR_, _DATA_FILENAME_, mainWindow) self._FileExistsAndIsCorrect(_NEW_DIAGRAM_PATH_, _EXPECTED_DIAGRAM_PATH_) self._FileExistsAndIsCorrect(_NEW_NAME1_PATH_, _EXPECTED_NAME1_PATH_) self._FileExistsAndIsCorrect(_NEW_NAME1_SVG_PATH_, _EXPECTED_NAME1_SVG_PATH_) self._FileExistsAndIsCorrect(_NEW_NAME2_PATH_, _EXPECTED_NAME2_PATH_) - @staticmethod def _FileExistsAndIsCorrect(producedFile, expectedFile): assert producedFile.is_file() @@ -71,12 +87,12 @@ def testUsingQtBotForGivenRegimes(self, qtbot): onlyTheseRegimes = ["name1"] mainWindow = _createMainWindow(_DATA_DIR_, _PROJECT_NAME_, qtbot) _rdopfp.printRegimesAndCopyFiles( - _DATA_DIR_, _PROJECT_NAME_, _DATA_FILENAME_, mainWindow, onlyTheseRegimes=onlyTheseRegimes + _DATA_DIR_, _PROJECT_NAME_, _RESULTS_DIR_2_, _DATA_FILENAME_, mainWindow, onlyTheseRegimes=onlyTheseRegimes ) - self._FileExistsAndIsCorrect(_NEW_NAME1_PATH_, _EXPECTED_NAME1_PATH_) - self._FileExistsAndIsCorrect(_NEW_NAME1_PATH_, _EXPECTED_DIAGRAM_PATH_) - assert not _NEW_DIAGRAM_PATH_.is_file() - assert not _NEW_NAME2_PATH_.is_file() + self._FileExistsAndIsCorrect(_NEW_NAME1_PATH_2_, _EXPECTED_NAME1_PATH_) + self._FileExistsAndIsCorrect(_NEW_NAME1_PATH_2_, _EXPECTED_DIAGRAM_PATH_) + assert not _NEW_DIAGRAM_PATH_2_.is_file() + assert not _NEW_NAME2_PATH_2_.is_file() # non-qtbot solution? diff --git a/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py b/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py index d00cea5e..11161f19 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py +++ b/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py @@ -14,19 +14,19 @@ def getPumpsAndValvesWithValuesFromJson(projectJson): f.close() data = {} - undesiredBlocks = ['.__BlockDct__', 'IDs', 'Strings'] - for i, block in enumerate(jsonValues['Blocks']): + undesiredBlocks = [".__BlockDct__", "IDs", "Strings"] + for i, block in enumerate(jsonValues["Blocks"]): if block not in undesiredBlocks: - curDict = jsonValues['Blocks'][block] - if 'BlockName' in curDict: - curBlockName = curDict['BlockName'] - if curBlockName == 'Pump': - desiredValueName = 'massFlowRateInKgPerH' + curDict = jsonValues["Blocks"][block] + if "BlockName" in curDict: + curBlockName = curDict["BlockName"] + if curBlockName == "Pump": + desiredValueName = "massFlowRateInKgPerH" data = getData(curDict, data, desiredValueName) - elif curBlockName == 'TVentil': - desiredValueName = 'PositionForMassFlowSolver' + elif curBlockName == "TVentil": + desiredValueName = "PositionForMassFlowSolver" data = getData(curDict, data, desiredValueName) - pumpsAndValvesAndValues = _pd.DataFrame(data, index=["\'dummy regime\'"]) + pumpsAndValvesAndValues = _pd.DataFrame(data, index=["'dummy regime'"]) pumpsAndValvesAndValues.index.name = "regimeName" return pumpsAndValvesAndValues @@ -39,5 +39,5 @@ def getData(curDict, data, desiredValueName): def writeToCsv(pumpsAndValvesAndValues, regimeFileName): - pumpsAndValvesAndValues = pumpsAndValvesAndValues.sort_index(axis='columns') + pumpsAndValvesAndValues = pumpsAndValvesAndValues.sort_index(axis="columns") pumpsAndValvesAndValues.to_csv(regimeFileName) diff --git a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py index 48cd5d5e..5465ac47 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py +++ b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py @@ -33,24 +33,16 @@ def getPumpsAndValvesAndMainTaps(pumpsAndValvesNames, mainWindow): return pumpsAndValves, mainTaps -# def changeMfrOfTaps(tapNames): -# with in_place.InPlace('data.txt') as file: -# for line in file: -# line = line.replace('test', 'testZ') -# file.write(line) - - def printRegimesAndCopyFiles( - _DATA_DIR_, _PROJECT_NAME_, _DATA_FILENAME_, mainWindow, pumpTapPairs=None, onlyTheseRegimes=None -): # list for onlyTheseRegimes + _DATA_DIR_, _PROJECT_NAME_, _RESULTS_DIR_, _DATA_FILENAME_, mainWindow, pumpTapPairs=None, onlyTheseRegimes=None +): # createPDF of diagram only if not onlyTheseRegimes: - pdfName = str(_DATA_DIR_) + "\\" + _PROJECT_NAME_ + "_diagram.pdf" + pdfName = str(_RESULTS_DIR_) + "\\" + _PROJECT_NAME_ + "_diagram.pdf" printDiagramToPDF(pdfName, mainWindow) regimeValues = _gdr.getRegimes(_DATA_DIR_ / _DATA_FILENAME_, onlyTheseRegimes) pumpsAndValvesNames = list(regimeValues.columns) - # pumpsAndValvesNames.remove('regimeName') massFlowRatesPrintFileName = f"{_PROJECT_NAME_}_Mfr.prt" temperaturesPintFileName = f"{_PROJECT_NAME_}_T.prt" massFlowRatesPrintFilePath = _DATA_DIR_ / massFlowRatesPrintFileName @@ -59,7 +51,6 @@ def printRegimesAndCopyFiles( for regimeName in regimeValues.index: regimeRow = regimeValues.loc[regimeName] - # regimeName = regimeRow["regimeName"] adjustPumpsAndValves(pumpsAndValves, regimeRow, pumpTapPairs, mainTaps) @@ -67,7 +58,6 @@ def printRegimesAndCopyFiles( if not exception: print("massflowSolver ran without issue") - # copyMFRandTfiles() timeStep = 2 else: regimeName = regimeName + "_FAILED" @@ -78,8 +68,8 @@ def printRegimesAndCopyFiles( ) massFlowSolverVisualizer.slider.setValue(timeStep) - pdfName = str(_DATA_DIR_) + "\\" + _PROJECT_NAME_ + "_" + regimeName + ".pdf" - svgName = str(_DATA_DIR_) + "\\" + _PROJECT_NAME_ + "_" + regimeName + ".svg" + pdfName = str(_RESULTS_DIR_) + "\\" + _PROJECT_NAME_ + "_" + regimeName + ".pdf" + svgName = str(_RESULTS_DIR_) + "\\" + _PROJECT_NAME_ + "_" + regimeName + ".svg" printDiagramToPDF(pdfName, mainWindow) printDiagramToSVG(svgName, mainWindow) massFlowSolverVisualizer.close() From 39ae20bc3c0d1732aeadffb11b6da7b3dab8702f Mon Sep 17 00:00:00 2001 From: ahobeost Date: Tue, 4 Jul 2023 09:23:41 +0200 Subject: [PATCH 15/56] refactoring and CI cleanup --- .../testExportRegimeTemplate.py | 12 +-- .../testPrintRegimesAndCopyFiles.py | 79 +++++++++---------- .../regimeExporter/exportRegimes.py | 7 +- .../renderDiagramOnPDFfromPython.py | 34 +++++--- 4 files changed, 69 insertions(+), 63 deletions(-) diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py index 28a0a9fd..a09a25bb 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py @@ -3,16 +3,16 @@ import trnsysGUI as _GUI import trnsysGUI.pythonInterface.regimeExporter.exportRegimes as _er -_PROJECT_NAME_ = "diagramForRegimes" -_DATA_DIR_ = _pl.Path(_GUI.__file__).parent / f"..\\tests\\trnsysGUI\\data\\{_PROJECT_NAME_}" -_EXPECTED_CVSS_DIR_ = _DATA_DIR_ / "expectedCSVs" +_PROJECT_NAME = "diagramForRegimes" +_DATA_DIR = _pl.Path(_GUI.__file__).parent / f"..\\tests\\trnsysGUI\\data\\{_PROJECT_NAME}" +_EXPECTED_CVSS_DIR = _DATA_DIR / "expectedCSVs" class TestExportRegimeTemplate: def testExportTemplate(self): - projectJson = _DATA_DIR_ / f"{_PROJECT_NAME_}.json" - regimeFileName = _DATA_DIR_ / "regimeTemplate.csv" - expectedFileName = _EXPECTED_CVSS_DIR_ / "expectedRegimeTemplate.csv" + projectJson = _DATA_DIR / f"{_PROJECT_NAME}.json" + regimeFileName = _DATA_DIR / "regimeTemplate.csv" + expectedFileName = _EXPECTED_CVSS_DIR / "expectedRegimeTemplate.csv" _er.exportRegimeTemplate(projectJson, regimeFileName) diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py index f884f6c3..32c997ca 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py @@ -1,6 +1,6 @@ import os as _os -import matplotlib.testing.compare as _mpltc import pathlib as _pl +import matplotlib.testing.compare as _mpltc # type: ignore[import] import pytrnsys.utils.log as _ulog @@ -9,17 +9,17 @@ import trnsysGUI.project as _prj import trnsysGUI.pythonInterface.regimeExporter.renderDiagramOnPDFfromPython as _rdopfp -_PROJECT_NAME_ = "diagramForRegimes" -_DATA_DIR_ = _pl.Path(_GUI.__file__).parent / f"..\\tests\\trnsysGUI\\data\\{_PROJECT_NAME_}" -_DATA_FILENAME_ = "regimes.csv" -_EXPECTED_PDFS_DIR_ = _DATA_DIR_ / "expectedPDFs" -_RESULTS_DIR_ = _DATA_DIR_ / "results" -_RESULTS_DIR_2_ = _DATA_DIR_ / "resultsReducedUsage" +_PROJECT_NAME = "diagramForRegimes" +_DATA_DIR = _pl.Path(_GUI.__file__).parent / f"..\\tests\\trnsysGUI\\data\\{_PROJECT_NAME}" +_DATA_FILENAME = "regimes.csv" +_EXPECTED_PDFS_DIR = _DATA_DIR / "expectedPDFs" +_RESULTS_DIR = _DATA_DIR / "results" +_RESULTS_DIR_2 = _DATA_DIR / "resultsReducedUsage" -_DIAGRAM_ENDING_ = "_diagram.pdf" -_NAME1_ENDING_ = "_name1.pdf" -_NAME2_ENDING_ = "_name2.pdf" -_NAME1_SVG_ENDING_ = "_name1.svg" +_DIAGRAM_ENDING = "_diagram.pdf" +_NAME1_ENDING = "_name1.pdf" +_NAME2_ENDING = "_name2.pdf" +_NAME1_SVG_ENDING = "_name1.svg" def _ensureDirExists(dirPath): @@ -27,30 +27,30 @@ def _ensureDirExists(dirPath): _os.makedirs(dirPath) -_ensureDirExists(_RESULTS_DIR_) -_ensureDirExists(_RESULTS_DIR_2_) +_ensureDirExists(_RESULTS_DIR) +_ensureDirExists(_RESULTS_DIR_2) def _getExpectedAndNewFilePaths(ending, resultsDir): - pdfName = _PROJECT_NAME_ + ending - expectedPdfPath = _EXPECTED_PDFS_DIR_ / pdfName - newPdfPath = _DATA_DIR_ / resultsDir / pdfName + pdfName = _PROJECT_NAME + ending + expectedPdfPath = _EXPECTED_PDFS_DIR / pdfName + newPdfPath = _DATA_DIR / resultsDir / pdfName return expectedPdfPath, newPdfPath -_EXPECTED_DIAGRAM_PATH_, _NEW_DIAGRAM_PATH_ = _getExpectedAndNewFilePaths(_DIAGRAM_ENDING_, _RESULTS_DIR_) -_EXPECTED_NAME1_PATH_, _NEW_NAME1_PATH_ = _getExpectedAndNewFilePaths(_NAME1_ENDING_, _RESULTS_DIR_) -_EXPECTED_NAME2_PATH_, _NEW_NAME2_PATH_ = _getExpectedAndNewFilePaths(_NAME2_ENDING_, _RESULTS_DIR_) -_EXPECTED_NAME1_SVG_PATH_, _NEW_NAME1_SVG_PATH_ = _getExpectedAndNewFilePaths(_NAME1_SVG_ENDING_, _RESULTS_DIR_) +_EXPECTED_DIAGRAM_PATH, _NEW_DIAGRAM_PATH = _getExpectedAndNewFilePaths(_DIAGRAM_ENDING, _RESULTS_DIR) +_EXPECTED_NAME1_PATH, _NEW_NAME1_PATH = _getExpectedAndNewFilePaths(_NAME1_ENDING, _RESULTS_DIR) +_EXPECTED_NAME2_PATH, _NEW_NAME2_PATH = _getExpectedAndNewFilePaths(_NAME2_ENDING, _RESULTS_DIR) +_EXPECTED_NAME1_SVG_PATH, _NEW_NAME1_SVG_PATH = _getExpectedAndNewFilePaths(_NAME1_SVG_ENDING, _RESULTS_DIR) -_, _NEW_DIAGRAM_PATH_2_ = _getExpectedAndNewFilePaths(_DIAGRAM_ENDING_, _RESULTS_DIR_2_) -_, _NEW_NAME1_PATH_2_ = _getExpectedAndNewFilePaths(_NAME1_ENDING_, _RESULTS_DIR_2_) -_, _NEW_NAME2_PATH_2_ = _getExpectedAndNewFilePaths(_NAME2_ENDING_, _RESULTS_DIR_2_) -_, _NEW_NAME1_SVG_PATH_2_ = _getExpectedAndNewFilePaths(_NAME1_SVG_ENDING_, _RESULTS_DIR_2_) +_, _NEW_DIAGRAM_PATH_2 = _getExpectedAndNewFilePaths(_DIAGRAM_ENDING, _RESULTS_DIR_2) +_, _NEW_NAME1_PATH_2 = _getExpectedAndNewFilePaths(_NAME1_ENDING, _RESULTS_DIR_2) +_, _NEW_NAME2_PATH_2 = _getExpectedAndNewFilePaths(_NAME2_ENDING, _RESULTS_DIR_2) +_, _NEW_NAME1_SVG_PATH_2 = _getExpectedAndNewFilePaths(_NAME1_SVG_ENDING, _RESULTS_DIR_2) -def _createMainWindow(PROJECT_FOLDER, PROJECT_NAME, qtbot): - projectJsonFilePath = PROJECT_FOLDER / f"{PROJECT_NAME}.json" +def _createMainWindow(projectFolder, projectName, qtbot): + projectJsonFilePath = projectFolder / f"{projectName}.json" project = _prj.LoadProject(projectJsonFilePath) logger = _ulog.getOrCreateCustomLogger("root", "DEBUG") # type: ignore[attr-defined] @@ -70,13 +70,13 @@ def testMplInstallation(self): assert "svg" in _mpltc.comparable_formats() def testUsingQtBot(self, qtbot): - mainWindow = _createMainWindow(_DATA_DIR_, _PROJECT_NAME_, qtbot) - _rdopfp.printRegimesAndCopyFiles(_DATA_DIR_, _PROJECT_NAME_, _RESULTS_DIR_, _DATA_FILENAME_, mainWindow) + mainWindow = _createMainWindow(_DATA_DIR, _PROJECT_NAME, qtbot) + _rdopfp.printRegimesAndCopyFiles(_DATA_DIR, _PROJECT_NAME, _RESULTS_DIR, _DATA_FILENAME, mainWindow) - self._FileExistsAndIsCorrect(_NEW_DIAGRAM_PATH_, _EXPECTED_DIAGRAM_PATH_) - self._FileExistsAndIsCorrect(_NEW_NAME1_PATH_, _EXPECTED_NAME1_PATH_) - self._FileExistsAndIsCorrect(_NEW_NAME1_SVG_PATH_, _EXPECTED_NAME1_SVG_PATH_) - self._FileExistsAndIsCorrect(_NEW_NAME2_PATH_, _EXPECTED_NAME2_PATH_) + self._FileExistsAndIsCorrect(_NEW_DIAGRAM_PATH, _EXPECTED_DIAGRAM_PATH) + self._FileExistsAndIsCorrect(_NEW_NAME1_PATH, _EXPECTED_NAME1_PATH) + self._FileExistsAndIsCorrect(_NEW_NAME1_SVG_PATH, _EXPECTED_NAME1_SVG_PATH) + self._FileExistsAndIsCorrect(_NEW_NAME2_PATH, _EXPECTED_NAME2_PATH) @staticmethod def _FileExistsAndIsCorrect(producedFile, expectedFile): @@ -85,14 +85,13 @@ def _FileExistsAndIsCorrect(producedFile, expectedFile): def testUsingQtBotForGivenRegimes(self, qtbot): onlyTheseRegimes = ["name1"] - mainWindow = _createMainWindow(_DATA_DIR_, _PROJECT_NAME_, qtbot) - _rdopfp.printRegimesAndCopyFiles( - _DATA_DIR_, _PROJECT_NAME_, _RESULTS_DIR_2_, _DATA_FILENAME_, mainWindow, onlyTheseRegimes=onlyTheseRegimes - ) - self._FileExistsAndIsCorrect(_NEW_NAME1_PATH_2_, _EXPECTED_NAME1_PATH_) - self._FileExistsAndIsCorrect(_NEW_NAME1_PATH_2_, _EXPECTED_DIAGRAM_PATH_) - assert not _NEW_DIAGRAM_PATH_2_.is_file() - assert not _NEW_NAME2_PATH_2_.is_file() + mainWindow = _createMainWindow(_DATA_DIR, _PROJECT_NAME, qtbot) + _rdopfp.printRegimesAndCopyFiles(_DATA_DIR, _PROJECT_NAME, _RESULTS_DIR_2, _DATA_FILENAME, mainWindow, + onlyTheseRegimes=onlyTheseRegimes) + self._FileExistsAndIsCorrect(_NEW_NAME1_PATH_2, _EXPECTED_NAME1_PATH) + self._FileExistsAndIsCorrect(_NEW_NAME1_PATH_2, _EXPECTED_DIAGRAM_PATH) + assert not _NEW_DIAGRAM_PATH_2.is_file() + assert not _NEW_NAME2_PATH_2.is_file() # non-qtbot solution? diff --git a/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py b/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py index 11161f19..d8f80bc0 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py +++ b/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py @@ -9,13 +9,12 @@ def exportRegimeTemplate(projectJson, regimeFileName): def getPumpsAndValvesWithValuesFromJson(projectJson): - f = open(projectJson) - jsonValues = json.load(f) - f.close() + with open(projectJson, 'r', encoding='utf-8') as openFile: + jsonValues = json.load(openFile) data = {} undesiredBlocks = [".__BlockDct__", "IDs", "Strings"] - for i, block in enumerate(jsonValues["Blocks"]): + for block in jsonValues["Blocks"]: if block not in undesiredBlocks: curDict = jsonValues["Blocks"][block] if "BlockName" in curDict: diff --git a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py index 5465ac47..aa5c610f 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py +++ b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py @@ -34,20 +34,16 @@ def getPumpsAndValvesAndMainTaps(pumpsAndValvesNames, mainWindow): def printRegimesAndCopyFiles( - _DATA_DIR_, _PROJECT_NAME_, _RESULTS_DIR_, _DATA_FILENAME_, mainWindow, pumpTapPairs=None, onlyTheseRegimes=None + _DATA_DIR, _PROJECT_NAME, _RESULTS_DIR, _DATA_FILENAME, mainWindow, pumpTapPairs=None, onlyTheseRegimes=None ): # createPDF of diagram only if not onlyTheseRegimes: - pdfName = str(_RESULTS_DIR_) + "\\" + _PROJECT_NAME_ + "_diagram.pdf" - printDiagramToPDF(pdfName, mainWindow) + makeDiagramFiles(_PROJECT_NAME, _RESULTS_DIR, mainWindow) - regimeValues = _gdr.getRegimes(_DATA_DIR_ / _DATA_FILENAME_, onlyTheseRegimes) + regimeValues = _gdr.getRegimes(_DATA_DIR / _DATA_FILENAME, onlyTheseRegimes) pumpsAndValvesNames = list(regimeValues.columns) - massFlowRatesPrintFileName = f"{_PROJECT_NAME_}_Mfr.prt" - temperaturesPintFileName = f"{_PROJECT_NAME_}_T.prt" - massFlowRatesPrintFilePath = _DATA_DIR_ / massFlowRatesPrintFileName - temperaturesPrintFilePath = _DATA_DIR_ / temperaturesPintFileName pumpsAndValves, mainTaps = getPumpsAndValvesAndMainTaps(pumpsAndValvesNames, mainWindow) + massFlowRatesPrintFilePath, temperaturesPrintFilePath = getPrtFilePaths(_DATA_DIR, _PROJECT_NAME) for regimeName in regimeValues.index: regimeRow = regimeValues.loc[regimeName] @@ -57,7 +53,6 @@ def printRegimesAndCopyFiles( exception = runMassFlowSolver(mainWindow) if not exception: - print("massflowSolver ran without issue") timeStep = 2 else: regimeName = regimeName + "_FAILED" @@ -68,13 +63,26 @@ def printRegimesAndCopyFiles( ) massFlowSolverVisualizer.slider.setValue(timeStep) - pdfName = str(_RESULTS_DIR_) + "\\" + _PROJECT_NAME_ + "_" + regimeName + ".pdf" - svgName = str(_RESULTS_DIR_) + "\\" + _PROJECT_NAME_ + "_" + regimeName + ".svg" - printDiagramToPDF(pdfName, mainWindow) - printDiagramToSVG(svgName, mainWindow) + makeDiagramFiles(_PROJECT_NAME, _RESULTS_DIR, mainWindow, regimeName=regimeName) + massFlowSolverVisualizer.close() +def getPrtFilePaths(_DATA_DIR, _PROJECT_NAME): + massFlowRatesPrintFileName = f"{_PROJECT_NAME}_Mfr.prt" + temperaturesPintFileName = f"{_PROJECT_NAME}_T.prt" + massFlowRatesPrintFilePath = _DATA_DIR / massFlowRatesPrintFileName + temperaturesPrintFilePath = _DATA_DIR / temperaturesPintFileName + return massFlowRatesPrintFilePath, temperaturesPrintFilePath + + +def makeDiagramFiles(_PROJECT_NAME, _RESULTS_DIR, mainWindow, regimeName="diagram"): + pdfName = str(_RESULTS_DIR) + "\\" + _PROJECT_NAME + "_" + regimeName + ".pdf" + svgName = str(_RESULTS_DIR) + "\\" + _PROJECT_NAME + "_" + regimeName + ".svg" + printDiagramToPDF(pdfName, mainWindow) + printDiagramToSVG(svgName, mainWindow) + + def adjustPumpsAndValves(pumpsAndValves, regimeRow, pumpTapPairs, mainTaps): for blockItem in pumpsAndValves: From 8c5384cb5b30dbea956ee1efd357bc872b3e1f21 Mon Sep 17 00:00:00 2001 From: ahobeost Date: Tue, 4 Jul 2023 09:30:49 +0200 Subject: [PATCH 16/56] CI adjustments --- .../testExportRegimeTemplate.py | 4 +-- .../renderDiagramOnPDFfromPython.py | 26 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py index a09a25bb..d5af1af2 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py @@ -16,7 +16,7 @@ def testExportTemplate(self): _er.exportRegimeTemplate(projectJson, regimeFileName) - expectedContent = _pl.Path(expectedFileName).read_text() - actualContent = _pl.Path(regimeFileName).read_text() + expectedContent = _pl.Path(expectedFileName).read_text(encoding='utf-8') + actualContent = _pl.Path(regimeFileName).read_text(encoding='utf-8') assert actualContent == expectedContent diff --git a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py index aa5c610f..791c7197 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py +++ b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py @@ -34,16 +34,16 @@ def getPumpsAndValvesAndMainTaps(pumpsAndValvesNames, mainWindow): def printRegimesAndCopyFiles( - _DATA_DIR, _PROJECT_NAME, _RESULTS_DIR, _DATA_FILENAME, mainWindow, pumpTapPairs=None, onlyTheseRegimes=None + dataDir, projectName, resultsDir, dataFileName, mainWindow, pumpTapPairs=None, onlyTheseRegimes=None ): # createPDF of diagram only if not onlyTheseRegimes: - makeDiagramFiles(_PROJECT_NAME, _RESULTS_DIR, mainWindow) + makeDiagramFiles(projectName, resultsDir, mainWindow) - regimeValues = _gdr.getRegimes(_DATA_DIR / _DATA_FILENAME, onlyTheseRegimes) + regimeValues = _gdr.getRegimes(dataDir / dataFileName, onlyTheseRegimes) pumpsAndValvesNames = list(regimeValues.columns) pumpsAndValves, mainTaps = getPumpsAndValvesAndMainTaps(pumpsAndValvesNames, mainWindow) - massFlowRatesPrintFilePath, temperaturesPrintFilePath = getPrtFilePaths(_DATA_DIR, _PROJECT_NAME) + massFlowRatesPrintFilePath, temperaturesPrintFilePath = getPrtFilePaths(dataDir, projectName) for regimeName in regimeValues.index: regimeRow = regimeValues.loc[regimeName] @@ -63,22 +63,22 @@ def printRegimesAndCopyFiles( ) massFlowSolverVisualizer.slider.setValue(timeStep) - makeDiagramFiles(_PROJECT_NAME, _RESULTS_DIR, mainWindow, regimeName=regimeName) + makeDiagramFiles(projectName, resultsDir, mainWindow, regimeName=regimeName) massFlowSolverVisualizer.close() -def getPrtFilePaths(_DATA_DIR, _PROJECT_NAME): - massFlowRatesPrintFileName = f"{_PROJECT_NAME}_Mfr.prt" - temperaturesPintFileName = f"{_PROJECT_NAME}_T.prt" - massFlowRatesPrintFilePath = _DATA_DIR / massFlowRatesPrintFileName - temperaturesPrintFilePath = _DATA_DIR / temperaturesPintFileName +def getPrtFilePaths(dataDir, projectName): + massFlowRatesPrintFileName = f"{projectName}_Mfr.prt" + temperaturesPintFileName = f"{projectName}_T.prt" + massFlowRatesPrintFilePath = dataDir / massFlowRatesPrintFileName + temperaturesPrintFilePath = dataDir / temperaturesPintFileName return massFlowRatesPrintFilePath, temperaturesPrintFilePath -def makeDiagramFiles(_PROJECT_NAME, _RESULTS_DIR, mainWindow, regimeName="diagram"): - pdfName = str(_RESULTS_DIR) + "\\" + _PROJECT_NAME + "_" + regimeName + ".pdf" - svgName = str(_RESULTS_DIR) + "\\" + _PROJECT_NAME + "_" + regimeName + ".svg" +def makeDiagramFiles(projectName, resultsDir, mainWindow, regimeName="diagram"): + pdfName = str(resultsDir) + "\\" + projectName + "_" + regimeName + ".pdf" + svgName = str(resultsDir) + "\\" + projectName + "_" + regimeName + ".svg" printDiagramToPDF(pdfName, mainWindow) printDiagramToSVG(svgName, mainWindow) From e49a521843b0c564f151c50c93961b8331277421 Mon Sep 17 00:00:00 2001 From: ahobeost Date: Tue, 4 Jul 2023 09:37:02 +0200 Subject: [PATCH 17/56] refactoring major code smell --- .../regimeExporter/testPrintRegimesAndCopyFiles.py | 14 +++++++------- .../regimeExporter/renderDiagramOnPDFfromPython.py | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py index 32c997ca..10b2dbc3 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py @@ -73,13 +73,13 @@ def testUsingQtBot(self, qtbot): mainWindow = _createMainWindow(_DATA_DIR, _PROJECT_NAME, qtbot) _rdopfp.printRegimesAndCopyFiles(_DATA_DIR, _PROJECT_NAME, _RESULTS_DIR, _DATA_FILENAME, mainWindow) - self._FileExistsAndIsCorrect(_NEW_DIAGRAM_PATH, _EXPECTED_DIAGRAM_PATH) - self._FileExistsAndIsCorrect(_NEW_NAME1_PATH, _EXPECTED_NAME1_PATH) - self._FileExistsAndIsCorrect(_NEW_NAME1_SVG_PATH, _EXPECTED_NAME1_SVG_PATH) - self._FileExistsAndIsCorrect(_NEW_NAME2_PATH, _EXPECTED_NAME2_PATH) + self._fileExistsAndIsCorrect(_NEW_DIAGRAM_PATH, _EXPECTED_DIAGRAM_PATH) + self._fileExistsAndIsCorrect(_NEW_NAME1_PATH, _EXPECTED_NAME1_PATH) + self._fileExistsAndIsCorrect(_NEW_NAME1_SVG_PATH, _EXPECTED_NAME1_SVG_PATH) + self._fileExistsAndIsCorrect(_NEW_NAME2_PATH, _EXPECTED_NAME2_PATH) @staticmethod - def _FileExistsAndIsCorrect(producedFile, expectedFile): + def _fileExistsAndIsCorrect(producedFile, expectedFile): assert producedFile.is_file() _mpltc.compare_images(str(producedFile), str(expectedFile), 0, in_decorator=False) @@ -88,8 +88,8 @@ def testUsingQtBotForGivenRegimes(self, qtbot): mainWindow = _createMainWindow(_DATA_DIR, _PROJECT_NAME, qtbot) _rdopfp.printRegimesAndCopyFiles(_DATA_DIR, _PROJECT_NAME, _RESULTS_DIR_2, _DATA_FILENAME, mainWindow, onlyTheseRegimes=onlyTheseRegimes) - self._FileExistsAndIsCorrect(_NEW_NAME1_PATH_2, _EXPECTED_NAME1_PATH) - self._FileExistsAndIsCorrect(_NEW_NAME1_PATH_2, _EXPECTED_DIAGRAM_PATH) + self._fileExistsAndIsCorrect(_NEW_NAME1_PATH_2, _EXPECTED_NAME1_PATH) + self._fileExistsAndIsCorrect(_NEW_NAME1_PATH_2, _EXPECTED_DIAGRAM_PATH) assert not _NEW_DIAGRAM_PATH_2.is_file() assert not _NEW_NAME2_PATH_2.is_file() diff --git a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py index 791c7197..83ef7214 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py +++ b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py @@ -107,7 +107,7 @@ def runMassFlowSolver(mainWindow) -> _tp.Optional[Exception]: def _exportMassFlowSolverDeckAndRunTrnsys(editor: _de.Editor): # type: ignore[name-defined] - exportedFilePath = str(_exportHydraulic(editor, _format="mfs")) + exportedFilePath = str(_exportHydraulic(editor, formatting="mfs")) trnExePath = str(_getTrnExePath()) @@ -115,8 +115,8 @@ def _exportMassFlowSolverDeckAndRunTrnsys(editor: _de.Editor): # type: ignore[n return exception -def _exportHydraulic(editor: _de.Editor, *, _format) -> str: # type: ignore[name-defined] - exportedFilePath = editor.exportHydraulics(exportTo=_format) +def _exportHydraulic(editor: _de.Editor, *, formatting) -> str: # type: ignore[name-defined] + exportedFilePath = editor.exportHydraulics(exportTo=formatting) return exportedFilePath From b5fba85d03816051b80f28837bbd8304435ed22c Mon Sep 17 00:00:00 2001 From: ahobeost Date: Tue, 4 Jul 2023 11:07:32 +0200 Subject: [PATCH 18/56] Using OO to reduce required argument passing. --- .../testPrintRegimesAndCopyFiles.py | 10 +- .../renderDiagramOnPDFfromPython.py | 229 +++++++++--------- 2 files changed, 125 insertions(+), 114 deletions(-) diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py index 10b2dbc3..4d45be8e 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py @@ -11,7 +11,7 @@ _PROJECT_NAME = "diagramForRegimes" _DATA_DIR = _pl.Path(_GUI.__file__).parent / f"..\\tests\\trnsysGUI\\data\\{_PROJECT_NAME}" -_DATA_FILENAME = "regimes.csv" +_REGIMES_FILENAME = "regimes.csv" _EXPECTED_PDFS_DIR = _DATA_DIR / "expectedPDFs" _RESULTS_DIR = _DATA_DIR / "results" _RESULTS_DIR_2 = _DATA_DIR / "resultsReducedUsage" @@ -71,7 +71,8 @@ def testMplInstallation(self): def testUsingQtBot(self, qtbot): mainWindow = _createMainWindow(_DATA_DIR, _PROJECT_NAME, qtbot) - _rdopfp.printRegimesAndCopyFiles(_DATA_DIR, _PROJECT_NAME, _RESULTS_DIR, _DATA_FILENAME, mainWindow) + regimeExporter = _rdopfp.RegimeExporter(_PROJECT_NAME, _DATA_DIR, _RESULTS_DIR, _REGIMES_FILENAME, mainWindow) + regimeExporter.export() self._fileExistsAndIsCorrect(_NEW_DIAGRAM_PATH, _EXPECTED_DIAGRAM_PATH) self._fileExistsAndIsCorrect(_NEW_NAME1_PATH, _EXPECTED_NAME1_PATH) @@ -86,8 +87,9 @@ def _fileExistsAndIsCorrect(producedFile, expectedFile): def testUsingQtBotForGivenRegimes(self, qtbot): onlyTheseRegimes = ["name1"] mainWindow = _createMainWindow(_DATA_DIR, _PROJECT_NAME, qtbot) - _rdopfp.printRegimesAndCopyFiles(_DATA_DIR, _PROJECT_NAME, _RESULTS_DIR_2, _DATA_FILENAME, mainWindow, - onlyTheseRegimes=onlyTheseRegimes) + regimeExporter = _rdopfp.RegimeExporter(_PROJECT_NAME, _DATA_DIR, _RESULTS_DIR_2, _REGIMES_FILENAME, mainWindow) + regimeExporter.export(onlyTheseRegimes=onlyTheseRegimes) + self._fileExistsAndIsCorrect(_NEW_NAME1_PATH_2, _EXPECTED_NAME1_PATH) self._fileExistsAndIsCorrect(_NEW_NAME1_PATH_2, _EXPECTED_DIAGRAM_PATH) assert not _NEW_DIAGRAM_PATH_2.is_file() diff --git a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py index 83ef7214..db5178f1 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py +++ b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py @@ -1,3 +1,4 @@ +import dataclasses as _dc import os as _os import pathlib as _pl import subprocess as _sp @@ -8,97 +9,128 @@ import PyQt5.QtSvg as _qtsvg import PyQt5.QtCore as _qtc -import trnsysGUI.pythonInterface.regimeExporter.getDesiredRegimes as _gdr -import trnsysGUI.MassFlowVisualizer as _mfv import trnsysGUI.diagram.Editor as _de - - +import trnsysGUI.MassFlowVisualizer as _mfv +import trnsysGUI.mainWindow as _mw import trnsysGUI.pump as _pump +import trnsysGUI.pythonInterface.regimeExporter.getDesiredRegimes as _gdr import trnsysGUI.TVentil as _tv - import trnsysGUI.WTap_main as _wtm -def getPumpsAndValvesAndMainTaps(pumpsAndValvesNames, mainWindow): - pumpsAndValves = [] - mainTaps = {} - blockItemsAndConnections = mainWindow.editor.trnsysObj - for blockItem in blockItemsAndConnections: - if isinstance(blockItem, (_pump.Pump, _tv.TVentil)): - if blockItem.displayName in pumpsAndValvesNames: - pumpsAndValves.append(blockItem) - elif isinstance(blockItem, _wtm.WTap_main): - mainTaps[blockItem.displayName] = blockItem - - return pumpsAndValves, mainTaps - - -def printRegimesAndCopyFiles( - dataDir, projectName, resultsDir, dataFileName, mainWindow, pumpTapPairs=None, onlyTheseRegimes=None -): - # createPDF of diagram only - if not onlyTheseRegimes: - makeDiagramFiles(projectName, resultsDir, mainWindow) - - regimeValues = _gdr.getRegimes(dataDir / dataFileName, onlyTheseRegimes) - pumpsAndValvesNames = list(regimeValues.columns) - pumpsAndValves, mainTaps = getPumpsAndValvesAndMainTaps(pumpsAndValvesNames, mainWindow) - massFlowRatesPrintFilePath, temperaturesPrintFilePath = getPrtFilePaths(dataDir, projectName) - - for regimeName in regimeValues.index: - regimeRow = regimeValues.loc[regimeName] - - adjustPumpsAndValves(pumpsAndValves, regimeRow, pumpTapPairs, mainTaps) - - exception = runMassFlowSolver(mainWindow) - - if not exception: - timeStep = 2 - else: - regimeName = regimeName + "_FAILED" - timeStep = 1 - - massFlowSolverVisualizer = _mfv.MassFlowVisualizer( # type: ignore[attr-defined] # pylint: disable=unused-variable - mainWindow, massFlowRatesPrintFilePath, temperaturesPrintFilePath - ) - massFlowSolverVisualizer.slider.setValue(timeStep) - - makeDiagramFiles(projectName, resultsDir, mainWindow, regimeName=regimeName) - - massFlowSolverVisualizer.close() - - -def getPrtFilePaths(dataDir, projectName): - massFlowRatesPrintFileName = f"{projectName}_Mfr.prt" - temperaturesPintFileName = f"{projectName}_T.prt" - massFlowRatesPrintFilePath = dataDir / massFlowRatesPrintFileName - temperaturesPrintFilePath = dataDir / temperaturesPintFileName - return massFlowRatesPrintFilePath, temperaturesPrintFilePath - - -def makeDiagramFiles(projectName, resultsDir, mainWindow, regimeName="diagram"): - pdfName = str(resultsDir) + "\\" + projectName + "_" + regimeName + ".pdf" - svgName = str(resultsDir) + "\\" + projectName + "_" + regimeName + ".svg" - printDiagramToPDF(pdfName, mainWindow) - printDiagramToSVG(svgName, mainWindow) - - -def adjustPumpsAndValves(pumpsAndValves, regimeRow, pumpTapPairs, mainTaps): - - for blockItem in pumpsAndValves: - blockItemName = blockItem.displayName - desiredValue = regimeRow[blockItemName] - if isinstance(blockItem, _pump.Pump): - # assert desiredValue meaningful - blockItem.massFlowRateInKgPerH = desiredValue - if pumpTapPairs and (blockItemName in pumpTapPairs): - associatedTap = pumpTapPairs[blockItemName] - mainTaps[associatedTap].massFlowRateInKgPerH = desiredValue - elif isinstance(blockItem, _tv.TVentil): - # assert desiredValue meaningful - blockItem.positionForMassFlowSolver = desiredValue - else: - raise TypeError(f"Encountered blockItem of type {blockItem}, instead of a pump or a Valve") +@_dc.dataclass() +class RegimeExporter: + projectName: _tp.Union[str, _pl.Path] + dataDir: _tp.Union[str, _pl.Path] + resultsDir: _tp.Union[str, _pl.Path] + regimesFileName: _tp.Union[str, _pl.Path] + mainWindow: _mw.MainWindow + + def __post_init__(self): + self.printFilePaths: list = self._getPrtFilePaths() + + def _getPrtFilePaths(self): + massFlowRatesPrintFileName = f"{self.projectName}_Mfr.prt" + temperaturesPintFileName = f"{self.projectName}_T.prt" + massFlowRatesPrintFilePath = self.dataDir / massFlowRatesPrintFileName + temperaturesPrintFilePath = self.dataDir / temperaturesPintFileName + + return [massFlowRatesPrintFilePath, temperaturesPrintFilePath] + + def export(self, pumpTapPairs=None, onlyTheseRegimes=None): + + if not onlyTheseRegimes: + self._makeDiagramFiles() + + regimeValues = _gdr.getRegimes(self.dataDir / self.regimesFileName, onlyTheseRegimes) + pumpsAndValvesNames = list(regimeValues.columns) + pumpsAndValves, mainTaps = self.getPumpsAndValvesAndMainTaps(pumpsAndValvesNames) + + self._simulateAndVisualizeMassFlows(mainTaps, pumpTapPairs, pumpsAndValves, regimeValues) + + def _makeDiagramFiles(self, regimeName="diagram"): + pdfName = str(self.resultsDir) + "\\" + self.projectName + "_" + regimeName + ".pdf" + svgName = str(self.resultsDir) + "\\" + self.projectName + "_" + regimeName + ".svg" + self._printDiagramToPDF(pdfName) + self._printDiagramToSVG(svgName) + + def getPumpsAndValvesAndMainTaps(self, pumpsAndValvesNames): + pumpsAndValves = [] + mainTaps = {} + blockItemsAndConnections = self.mainWindow.editor.trnsysObj + for blockItem in blockItemsAndConnections: + if isinstance(blockItem, (_pump.Pump, _tv.TVentil)): + if blockItem.displayName in pumpsAndValvesNames: + pumpsAndValves.append(blockItem) + elif isinstance(blockItem, _wtm.WTap_main): + mainTaps[blockItem.displayName] = blockItem + + return pumpsAndValves, mainTaps + + def _simulateAndVisualizeMassFlows(self, mainTaps, pumpTapPairs, pumpsAndValves, regimeValues): + massFlowRatesPrintFilePath, temperaturesPrintFilePath = self.printFilePaths + + for regimeName in regimeValues.index: + regimeRow = regimeValues.loc[regimeName] + + self._adjustPumpsAndValves(pumpsAndValves, regimeRow, pumpTapPairs, mainTaps) + + exception = runMassFlowSolver(self.mainWindow) + + if not exception: + timeStep = 2 + else: + regimeName = regimeName + "_FAILED" + timeStep = 1 + + massFlowSolverVisualizer = _mfv.MassFlowVisualizer( + # type: ignore[attr-defined] # pylint: disable=unused-variable + self.mainWindow, + massFlowRatesPrintFilePath, + temperaturesPrintFilePath, + ) + massFlowSolverVisualizer.slider.setValue(timeStep) + + self._makeDiagramFiles(regimeName=regimeName) + + massFlowSolverVisualizer.close() + + @staticmethod + def _adjustPumpsAndValves(pumpsAndValves, regimeRow, pumpTapPairs, mainTaps): + + for blockItem in pumpsAndValves: + blockItemName = blockItem.displayName + desiredValue = regimeRow[blockItemName] + if isinstance(blockItem, _pump.Pump): + blockItem.massFlowRateInKgPerH = desiredValue + if pumpTapPairs and (blockItemName in pumpTapPairs): + associatedTap = pumpTapPairs[blockItemName] + mainTaps[associatedTap].massFlowRateInKgPerH = desiredValue + elif isinstance(blockItem, _tv.TVentil): + blockItem.positionForMassFlowSolver = desiredValue + else: + raise TypeError(f"Encountered blockItem of type {blockItem}, instead of a pump or a Valve") + + def _printDiagramToPDF(self, fileName): + if fileName != "": + printer = _qtp.QPrinter(_qtp.QPrinter.HighResolution) + printer.setOrientation(_qtp.QPrinter.Landscape) + printer.setOutputFormat(_qtp.QPrinter.PdfFormat) + printer.setOutputFileName(fileName) + painter = _qtg.QPainter(printer) + self.mainWindow.editor.diagramScene.render(painter) + painter.end() + + def _printDiagramToSVG(self, fileName): + # upside down and tiny compared to canvas + if fileName != "": + generator = _qtsvg.QSvgGenerator() + generator.setSize(_qtc.QSize(1600, 1600)) + generator.setViewBox(_qtc.QRect(0, 0, 1600, 1600)) + generator.setFileName(fileName) + painter = _qtg.QPainter(generator) + self.mainWindow.editor.diagramScene.render(painter) + painter.end() def runMassFlowSolver(mainWindow) -> _tp.Optional[Exception]: @@ -128,29 +160,6 @@ def _getTrnExePath(): return _pl.PureWindowsPath(r"C:\TRNSYS18\Exe\TrnEXE.exe") -def printDiagramToPDF(fileName, mainWindow): - if fileName != "": - printer = _qtp.QPrinter(_qtp.QPrinter.HighResolution) - printer.setOrientation(_qtp.QPrinter.Landscape) - printer.setOutputFormat(_qtp.QPrinter.PdfFormat) - printer.setOutputFileName(fileName) - painter = _qtg.QPainter(printer) - mainWindow.editor.diagramScene.render(painter) - painter.end() - - -def printDiagramToSVG(fileName, mainWindow): - # upside down and tiny compared to canvas - if fileName != "": - generator = _qtsvg.QSvgGenerator() - generator.setSize(_qtc.QSize(1600, 1600)) - generator.setViewBox(_qtc.QRect(0, 0, 1600, 1600)) - generator.setFileName(fileName) - painter = _qtg.QPainter(generator) - mainWindow.editor.diagramScene.render(painter) - painter.end() - - def runDck(cmd, dckName): exception = None try: @@ -159,8 +168,8 @@ def runDck(cmd, dckName): skipOthers = False else: raise FileNotFoundError("File not found: " + dckName) - except Exception as e: + except _sp.CalledProcessError as caughtException: skipOthers = True - exception = e + exception = caughtException return skipOthers, exception From f27d910d2839b9f81863e5b5f9baec599e42fa2b Mon Sep 17 00:00:00 2001 From: ahobeost Date: Tue, 4 Jul 2023 11:21:58 +0200 Subject: [PATCH 19/56] Typing --- .../testExportRegimeTemplate.py | 4 +- .../regimeExporter/exportRegimes.py | 2 +- .../regimeExporter/getDesiredRegimes.py | 3 +- .../renderDiagramOnPDFfromPython.py | 38 ++++++++++--------- 4 files changed, 26 insertions(+), 21 deletions(-) diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py index d5af1af2..4eaf3067 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py @@ -16,7 +16,7 @@ def testExportTemplate(self): _er.exportRegimeTemplate(projectJson, regimeFileName) - expectedContent = _pl.Path(expectedFileName).read_text(encoding='utf-8') - actualContent = _pl.Path(regimeFileName).read_text(encoding='utf-8') + expectedContent = _pl.Path(expectedFileName).read_text(encoding="utf-8") + actualContent = _pl.Path(regimeFileName).read_text(encoding="utf-8") assert actualContent == expectedContent diff --git a/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py b/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py index d8f80bc0..affa5f51 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py +++ b/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py @@ -9,7 +9,7 @@ def exportRegimeTemplate(projectJson, regimeFileName): def getPumpsAndValvesWithValuesFromJson(projectJson): - with open(projectJson, 'r', encoding='utf-8') as openFile: + with open(projectJson, "r", encoding="utf-8") as openFile: jsonValues = json.load(openFile) data = {} diff --git a/trnsysGUI/pythonInterface/regimeExporter/getDesiredRegimes.py b/trnsysGUI/pythonInterface/regimeExporter/getDesiredRegimes.py index 190eef03..4e7ce141 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/getDesiredRegimes.py +++ b/trnsysGUI/pythonInterface/regimeExporter/getDesiredRegimes.py @@ -10,6 +10,7 @@ def getRegimesFromFile(fileName): return table raise ValueError(f"Column name '{colName}' not found.") + # error handling? # - will throw "fileNotFoundError" as it is. # @@ -23,7 +24,7 @@ def getRegimesFromFile(fileName): def getRegimes(filePath, onlyTheseRegimes): regimeValues = getRegimesFromFile(filePath) - regimeValues = regimeValues.set_index('regimeName') + regimeValues = regimeValues.set_index("regimeName") if onlyTheseRegimes: return regimeValues.loc[onlyTheseRegimes] return regimeValues diff --git a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py index db5178f1..85c1e05b 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py +++ b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py @@ -8,6 +8,7 @@ import PyQt5.QtPrintSupport as _qtp import PyQt5.QtSvg as _qtsvg import PyQt5.QtCore as _qtc +import pandas as _pd import trnsysGUI.diagram.Editor as _de import trnsysGUI.MassFlowVisualizer as _mfv @@ -18,26 +19,26 @@ import trnsysGUI.WTap_main as _wtm -@_dc.dataclass() +@_dc.dataclass class RegimeExporter: projectName: _tp.Union[str, _pl.Path] dataDir: _tp.Union[str, _pl.Path] resultsDir: _tp.Union[str, _pl.Path] regimesFileName: _tp.Union[str, _pl.Path] - mainWindow: _mw.MainWindow + mainWindow: _mw.MainWindow # type: ignore[name-defined] - def __post_init__(self): - self.printFilePaths: list = self._getPrtFilePaths() + def __post_init__(self) -> None: + self.massFlowRatesPrintFilePath, self.temperaturesPrintFilePath = self._getPrtFilePaths() - def _getPrtFilePaths(self): + def _getPrtFilePaths(self) -> [str, str]: massFlowRatesPrintFileName = f"{self.projectName}_Mfr.prt" temperaturesPintFileName = f"{self.projectName}_T.prt" massFlowRatesPrintFilePath = self.dataDir / massFlowRatesPrintFileName temperaturesPrintFilePath = self.dataDir / temperaturesPintFileName - return [massFlowRatesPrintFilePath, temperaturesPrintFilePath] + return massFlowRatesPrintFilePath, temperaturesPrintFilePath - def export(self, pumpTapPairs=None, onlyTheseRegimes=None): + def export(self, pumpTapPairs: list = None, onlyTheseRegimes: list = None) -> None: if not onlyTheseRegimes: self._makeDiagramFiles() @@ -48,13 +49,13 @@ def export(self, pumpTapPairs=None, onlyTheseRegimes=None): self._simulateAndVisualizeMassFlows(mainTaps, pumpTapPairs, pumpsAndValves, regimeValues) - def _makeDiagramFiles(self, regimeName="diagram"): + def _makeDiagramFiles(self, regimeName="diagram") -> None: pdfName = str(self.resultsDir) + "\\" + self.projectName + "_" + regimeName + ".pdf" svgName = str(self.resultsDir) + "\\" + self.projectName + "_" + regimeName + ".svg" self._printDiagramToPDF(pdfName) self._printDiagramToSVG(svgName) - def getPumpsAndValvesAndMainTaps(self, pumpsAndValvesNames): + def getPumpsAndValvesAndMainTaps(self, pumpsAndValvesNames: list) -> [list, dict]: pumpsAndValves = [] mainTaps = {} blockItemsAndConnections = self.mainWindow.editor.trnsysObj @@ -67,8 +68,9 @@ def getPumpsAndValvesAndMainTaps(self, pumpsAndValvesNames): return pumpsAndValves, mainTaps - def _simulateAndVisualizeMassFlows(self, mainTaps, pumpTapPairs, pumpsAndValves, regimeValues): - massFlowRatesPrintFilePath, temperaturesPrintFilePath = self.printFilePaths + def _simulateAndVisualizeMassFlows( + self, mainTaps: dict, pumpTapPairs: list, pumpsAndValves: list, regimeValues: _pd.DataFrame + ) -> None: for regimeName in regimeValues.index: regimeRow = regimeValues.loc[regimeName] @@ -86,8 +88,8 @@ def _simulateAndVisualizeMassFlows(self, mainTaps, pumpTapPairs, pumpsAndValves, massFlowSolverVisualizer = _mfv.MassFlowVisualizer( # type: ignore[attr-defined] # pylint: disable=unused-variable self.mainWindow, - massFlowRatesPrintFilePath, - temperaturesPrintFilePath, + self.massFlowRatesPrintFilePath, + self.temperaturesPrintFilePath, ) massFlowSolverVisualizer.slider.setValue(timeStep) @@ -96,7 +98,9 @@ def _simulateAndVisualizeMassFlows(self, mainTaps, pumpTapPairs, pumpsAndValves, massFlowSolverVisualizer.close() @staticmethod - def _adjustPumpsAndValves(pumpsAndValves, regimeRow, pumpTapPairs, mainTaps): + def _adjustPumpsAndValves( + pumpsAndValves: list, regimeRow: _pd.DataFrame, pumpTapPairs: list, mainTaps: dict + ) -> None: for blockItem in pumpsAndValves: blockItemName = blockItem.displayName @@ -111,7 +115,7 @@ def _adjustPumpsAndValves(pumpsAndValves, regimeRow, pumpTapPairs, mainTaps): else: raise TypeError(f"Encountered blockItem of type {blockItem}, instead of a pump or a Valve") - def _printDiagramToPDF(self, fileName): + def _printDiagramToPDF(self, fileName: str) -> None: if fileName != "": printer = _qtp.QPrinter(_qtp.QPrinter.HighResolution) printer.setOrientation(_qtp.QPrinter.Landscape) @@ -121,7 +125,7 @@ def _printDiagramToPDF(self, fileName): self.mainWindow.editor.diagramScene.render(painter) painter.end() - def _printDiagramToSVG(self, fileName): + def _printDiagramToSVG(self, fileName: str) -> None: # upside down and tiny compared to canvas if fileName != "": generator = _qtsvg.QSvgGenerator() @@ -160,7 +164,7 @@ def _getTrnExePath(): return _pl.PureWindowsPath(r"C:\TRNSYS18\Exe\TrnEXE.exe") -def runDck(cmd, dckName): +def runDck(cmd: str, dckName: str) -> [bool, _tp.Optional[Exception]]: exception = None try: if _os.path.isfile(dckName): From 9c752837c82d2de3fc32dfb7b860a81573c92f58 Mon Sep 17 00:00:00 2001 From: ahobeost Date: Tue, 4 Jul 2023 11:30:22 +0200 Subject: [PATCH 20/56] CI adjustments --- .../renderDiagramOnPDFfromPython.py | 28 ++++++++----------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py index 85c1e05b..a961aca6 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py +++ b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py @@ -8,7 +8,6 @@ import PyQt5.QtPrintSupport as _qtp import PyQt5.QtSvg as _qtsvg import PyQt5.QtCore as _qtc -import pandas as _pd import trnsysGUI.diagram.Editor as _de import trnsysGUI.MassFlowVisualizer as _mfv @@ -21,16 +20,16 @@ @_dc.dataclass class RegimeExporter: - projectName: _tp.Union[str, _pl.Path] - dataDir: _tp.Union[str, _pl.Path] - resultsDir: _tp.Union[str, _pl.Path] - regimesFileName: _tp.Union[str, _pl.Path] + projectName: str + dataDir: _pl.Path + resultsDir: _pl.Path + regimesFileName: str mainWindow: _mw.MainWindow # type: ignore[name-defined] def __post_init__(self) -> None: self.massFlowRatesPrintFilePath, self.temperaturesPrintFilePath = self._getPrtFilePaths() - def _getPrtFilePaths(self) -> [str, str]: + def _getPrtFilePaths(self): massFlowRatesPrintFileName = f"{self.projectName}_Mfr.prt" temperaturesPintFileName = f"{self.projectName}_T.prt" massFlowRatesPrintFilePath = self.dataDir / massFlowRatesPrintFileName @@ -38,7 +37,7 @@ def _getPrtFilePaths(self) -> [str, str]: return massFlowRatesPrintFilePath, temperaturesPrintFilePath - def export(self, pumpTapPairs: list = None, onlyTheseRegimes: list = None) -> None: + def export(self, pumpTapPairs=None, onlyTheseRegimes=None) -> None: if not onlyTheseRegimes: self._makeDiagramFiles() @@ -55,7 +54,7 @@ def _makeDiagramFiles(self, regimeName="diagram") -> None: self._printDiagramToPDF(pdfName) self._printDiagramToSVG(svgName) - def getPumpsAndValvesAndMainTaps(self, pumpsAndValvesNames: list) -> [list, dict]: + def getPumpsAndValvesAndMainTaps(self, pumpsAndValvesNames): pumpsAndValves = [] mainTaps = {} blockItemsAndConnections = self.mainWindow.editor.trnsysObj @@ -68,9 +67,7 @@ def getPumpsAndValvesAndMainTaps(self, pumpsAndValvesNames: list) -> [list, dict return pumpsAndValves, mainTaps - def _simulateAndVisualizeMassFlows( - self, mainTaps: dict, pumpTapPairs: list, pumpsAndValves: list, regimeValues: _pd.DataFrame - ) -> None: + def _simulateAndVisualizeMassFlows(self, mainTaps, pumpTapPairs, pumpsAndValves, regimeValues) -> None: for regimeName in regimeValues.index: regimeRow = regimeValues.loc[regimeName] @@ -85,8 +82,7 @@ def _simulateAndVisualizeMassFlows( regimeName = regimeName + "_FAILED" timeStep = 1 - massFlowSolverVisualizer = _mfv.MassFlowVisualizer( - # type: ignore[attr-defined] # pylint: disable=unused-variable + massFlowSolverVisualizer = _mfv.MassFlowVisualizer( # type: ignore[attr-defined] self.mainWindow, self.massFlowRatesPrintFilePath, self.temperaturesPrintFilePath, @@ -98,9 +94,7 @@ def _simulateAndVisualizeMassFlows( massFlowSolverVisualizer.close() @staticmethod - def _adjustPumpsAndValves( - pumpsAndValves: list, regimeRow: _pd.DataFrame, pumpTapPairs: list, mainTaps: dict - ) -> None: + def _adjustPumpsAndValves(pumpsAndValves, regimeRow, pumpTapPairs, mainTaps) -> None: for blockItem in pumpsAndValves: blockItemName = blockItem.displayName @@ -164,7 +158,7 @@ def _getTrnExePath(): return _pl.PureWindowsPath(r"C:\TRNSYS18\Exe\TrnEXE.exe") -def runDck(cmd: str, dckName: str) -> [bool, _tp.Optional[Exception]]: +def runDck(cmd, dckName): exception = None try: if _os.path.isfile(dckName): From e7fc55cd7f41bbde2d2fb1c317c62c051c8a181e Mon Sep 17 00:00:00 2001 From: ahobeost Date: Tue, 4 Jul 2023 12:27:35 +0200 Subject: [PATCH 21/56] Adjustment for Sonarcloud --- .../regimeExporter/renderDiagramOnPDFfromPython.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py index a961aca6..168401eb 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py +++ b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py @@ -26,7 +26,7 @@ class RegimeExporter: regimesFileName: str mainWindow: _mw.MainWindow # type: ignore[name-defined] - def __post_init__(self) -> None: + def __post_init__(self) -> None: # /NOSONAR self.massFlowRatesPrintFilePath, self.temperaturesPrintFilePath = self._getPrtFilePaths() def _getPrtFilePaths(self): From d94e5d2cae638eae25035220de1b8035d1ba3850 Mon Sep 17 00:00:00 2001 From: spfRechenknecht Date: Wed, 5 Jul 2023 11:26:16 +0200 Subject: [PATCH 22/56] Added path printing to CI --- .github/workflows/build-windows.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 41b334d5..f6c127ae 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -15,6 +15,11 @@ jobs: runs-on: [self-hosted, etzel] steps: - uses: actions/checkout@v3 + - name: Display the path + run: | + import os + print(os.environ['PATH']) + shell: python - name: Remove old venv run: | if (Test-Path -LiteralPath venv) { From 2ac12fe764df8ee02a58f2e149fe92a9a674791b Mon Sep 17 00:00:00 2001 From: spfRechenknecht Date: Wed, 5 Jul 2023 11:28:36 +0200 Subject: [PATCH 23/56] Adjusted path printing to windows CMD --- .github/workflows/build-windows.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index f6c127ae..9590060f 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -16,10 +16,8 @@ jobs: steps: - uses: actions/checkout@v3 - name: Display the path - run: | - import os - print(os.environ['PATH']) - shell: python + run: echo %PATH% + shell: cmd - name: Remove old venv run: | if (Test-Path -LiteralPath venv) { From 99f6c1887f9a8462789ca719df11b6a30e6f81d6 Mon Sep 17 00:00:00 2001 From: ahobeost Date: Wed, 5 Jul 2023 13:10:24 +0200 Subject: [PATCH 24/56] adding Inkscape path to GITHUB_PATH --- .github/workflows/build-windows.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 9590060f..5fae7563 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -18,6 +18,12 @@ jobs: - name: Display the path run: echo %PATH% shell: cmd + - name: Add Inkscape to the path + run: "{C:\CI-Progams\Inkscape\bin}" >> $env:GITHUB_PATH + shell: pwsh + - name: Display the path AGAIN + run: echo %PATH% + shell: cmd - name: Remove old venv run: | if (Test-Path -LiteralPath venv) { From 4d0deb75a4b01c93dbfdd652d9e6b701ab59497b Mon Sep 17 00:00:00 2001 From: ahobeost Date: Wed, 5 Jul 2023 13:13:44 +0200 Subject: [PATCH 25/56] adjusting declaration of Inkscape path --- .github/workflows/build-windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 5fae7563..7ac5b263 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -19,7 +19,7 @@ jobs: run: echo %PATH% shell: cmd - name: Add Inkscape to the path - run: "{C:\CI-Progams\Inkscape\bin}" >> $env:GITHUB_PATH + run: echo "C:\CI-Progams\Inkscape\bin" >> $env:GITHUB_PATH shell: pwsh - name: Display the path AGAIN run: echo %PATH% From 9f5b8478d9e456086af50e6b033c81f407975cb0 Mon Sep 17 00:00:00 2001 From: ahobeost Date: Wed, 5 Jul 2023 13:15:48 +0200 Subject: [PATCH 26/56] using evironmental variable file definition for Inkscape path --- .github/workflows/build-windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 7ac5b263..f3dbcda0 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -19,7 +19,7 @@ jobs: run: echo %PATH% shell: cmd - name: Add Inkscape to the path - run: echo "C:\CI-Progams\Inkscape\bin" >> $env:GITHUB_PATH + run: echo "C:\CI-Progams\Inkscape\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append shell: pwsh - name: Display the path AGAIN run: echo %PATH% From a56edeb0d112ec863209d6908eb057165d014004 Mon Sep 17 00:00:00 2001 From: ahobeost Date: Wed, 5 Jul 2023 13:17:01 +0200 Subject: [PATCH 27/56] removing shell declaration for Inkscape path declaration --- .github/workflows/build-windows.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index f3dbcda0..23beaa77 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -20,7 +20,6 @@ jobs: shell: cmd - name: Add Inkscape to the path run: echo "C:\CI-Progams\Inkscape\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - shell: pwsh - name: Display the path AGAIN run: echo %PATH% shell: cmd From 4df6ba30c6714dca453db714964f354bf64072f8 Mon Sep 17 00:00:00 2001 From: ahobeost Date: Wed, 5 Jul 2023 13:34:15 +0200 Subject: [PATCH 28/56] Removing path printing from jobs --- .github/workflows/build-windows.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 23beaa77..6bff0bef 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -15,14 +15,8 @@ jobs: runs-on: [self-hosted, etzel] steps: - uses: actions/checkout@v3 - - name: Display the path - run: echo %PATH% - shell: cmd - name: Add Inkscape to the path run: echo "C:\CI-Progams\Inkscape\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - - name: Display the path AGAIN - run: echo %PATH% - shell: cmd - name: Remove old venv run: | if (Test-Path -LiteralPath venv) { From 44ba1c650264481b0d40627a5088fba84be7c1cf Mon Sep 17 00:00:00 2001 From: ahobeost Date: Wed, 5 Jul 2023 14:52:16 +0200 Subject: [PATCH 29/56] Adjustments to files to overcome bug and refactoring of test --- .../expectedCSVs/expectedRegimeTemplate.csv | 2 +- .../data/diagramForRegimes/regimes.csv | 6 +- .../ddck/generic/end.ddck | 14 ++ .../ddck/generic/head.ddck | 110 ++++++++++++ .../diagramWithTapForRegimes.json | 161 ++++++++++++++++++ .../diagramWithTapForRegimes_dummy_regime.pdf | Bin 0 -> 8899 bytes .../data/diagramWithTapForRegimes/regimes.csv | 3 + .../testPrintRegimesAndCopyFiles.py | 118 +++++++++++-- .../regimeExporter/exportRegimes.py | 2 +- 9 files changed, 393 insertions(+), 23 deletions(-) create mode 100644 tests/trnsysGUI/data/diagramWithTapForRegimes/ddck/generic/end.ddck create mode 100644 tests/trnsysGUI/data/diagramWithTapForRegimes/ddck/generic/head.ddck create mode 100644 tests/trnsysGUI/data/diagramWithTapForRegimes/diagramWithTapForRegimes.json create mode 100644 tests/trnsysGUI/data/diagramWithTapForRegimes/expectedPDFs/diagramWithTapForRegimes_dummy_regime.pdf create mode 100644 tests/trnsysGUI/data/diagramWithTapForRegimes/regimes.csv diff --git a/tests/trnsysGUI/data/diagramForRegimes/expectedCSVs/expectedRegimeTemplate.csv b/tests/trnsysGUI/data/diagramForRegimes/expectedCSVs/expectedRegimeTemplate.csv index 411cf016..569d29af 100644 --- a/tests/trnsysGUI/data/diagramForRegimes/expectedCSVs/expectedRegimeTemplate.csv +++ b/tests/trnsysGUI/data/diagramForRegimes/expectedCSVs/expectedRegimeTemplate.csv @@ -1,2 +1,2 @@ regimeName,pump1,pump2,pump3,valve1,valve2 -'dummy regime',500.0,0.0,500.0,0.0,0.0 +dummy regime,500.0,0.0,500.0,0.0,0.0 diff --git a/tests/trnsysGUI/data/diagramForRegimes/regimes.csv b/tests/trnsysGUI/data/diagramForRegimes/regimes.csv index e2a6af09..9a62101d 100644 --- a/tests/trnsysGUI/data/diagramForRegimes/regimes.csv +++ b/tests/trnsysGUI/data/diagramForRegimes/regimes.csv @@ -1,4 +1,4 @@ regimeName,pump1,pump2,pump3,valve1,valve2 -"name1",500,0,500,0,0 -"name2",500,500,0,0,1 -"throws",0,0,500,0,1 \ No newline at end of file +name1,500,0,500,0,0 +name2,500,500,0,0,1 +throws,0,0,500,0,1 \ No newline at end of file diff --git a/tests/trnsysGUI/data/diagramWithTapForRegimes/ddck/generic/end.ddck b/tests/trnsysGUI/data/diagramWithTapForRegimes/ddck/generic/end.ddck new file mode 100644 index 00000000..86bc6bfd --- /dev/null +++ b/tests/trnsysGUI/data/diagramWithTapForRegimes/ddck/generic/end.ddck @@ -0,0 +1,14 @@ +******************************* +**BEGIN Head.ddck +******************************* + +***************************************** +** Contact person: Dani Carbonell +** Date: 30.09.2016 +***************************************** + +END + +******************************* +**END End.ddck +******************************* diff --git a/tests/trnsysGUI/data/diagramWithTapForRegimes/ddck/generic/head.ddck b/tests/trnsysGUI/data/diagramWithTapForRegimes/ddck/generic/head.ddck new file mode 100644 index 00000000..b20348bd --- /dev/null +++ b/tests/trnsysGUI/data/diagramWithTapForRegimes/ddck/generic/head.ddck @@ -0,0 +1,110 @@ +******************************* +**BEGIN Head.ddck +******************************* + +***************************************** +** Contact person: Dani Carbonell +** Date: 30.09.2016 +***************************************** + +*************************************************************************** +** Description: +** Basic TRNSYS variables including fluid properties +*************************************************************************** + +VERSION 17 + +************************************** +***Simulation time ****** +************************************** + +CONSTANTS 3 +START = 0 +STOP = 8760 +dtSim = 1/30. ! time step in hours + +************************************** +***TRNSYS SIMULATION constants ****** +************************************** + +CONSTANTS 13 +nIteTrnsys = 30 ! TRNSYS Limit of iterations +nWarnTrnsys = 12000 ! TRNSYS Limit of warnings +nCallTraceTrnys = 31 ! TRNSYS limit of calls to a component before it will be traced +FrInte_Tol = 0.003 ! TRNSYS solver tolerances +FrConv_Tol = 0.0005 ! TRNSYS solver tolerances +nan_check_bool = 1 ! TRNSYS nan check boolean +time_report = 1 ! TRNSYS time report +solver_equation = 0 ! TRNSYS EQUATION SOLVER statement +debug_statement = 0 ! TRNSYS Overwrite DEBUG statement +solver_statement = 0 ! TRNSYS Solver statement +min_relax_factor = 1 ! TRNSYS Minimum relaxation factor +max_relac_factor = 1 ! TRNSYS Maximum relaxation factor +solver_integration = 1 ! TRNSYS numerical integration solver method + + +************************************** +***TRNSYS SIMULATION SET-UP ****** +************************************** + +SIMULATION START STOP dtSim +TOLERANCES FrInte_Tol FrConv_Tol +LIMITS nIteTrnsys nWarnTrnsys nCallTraceTrnys ! Limit of Iterations, limit of warnings, limit of calls to a component before it will be traced +DFQ solver_integration ! TRNSYS numerical integration solver method +WIDTH 132 ! TRNSYS output file width, number of characters +LIST ! NOLIST statement + +SOLVER solver_statement min_relax_factor max_relac_factor ! Solver statement, Minimum relaxation factor, Maximum relaxation factor +NAN_CHECK nan_check_bool ! Nan DEBUG statement +OVERWRITE_CHECK debug_statement ! Overwrite DEBUG statement +EQSOLVER solver_equation ! EQUATION SOLVER statement +TIME_REPORT time_report + + +************************************** +*** MASS FLOW SOLVER CONSTANTS ****** +************************************** + +CONSTANTS 3 +mfrSolverAbsTol = 1e-8 +mfrSolverRelTol = 1e-8 +mfrTolSwitchThreshold = 1e2 + +************************************** +***User defined printer settings****** +************************************** + +CONSTANTS 3 + +tStrtUser = START ! START start time of user defined printer +tEndUser = STOP ! END time of user defined printer +dtPrUser = dtSim ! timestep of user defined printer + +************************************** +***Generic Constants ****** +************************************** + +CONSTANTS 6 +versionDeck = 1 !can be changed from config file to adapt processes and so on +PI = 3.1415926 +Zero = 0 +Nix = 0 +notused = 0 +NPlotsPerSim = 18 + +************************************** +***Constant fluid properties ****** +************************************** + +CONSTANTS 7 +CPBRI = 3.8160 ! spec. heat of Glycol [kJ/kgK]; Value for an average pipe temperature with 55 °C Tyfocor LS +RHOBRI = 1016.0 ! density Glycol [kg/m³]; Value for an average pipe temperature with 55 °C Tyfocor L +CPWAT = 4.19 ! spec. heat of Water [kJ/kgK] at 20 °C +RHOWAT = 998.0 ! density of Water [kg/m³] at20 °C +LAMWAT = 0.58 ! heat conductivity W/(mK) +CPWAT_SI = CPWAT*1000 ! J/(kgK) +CPBRI_SI = CPBRI*1000 ! J/(kgK) + +******************************* +**END Head.dck +******************************* diff --git a/tests/trnsysGUI/data/diagramWithTapForRegimes/diagramWithTapForRegimes.json b/tests/trnsysGUI/data/diagramWithTapForRegimes/diagramWithTapForRegimes.json new file mode 100644 index 00000000..4e2860e3 --- /dev/null +++ b/tests/trnsysGUI/data/diagramWithTapForRegimes/diagramWithTapForRegimes.json @@ -0,0 +1,161 @@ +{ + "Blocks": { + ".__BlockDct__": true, + "Block-1": { + ".__BlockDict__": true, + "BlockDisplayName": "WtSp1", + "BlockName": "WTap_main", + "Id": 1, + "__version__": "bbc03f36-d1a1-4d97-a9c0-d212ea3a0203", + "blockPosition": [ + -85.0, + -303.0 + ], + "flippedH": false, + "flippedV": false, + "portsIdsIn": [], + "portsIdsOut": [ + 2 + ], + "rotationN": 0, + "trnsysId": 1 + }, + "Block-3": { + ".__BlockDict__": true, + "BlockDisplayName": "WtTp3", + "BlockName": "WTap", + "Id": 3, + "__version__": "bbc03f36-d1a1-4d97-a9c0-d212ea3a0203", + "blockPosition": [ + -86.0, + -375.0 + ], + "flippedH": false, + "flippedV": false, + "portsIdsIn": [ + 4 + ], + "portsIdsOut": [], + "rotationN": 0, + "trnsysId": 2 + }, + "Block-5": { + ".__BlockDict__": true, + "BlockDisplayName": "Pump5", + "BlockName": "Pump", + "Id": 5, + "__version__": "9552365f-ef11-4fac-ba35-644e94b54088", + "blockPosition": [ + -166.0, + -302.0 + ], + "flippedH": false, + "flippedV": false, + "massFlowRateInKgPerH": 500, + "portsIdsIn": [ + 6 + ], + "portsIdsOut": [ + 7 + ], + "rotationN": -1, + "trnsysId": 3 + }, + "Connection-8": { + ".__ConnectionDict__": true, + "__version__": "74032e79-2abc-4fcf-9328-5d697ef31023", + "connectionId": 1, + "diameterInCm": { + "name": "loop1Dia" + }, + "fromPortId": 2, + "id": 8, + "labelPos": [ + -88.0, + -286.0 + ], + "lengthInM": { + "name": "loop1Len" + }, + "massFlowLabelPos": [ + -88.0, + -286.0 + ], + "name": "WtSp1_Pump5", + "segmentsCorners": [ + [ + -147.0, + -283.0 + ], + [ + -147.0, + -302.0 + ] + ], + "shallBeSimulated": true, + "toPortId": 6, + "trnsysId": 4, + "uValueInWPerM2K": { + "name": "loop1UVal" + } + }, + "Connection-9": { + ".__ConnectionDict__": true, + "__version__": "74032e79-2abc-4fcf-9328-5d697ef31023", + "connectionId": 2, + "diameterInCm": { + "name": "loop1Dia" + }, + "fromPortId": 7, + "id": 9, + "labelPos": [ + -149.0, + -339.0 + ], + "lengthInM": { + "name": "loop1Len" + }, + "massFlowLabelPos": [ + -149.0, + -339.0 + ], + "name": "Pump5_WtTp3", + "segmentsCorners": [ + [ + -146.0, + -355.0 + ] + ], + "shallBeSimulated": true, + "toPortId": 4, + "trnsysId": 5, + "uValueInWPerM2K": { + "name": "loop1UVal" + } + }, + "IDs": { + "GlobalId": 10, + "__idDct__": true, + "globalConnID": 3, + "trnsysID": 6 + }, + "Strings": { + "DiagramName": "diagramWithTapForRegimes.json", + "ProjectFolder": "C:\\Users\\alex.hobe\\Projects\\pytrnsys_gui\\tests\\trnsysGUI\\data\\diagramWithTapForRegimes", + "__nameDct__": true + } + }, + "hydraulicLoops": [ + { + "__version__": "990b8023-eb4b-408e-8d54-23caa5916b2a", + "connectionsTrnsysId": [ + 4, + 5 + ], + "fluidName": "water", + "hasUserDefinedName": false, + "name": "loop1", + "useLoopWideDefaults": true + } + ] +} \ No newline at end of file diff --git a/tests/trnsysGUI/data/diagramWithTapForRegimes/expectedPDFs/diagramWithTapForRegimes_dummy_regime.pdf b/tests/trnsysGUI/data/diagramWithTapForRegimes/expectedPDFs/diagramWithTapForRegimes_dummy_regime.pdf new file mode 100644 index 0000000000000000000000000000000000000000..dc98b4b40cfd13a70ab180f5818f1413a5f7867d GIT binary patch literal 8899 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

    x<`VbWEXC+U$r>gv|DZQ%w0k9R-VsR{ zK--R=MJc|5SvT{*gb~-TrpDySciw)mb0ga`87srY;VyaC80burn%Z+hJfGdCR9$hA zq@m{cv~6dL9bEL;# zt;M|VOzGBkeHwO|Qqp^mYW1zWaeds77S(#nLF%Hft+%M70c_VJa=ecgJ0)9>eD@7hQK-JQ(n)$JqILfAqU*nsI`F7Bv1WaxpqJ zemLHtIQ_;|(`=8gCXH1cp&U7ZHNEnRVevGqhKa0A$%)W+K6SUN>s_8@spk-)K+8s- z4YiMNXnZSbVihBgQ0aX0%4VTbvaX{ka=?n()Qjd9-i;)U3+V#ZbvYYK(cn)z%N~+2FfZDwrsZ?1s?kX!eE$4r?t0I|H1B2ixX;yTB2nBW$Ne>Sv~w6@0L4w zLdSPmfwxH+-m*idLgSb?H;yjnlcDub#-)<3`B1*!MjH}^Zur;^pQAriL&xTY`MSy8 zeRM94JysqTd7!7scE&pY8_cJ?rndT$K%JGHvst)ev1s-=F6Z`|baCemjagQ>Pe=M< zf}3}{+wW<^%14OoZJ9xH7yr?{(Ie+8YRA#ADBQcCh>^V_H}kkNsC#d1Z{Byo-cqGr zCp2W(aj9al-U{cG?p_0pA6Izgez-tw)~Zo^Z`i}}F}3HU0S3JDklfK8+gNd2WRgYf z_@T}`99Q73sOmocsCS{b+ciSn^Wd$36Llie z1+ePfncbuJPIG67$kzJBnvS0{a4;9E_a4@)xG;m=ODM1DRi%3tP(#T=o9A*pMD3ce zoM>{|SDIEm3EwEUrH+@;B`wVvI zPMj)Fq<0Cg?Ct2uEOnjhw#lF8G*gaY7he6b zXD|Zvi_hbN*W^>P`up#XyJ-g#W!@01o24|2(NO~`br$5V8C9yr;}`98AXGA)eMaA% z7}2gTG`Sw4Fc?T|$-7*0s4u2k&{wo17S#+0*m&P2!zYE`BTd}-5w+d+TM5soTcehj ziZG#mYmIOLA;MInG1<_gUPMao5>CA6eJa_0SvsmoleaW(Nd2DPW%gl#@#KIKUaHB# z%;zS+R)L#!0V}|l#Z)cZ*Um4zU2Lk5+P!E`XVl-WuQGfDHEW``+IM;HQEHPKourOK=DB%Am*3vL*Xv!!Mzy8jv zj8a}p!zizjSs8;~Lqnr6Yvcof{u=qPC=dewzAnJJW*lJBUuYDvBf%9w#4U Date: Wed, 5 Jul 2023 15:37:53 +0200 Subject: [PATCH 30/56] Final refactoring of tests before review --- .../testPrintRegimesAndCopyFiles.py | 122 +++++++++++------- 1 file changed, 74 insertions(+), 48 deletions(-) diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py index fe322879..7688fb9e 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py @@ -26,13 +26,16 @@ class PathFinder: expectedFolderName: str resultsFolderName: str resultsFolderName2: _tp.Optional[str] + fileEnding: str = _dc.field(init=False) + pdfName: str = _dc.field(init=False) + svgName: str = _dc.field(init=False) @property def dataDir(self): return _pl.Path(_GUI.__file__).parent / self.baseFolderRelativePath / self.projectName @property - def expectedPdfsDir(self): + def expectedFilesDir(self): return self.dataDir / self.expectedFolderName @property @@ -43,19 +46,55 @@ def resultsDir(self): def resultsDir2(self): return self.dataDir / self.resultsFolderName2 + def setFileEnding(self, fileEnding): + self.fileEnding = fileEnding + self._setPdfName() + self._setSvgName() + + def _setPdfName(self): + self.pdfName = self.projectName + self.fileEnding + ".pdf" + + def _setSvgName(self): + self.svgName = self.projectName + self.fileEnding + ".svg" + + @property + def expectedPdfPath(self): + return self.expectedFilesDir / self.pdfName + + @property + def newPdfPath(self): + return self.dataDir / self.resultsDir / self.pdfName + + @property + def alternatePdfPath(self): + return self.dataDir / self.resultsDir2 / self.pdfName + + @property + def expectedSvgPath(self): + return self.expectedFilesDir / self.svgName + + @property + def newSvgPath(self): + return self.dataDir / self.resultsDir / self.svgName + + @property + def alternateSvgPath(self): + return self.dataDir / self.resultsDir2 / self.svgName + pathFinder = PathFinder(_PROJECT_NAME, baseFolderRelativePath, expectedFolderName, resultsDirName, resultsDirName2) _DATA_DIR = pathFinder.dataDir -_EXPECTED_PDFS_DIR = pathFinder.expectedPdfsDir +# _EXPECTED_PDFS_DIR = pathFinder.expectedFilesDir _RESULTS_DIR = pathFinder.resultsDir _RESULTS_DIR_2 = pathFinder.resultsDir2 -_DIAGRAM_ENDING = "_diagram.pdf" -_NAME1_ENDING = "_name1.pdf" -_NAME2_ENDING = "_name2.pdf" -_NAME1_SVG_ENDING = "_name1.svg" + +# _DIAGRAM_ENDING = "_diagram.pdf" +# _NAME1_ENDING = "_name1.pdf" +# _NAME2_ENDING = "_name2.pdf" +# _NAME1_SVG_ENDING = "_name1.svg" def _ensureDirExists(dirPath): @@ -67,38 +106,30 @@ def _ensureDirExists(dirPath): _ensureDirExists(_RESULTS_DIR_2) -def _getExpectedAndNewFilePaths(ending, resultsDir, dataDir, projectName, expectedPdfsDir): - pdfName = projectName + ending - expectedPdfPath = expectedPdfsDir / pdfName - newPdfPath = dataDir / resultsDir / pdfName - return expectedPdfPath, newPdfPath - - -_EXPECTED_DIAGRAM_PATH, _NEW_DIAGRAM_PATH = _getExpectedAndNewFilePaths( - _DIAGRAM_ENDING, _RESULTS_DIR, _DATA_DIR, _PROJECT_NAME, _EXPECTED_PDFS_DIR -) -_EXPECTED_NAME1_PATH, _NEW_NAME1_PATH = _getExpectedAndNewFilePaths( - _NAME1_ENDING, _RESULTS_DIR, _DATA_DIR, _PROJECT_NAME, _EXPECTED_PDFS_DIR -) -_EXPECTED_NAME2_PATH, _NEW_NAME2_PATH = _getExpectedAndNewFilePaths( - _NAME2_ENDING, _RESULTS_DIR, _DATA_DIR, _PROJECT_NAME, _EXPECTED_PDFS_DIR -) -_EXPECTED_NAME1_SVG_PATH, _NEW_NAME1_SVG_PATH = _getExpectedAndNewFilePaths( - _NAME1_SVG_ENDING, _RESULTS_DIR, _DATA_DIR, _PROJECT_NAME, _EXPECTED_PDFS_DIR -) - -_, _NEW_DIAGRAM_PATH_2 = _getExpectedAndNewFilePaths( - _DIAGRAM_ENDING, _RESULTS_DIR_2, _DATA_DIR, _PROJECT_NAME, _EXPECTED_PDFS_DIR -) -_, _NEW_NAME1_PATH_2 = _getExpectedAndNewFilePaths( - _NAME1_ENDING, _RESULTS_DIR_2, _DATA_DIR, _PROJECT_NAME, _EXPECTED_PDFS_DIR -) -_, _NEW_NAME2_PATH_2 = _getExpectedAndNewFilePaths( - _NAME2_ENDING, _RESULTS_DIR_2, _DATA_DIR, _PROJECT_NAME, _EXPECTED_PDFS_DIR -) -_, _NEW_NAME1_SVG_PATH_2 = _getExpectedAndNewFilePaths( - _NAME1_SVG_ENDING, _RESULTS_DIR_2, _DATA_DIR, _PROJECT_NAME, _EXPECTED_PDFS_DIR -) +# def _getExpectedAndNewFilePaths(ending, resultsDir, dataDir, projectName, expectedPdfsDir): +# pdfName = projectName + ending +# expectedPdfPath = expectedPdfsDir / pdfName +# newPdfPath = dataDir / resultsDir / pdfName +# return expectedPdfPath, newPdfPath + + +pathFinder.setFileEnding("_diagram") +_EXPECTED_DIAGRAM_PATH = pathFinder.expectedPdfPath +_NEW_DIAGRAM_PATH = pathFinder.newPdfPath +_NEW_DIAGRAM_PATH_2 = pathFinder.alternatePdfPath + +pathFinder.setFileEnding("_name1") +_EXPECTED_NAME1_PATH = pathFinder.expectedPdfPath +_NEW_NAME1_PATH = pathFinder.newPdfPath +_NEW_NAME1_PATH_2 = pathFinder.alternatePdfPath +_EXPECTED_NAME1_SVG_PATH = pathFinder.expectedSvgPath +_NEW_NAME1_SVG_PATH = pathFinder.newSvgPath +_NEW_NAME1_SVG_PATH_2 = pathFinder.alternateSvgPath + +pathFinder.setFileEnding("_name2") +_EXPECTED_NAME2_PATH = pathFinder.expectedPdfPath +_NEW_NAME2_PATH = pathFinder.newPdfPath +_NEW_NAME2_PATH_2 = pathFinder.alternatePdfPath def _createMainWindow(projectFolder, projectName, qtbot): @@ -151,31 +182,26 @@ def testUsingQtBotForRegimeWithTap(self, qtbot): pumpTapPairs = {"Pump5": "WtSp1"} onlyTheseRegimes = ["dummy_regime"] projectName = "diagramWithTapForRegimes" + regimeEnding = "_dummy_regime" pathFinder2 = PathFinder( projectName, baseFolderRelativePath, expectedFolderName, resultsDirName, resultsDirName2 ) dataDir = pathFinder2.dataDir - expectedPdfsDir = pathFinder2.expectedPdfsDir resultsDir = pathFinder2.resultsDir _ensureDirExists(resultsDir) - _, newDiagramPath = _getExpectedAndNewFilePaths( - _DIAGRAM_ENDING, resultsDir, dataDir, projectName, expectedPdfsDir - ) - regimeEnding = "_dummy_regime.pdf" - expectedFilePath, newFilePath = _getExpectedAndNewFilePaths( - regimeEnding, resultsDir, dataDir, projectName, expectedPdfsDir - ) + pathFinder2.setFileEnding(regimeEnding) mainWindow = _createMainWindow(dataDir, projectName, qtbot) regimeExporter = _rdopfp.RegimeExporter(projectName, dataDir, resultsDir, _REGIMES_FILENAME, mainWindow) regimeExporter.export(pumpTapPairs=pumpTapPairs, onlyTheseRegimes=onlyTheseRegimes) - self._fileExistsAndIsCorrect(newFilePath, expectedFilePath) + self._fileExistsAndIsCorrect(pathFinder2.newPdfPath, pathFinder2.expectedPdfPath) - assert not newDiagramPath.is_file() + pathFinder2.setFileEnding("_diagram") + assert not pathFinder2.newPdfPath.is_file() # non-qtbot solution? From a996c9bb4fcff40f4d5d34f75481d748e1dff47b Mon Sep 17 00:00:00 2001 From: ahobeost Date: Wed, 5 Jul 2023 15:46:43 +0200 Subject: [PATCH 31/56] CI adjustments --- .../testPrintRegimesAndCopyFiles.py | 32 ++++++------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py index 7688fb9e..038ec871 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py @@ -1,8 +1,8 @@ import dataclasses as _dc import os as _os -import matplotlib.testing.compare as _mpltc # type: ignore[import] import pathlib as _pl import typing as _tp +import matplotlib.testing.compare as _mpltc # type: ignore[import] import pytrnsys.utils.log as _ulog @@ -12,15 +12,15 @@ import trnsysGUI.pythonInterface.regimeExporter.renderDiagramOnPDFfromPython as _rdopfp _PROJECT_NAME = "diagramForRegimes" -baseFolderRelativePath = "..\\tests\\trnsysGUI\\data\\" -expectedFolderName = "expectedPDFs" -resultsDirName = "results" -resultsDirName2 = "resultsReducedUsage" +_BASE_FOLDER_FILE_PATH = "..\\tests\\trnsysGUI\\data\\" +_EXPECTED_FILES_PATH = "expectedPDFs" +_RESULTS_DIR_NAME = "results" +_RESULTS_DIR_NAME_2 = "resultsReducedUsage" _REGIMES_FILENAME = "regimes.csv" @_dc.dataclass -class PathFinder: +class PathFinder: # pylint: disable=too-many-instance-attributes projectName: str baseFolderRelativePath: str expectedFolderName: str @@ -82,21 +82,16 @@ def alternateSvgPath(self): return self.dataDir / self.resultsDir2 / self.svgName -pathFinder = PathFinder(_PROJECT_NAME, baseFolderRelativePath, expectedFolderName, resultsDirName, resultsDirName2) +pathFinder = PathFinder( + _PROJECT_NAME, _BASE_FOLDER_FILE_PATH, _EXPECTED_FILES_PATH, _RESULTS_DIR_NAME, _RESULTS_DIR_NAME_2 +) _DATA_DIR = pathFinder.dataDir -# _EXPECTED_PDFS_DIR = pathFinder.expectedFilesDir _RESULTS_DIR = pathFinder.resultsDir _RESULTS_DIR_2 = pathFinder.resultsDir2 -# _DIAGRAM_ENDING = "_diagram.pdf" -# _NAME1_ENDING = "_name1.pdf" -# _NAME2_ENDING = "_name2.pdf" -# _NAME1_SVG_ENDING = "_name1.svg" - - def _ensureDirExists(dirPath): if not _os.path.isdir(dirPath): _os.makedirs(dirPath) @@ -106,13 +101,6 @@ def _ensureDirExists(dirPath): _ensureDirExists(_RESULTS_DIR_2) -# def _getExpectedAndNewFilePaths(ending, resultsDir, dataDir, projectName, expectedPdfsDir): -# pdfName = projectName + ending -# expectedPdfPath = expectedPdfsDir / pdfName -# newPdfPath = dataDir / resultsDir / pdfName -# return expectedPdfPath, newPdfPath - - pathFinder.setFileEnding("_diagram") _EXPECTED_DIAGRAM_PATH = pathFinder.expectedPdfPath _NEW_DIAGRAM_PATH = pathFinder.newPdfPath @@ -185,7 +173,7 @@ def testUsingQtBotForRegimeWithTap(self, qtbot): regimeEnding = "_dummy_regime" pathFinder2 = PathFinder( - projectName, baseFolderRelativePath, expectedFolderName, resultsDirName, resultsDirName2 + projectName, _BASE_FOLDER_FILE_PATH, _EXPECTED_FILES_PATH, _RESULTS_DIR_NAME, _RESULTS_DIR_NAME_2 ) dataDir = pathFinder2.dataDir resultsDir = pathFinder2.resultsDir From 513763708b5438a1aeff11c08270775ea8e57fd8 Mon Sep 17 00:00:00 2001 From: ahobeost Date: Wed, 5 Jul 2023 16:15:50 +0200 Subject: [PATCH 32/56] Cleaned up PV.svg as it was completely pixelated --- trnsysGUI/images/PV.svg | 1001 +++++++++------------------------------ 1 file changed, 216 insertions(+), 785 deletions(-) diff --git a/trnsysGUI/images/PV.svg b/trnsysGUI/images/PV.svg index 17f1ae2a..418f2b5f 100644 --- a/trnsysGUI/images/PV.svg +++ b/trnsysGUI/images/PV.svg @@ -1,790 +1,221 @@ - + - - - - - - - - -]> - - From 7a492f53d919b8615bc998045b6d0a7612ffe369 Mon Sep 17 00:00:00 2001 From: ahobeost Date: Thu, 6 Jul 2023 12:48:15 +0200 Subject: [PATCH 33/56] Using the pump model to get the required values from the json --- .../expectedCSVs/expectedRegimeTemplate.csv | 2 +- .../pythonInterface/regimeExporter/exportRegimes.py | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/trnsysGUI/data/diagramForRegimes/expectedCSVs/expectedRegimeTemplate.csv b/tests/trnsysGUI/data/diagramForRegimes/expectedCSVs/expectedRegimeTemplate.csv index 569d29af..716700c2 100644 --- a/tests/trnsysGUI/data/diagramForRegimes/expectedCSVs/expectedRegimeTemplate.csv +++ b/tests/trnsysGUI/data/diagramForRegimes/expectedCSVs/expectedRegimeTemplate.csv @@ -1,2 +1,2 @@ regimeName,pump1,pump2,pump3,valve1,valve2 -dummy regime,500.0,0.0,500.0,0.0,0.0 +dummy_regime,500,0,500,0.0,0.0 diff --git a/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py b/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py index 6eee0269..e386bf40 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py +++ b/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py @@ -2,6 +2,8 @@ import pandas as _pd +import trnsysGUI.pump as _pu + def exportRegimeTemplate(projectJson, regimeFileName): pumpsAndValvesAndValues = getPumpsAndValvesWithValuesFromJson(projectJson) @@ -20,20 +22,20 @@ def getPumpsAndValvesWithValuesFromJson(projectJson): if "BlockName" in curDict: curBlockName = curDict["BlockName"] if curBlockName == "Pump": - desiredValueName = "massFlowRateInKgPerH" - data = getData(curDict, data, desiredValueName) + curPump = _pu.PumpModel.from_dict(curDict) + data[curPump.BlockDisplayName] = curPump.massFlowRateInKgPerH elif curBlockName == "TVentil": desiredValueName = "PositionForMassFlowSolver" data = getData(curDict, data, desiredValueName) - pumpsAndValvesAndValues = _pd.DataFrame(data, index=["dummy regime"]) + pumpsAndValvesAndValues = _pd.DataFrame(data, index=["dummy_regime"]) pumpsAndValvesAndValues.index.name = "regimeName" return pumpsAndValvesAndValues def getData(curDict, data, desiredValueName): - label = curDict["BlockDisplayName"] + bockItemName = curDict["BlockDisplayName"] value = float(curDict[desiredValueName]) - data[label] = value + data[bockItemName] = value return data From 17dc72a276c0a9b0566b6e1d46de46172279e2e0 Mon Sep 17 00:00:00 2001 From: ahobeost Date: Thu, 6 Jul 2023 13:05:01 +0200 Subject: [PATCH 34/56] Ajusted fileNames to use properties instead in the regimeExporter. Added initial typing for the interface --- .../testPrintRegimesAndCopyFiles.py | 20 +++++----- .../renderDiagramOnPDFfromPython.py | 37 ++++++++++--------- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py index 038ec871..438259b6 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py @@ -31,20 +31,20 @@ class PathFinder: # pylint: disable=too-many-instance-attributes svgName: str = _dc.field(init=False) @property - def dataDir(self): + def projectDir(self): return _pl.Path(_GUI.__file__).parent / self.baseFolderRelativePath / self.projectName @property def expectedFilesDir(self): - return self.dataDir / self.expectedFolderName + return self.projectDir / self.expectedFolderName @property def resultsDir(self): - return self.dataDir / self.resultsFolderName + return self.projectDir / self.resultsFolderName @property def resultsDir2(self): - return self.dataDir / self.resultsFolderName2 + return self.projectDir / self.resultsFolderName2 def setFileEnding(self, fileEnding): self.fileEnding = fileEnding @@ -63,11 +63,11 @@ def expectedPdfPath(self): @property def newPdfPath(self): - return self.dataDir / self.resultsDir / self.pdfName + return self.projectDir / self.resultsDir / self.pdfName @property def alternatePdfPath(self): - return self.dataDir / self.resultsDir2 / self.pdfName + return self.projectDir / self.resultsDir2 / self.pdfName @property def expectedSvgPath(self): @@ -75,11 +75,11 @@ def expectedSvgPath(self): @property def newSvgPath(self): - return self.dataDir / self.resultsDir / self.svgName + return self.projectDir / self.resultsDir / self.svgName @property def alternateSvgPath(self): - return self.dataDir / self.resultsDir2 / self.svgName + return self.projectDir / self.resultsDir2 / self.svgName pathFinder = PathFinder( @@ -87,7 +87,7 @@ def alternateSvgPath(self): ) -_DATA_DIR = pathFinder.dataDir +_DATA_DIR = pathFinder.projectDir _RESULTS_DIR = pathFinder.resultsDir _RESULTS_DIR_2 = pathFinder.resultsDir2 @@ -175,7 +175,7 @@ def testUsingQtBotForRegimeWithTap(self, qtbot): pathFinder2 = PathFinder( projectName, _BASE_FOLDER_FILE_PATH, _EXPECTED_FILES_PATH, _RESULTS_DIR_NAME, _RESULTS_DIR_NAME_2 ) - dataDir = pathFinder2.dataDir + dataDir = pathFinder2.projectDir resultsDir = pathFinder2.resultsDir _ensureDirExists(resultsDir) diff --git a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py index 168401eb..09571553 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py +++ b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py @@ -21,36 +21,37 @@ @_dc.dataclass class RegimeExporter: projectName: str - dataDir: _pl.Path + projectDir: _pl.Path resultsDir: _pl.Path regimesFileName: str mainWindow: _mw.MainWindow # type: ignore[name-defined] - def __post_init__(self) -> None: # /NOSONAR - self.massFlowRatesPrintFilePath, self.temperaturesPrintFilePath = self._getPrtFilePaths() - - def _getPrtFilePaths(self): + @property + def massFlowRatesPrintFilePath(self): massFlowRatesPrintFileName = f"{self.projectName}_Mfr.prt" - temperaturesPintFileName = f"{self.projectName}_T.prt" - massFlowRatesPrintFilePath = self.dataDir / massFlowRatesPrintFileName - temperaturesPrintFilePath = self.dataDir / temperaturesPintFileName + return self.projectDir / massFlowRatesPrintFileName - return massFlowRatesPrintFilePath, temperaturesPrintFilePath + @property + def temperaturesPrintFilePath(self): + temperaturesPintFileName = f"{self.projectName}_T.prt" + return self.projectDir / temperaturesPintFileName - def export(self, pumpTapPairs=None, onlyTheseRegimes=None) -> None: + def export( + self, pumpTapPairs: _tp.Optional[_tp.Dict] = None, onlyTheseRegimes: _tp.Optional[_tp.Sequence[str]] = None + ) -> None: if not onlyTheseRegimes: self._makeDiagramFiles() - regimeValues = _gdr.getRegimes(self.dataDir / self.regimesFileName, onlyTheseRegimes) + regimeValues = _gdr.getRegimes(self.projectDir / self.regimesFileName, onlyTheseRegimes) pumpsAndValvesNames = list(regimeValues.columns) pumpsAndValves, mainTaps = self.getPumpsAndValvesAndMainTaps(pumpsAndValvesNames) self._simulateAndVisualizeMassFlows(mainTaps, pumpTapPairs, pumpsAndValves, regimeValues) def _makeDiagramFiles(self, regimeName="diagram") -> None: - pdfName = str(self.resultsDir) + "\\" + self.projectName + "_" + regimeName + ".pdf" - svgName = str(self.resultsDir) + "\\" + self.projectName + "_" + regimeName + ".svg" + pdfName = self.resultsDir / f"{self.projectName}_{regimeName}.pdf" + svgName = self.resultsDir / f"{self.projectName}_{regimeName}.svg" self._printDiagramToPDF(pdfName) self._printDiagramToSVG(svgName) @@ -107,25 +108,25 @@ def _adjustPumpsAndValves(pumpsAndValves, regimeRow, pumpTapPairs, mainTaps) -> elif isinstance(blockItem, _tv.TVentil): blockItem.positionForMassFlowSolver = desiredValue else: - raise TypeError(f"Encountered blockItem of type {blockItem}, instead of a pump or a Valve") + raise AssertionError(f"Encountered blockItem of type {blockItem}, instead of a pump or a Valve") - def _printDiagramToPDF(self, fileName: str) -> None: + def _printDiagramToPDF(self, fileName: _pl.Path) -> None: if fileName != "": printer = _qtp.QPrinter(_qtp.QPrinter.HighResolution) printer.setOrientation(_qtp.QPrinter.Landscape) printer.setOutputFormat(_qtp.QPrinter.PdfFormat) - printer.setOutputFileName(fileName) + printer.setOutputFileName(str(fileName)) painter = _qtg.QPainter(printer) self.mainWindow.editor.diagramScene.render(painter) painter.end() - def _printDiagramToSVG(self, fileName: str) -> None: + def _printDiagramToSVG(self, fileName: _pl.Path) -> None: # upside down and tiny compared to canvas if fileName != "": generator = _qtsvg.QSvgGenerator() generator.setSize(_qtc.QSize(1600, 1600)) generator.setViewBox(_qtc.QRect(0, 0, 1600, 1600)) - generator.setFileName(fileName) + generator.setFileName(str(fileName)) painter = _qtg.QPainter(generator) self.mainWindow.editor.diagramScene.render(painter) painter.end() From 1935781c338e4014fa0de4ef6e47a9c7ecae8477 Mon Sep 17 00:00:00 2001 From: ahobeost Date: Wed, 26 Jun 2024 13:20:33 +0200 Subject: [PATCH 35/56] Improved f-string based on review --- trnsysGUI/WTap_main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trnsysGUI/WTap_main.py b/trnsysGUI/WTap_main.py index e1e2f142..163eaf70 100644 --- a/trnsysGUI/WTap_main.py +++ b/trnsysGUI/WTap_main.py @@ -65,7 +65,7 @@ def changeSize(self): return w, h def exportMassFlows(self): - resStr = "Mfr" + self.displayName + f" = {self.massFlowRateInKgPerH}" + "\n" + resStr = f"Mfr{self.displayName} = {self.massFlowRateInKgPerH}\n" equationNr = 1 return resStr, equationNr From f0887c26a1b7efe485e88941eeed496b94bc1a69 Mon Sep 17 00:00:00 2001 From: ahobeost Date: Wed, 26 Jun 2024 13:35:12 +0200 Subject: [PATCH 36/56] Fixed broken tests. --- .github/workflows/build-windows.yml | 2 +- .../regimeExporter/testExportRegimeTemplate.py | 7 ++++--- trnsysGUI/MassFlowVisualizer.py | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 6bff0bef..5a48ceb7 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -12,7 +12,7 @@ on: jobs: test: - runs-on: [self-hosted, etzel] + runs-on: [self-hosted, etna] steps: - uses: actions/checkout@v3 - name: Add Inkscape to the path diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py index 4eaf3067..42c05374 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py @@ -1,3 +1,4 @@ +import pandas as _pd import pathlib as _pl import trnsysGUI as _GUI @@ -16,7 +17,7 @@ def testExportTemplate(self): _er.exportRegimeTemplate(projectJson, regimeFileName) - expectedContent = _pl.Path(expectedFileName).read_text(encoding="utf-8") - actualContent = _pl.Path(regimeFileName).read_text(encoding="utf-8") + expectedContent = _pd.read_csv(expectedFileName) + actualContent = _pd.read_csv(regimeFileName) - assert actualContent == expectedContent + _pd.testing.assert_frame_equal(expectedContent, actualContent, check_dtype=False) diff --git a/trnsysGUI/MassFlowVisualizer.py b/trnsysGUI/MassFlowVisualizer.py index 2ed59f2a..222f45c3 100644 --- a/trnsysGUI/MassFlowVisualizer.py +++ b/trnsysGUI/MassFlowVisualizer.py @@ -351,7 +351,7 @@ def checkTimeStep(self): def checkTempTimeStep(self): tempMassFlowDataDup = self.tempMassFlowData tempMassFlowDataDup = tempMassFlowDataDup.drop(tempMassFlowDataDup.index[0]) - for items in tempMassFlowDataDup.nunique().iteritems(): + for items in tempMassFlowDataDup.nunique().items(): if items[0] != "TIME": if items[1] > 1: return False From 7ace51ac994441f31f03ce04ab8b25eb211a87eb Mon Sep 17 00:00:00 2001 From: ahobeost Date: Wed, 26 Jun 2024 14:01:03 +0200 Subject: [PATCH 37/56] Added inkscape path to CI steps. --- .github/workflows/run-tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 9f7ac678..1aaaae31 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -63,6 +63,8 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Add Inkscape to the path + run: echo "C:\CI-Progams\Inkscape\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - name: Remove old venv run: | From 90ce6a5d70d6bd660bcc4568df3368e51e81fe22 Mon Sep 17 00:00:00 2001 From: ahobeost Date: Wed, 26 Jun 2024 14:13:10 +0200 Subject: [PATCH 38/56] Fixed test by finding pump scripts. --- trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py b/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py index e386bf40..65dc5cdd 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py +++ b/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py @@ -2,7 +2,7 @@ import pandas as _pd -import trnsysGUI.pump as _pu +import trnsysGUI.pumpsAndTaps._serialization as _pu def exportRegimeTemplate(projectJson, regimeFileName): @@ -22,7 +22,7 @@ def getPumpsAndValvesWithValuesFromJson(projectJson): if "BlockName" in curDict: curBlockName = curDict["BlockName"] if curBlockName == "Pump": - curPump = _pu.PumpModel.from_dict(curDict) + curPump = _pu._PumpModelVersion1.from_dict(curDict) data[curPump.BlockDisplayName] = curPump.massFlowRateInKgPerH elif curBlockName == "TVentil": desiredValueName = "PositionForMassFlowSolver" From eb6cc8504f02c5819939ef3f6886ec1c72f1e442 Mon Sep 17 00:00:00 2001 From: ahobeost Date: Wed, 26 Jun 2024 14:35:16 +0200 Subject: [PATCH 39/56] Adjusted locations of files. --- .../regimeExporter/renderDiagramOnPDFfromPython.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py index 09571553..77adc887 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py +++ b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py @@ -12,10 +12,10 @@ import trnsysGUI.diagram.Editor as _de import trnsysGUI.MassFlowVisualizer as _mfv import trnsysGUI.mainWindow as _mw -import trnsysGUI.pump as _pump +import trnsysGUI.pumpsAndTaps.pump as _pump import trnsysGUI.pythonInterface.regimeExporter.getDesiredRegimes as _gdr import trnsysGUI.TVentil as _tv -import trnsysGUI.WTap_main as _wtm +import trnsysGUI.pumpsAndTaps.tapMains as _tm @_dc.dataclass @@ -63,7 +63,7 @@ def getPumpsAndValvesAndMainTaps(self, pumpsAndValvesNames): if isinstance(blockItem, (_pump.Pump, _tv.TVentil)): if blockItem.displayName in pumpsAndValvesNames: pumpsAndValves.append(blockItem) - elif isinstance(blockItem, _wtm.WTap_main): + elif isinstance(blockItem, _tm.TapMains): mainTaps[blockItem.displayName] = blockItem return pumpsAndValves, mainTaps From 0e2cabd8c055876d72c34888fa514f503b7c97e2 Mon Sep 17 00:00:00 2001 From: ahobeost Date: Wed, 26 Jun 2024 14:35:48 +0200 Subject: [PATCH 40/56] Slight refactoring of test to get all errors at once. --- .../testPrintRegimesAndCopyFiles.py | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py index 438259b6..c61283d3 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py @@ -1,8 +1,9 @@ import dataclasses as _dc +import matplotlib.testing.compare as _mpltc # type: ignore[import] import os as _os import pathlib as _pl +import pytest as _pt import typing as _tp -import matplotlib.testing.compare as _mpltc # type: ignore[import] import pytrnsys.utils.log as _ulog @@ -86,7 +87,6 @@ def alternateSvgPath(self): _PROJECT_NAME, _BASE_FOLDER_FILE_PATH, _EXPECTED_FILES_PATH, _RESULTS_DIR_NAME, _RESULTS_DIR_NAME_2 ) - _DATA_DIR = pathFinder.projectDir _RESULTS_DIR = pathFinder.resultsDir _RESULTS_DIR_2 = pathFinder.resultsDir2 @@ -100,7 +100,6 @@ def _ensureDirExists(dirPath): _ensureDirExists(_RESULTS_DIR) _ensureDirExists(_RESULTS_DIR_2) - pathFinder.setFileEnding("_diagram") _EXPECTED_DIAGRAM_PATH = pathFinder.expectedPdfPath _NEW_DIAGRAM_PATH = pathFinder.newPdfPath @@ -145,10 +144,19 @@ def testUsingQtBot(self, qtbot): regimeExporter = _rdopfp.RegimeExporter(_PROJECT_NAME, _DATA_DIR, _RESULTS_DIR, _REGIMES_FILENAME, mainWindow) regimeExporter.export() - self._fileExistsAndIsCorrect(_NEW_DIAGRAM_PATH, _EXPECTED_DIAGRAM_PATH) - self._fileExistsAndIsCorrect(_NEW_NAME1_PATH, _EXPECTED_NAME1_PATH) - self._fileExistsAndIsCorrect(_NEW_NAME1_SVG_PATH, _EXPECTED_NAME1_SVG_PATH) - self._fileExistsAndIsCorrect(_NEW_NAME2_PATH, _EXPECTED_NAME2_PATH) + files_to_compare = {'new_file': [_NEW_DIAGRAM_PATH, _NEW_NAME1_PATH, _NEW_NAME1_SVG_PATH, _NEW_NAME2_PATH], + 'expected_file': [_EXPECTED_DIAGRAM_PATH, _EXPECTED_NAME1_PATH, _EXPECTED_NAME1_SVG_PATH, + _EXPECTED_NAME2_PATH]} + + errors = [] + for i, new_file in enumerate(files_to_compare['new_file']): + try: + self._fileExistsAndIsCorrect(new_file, files_to_compare['expected_file'][i]) + except AssertionError as current_error: + errors.append(current_error) + + if errors: + raise Exception(errors) @staticmethod def _fileExistsAndIsCorrect(producedFile, expectedFile): @@ -191,5 +199,4 @@ def testUsingQtBotForRegimeWithTap(self, qtbot): pathFinder2.setFileEnding("_diagram") assert not pathFinder2.newPdfPath.is_file() - # non-qtbot solution? From 71d188841b1bd8cd1e28ddfac2f4f92ea23b3c1a Mon Sep 17 00:00:00 2001 From: ahobeost Date: Wed, 26 Jun 2024 16:24:29 +0200 Subject: [PATCH 41/56] Fixed testUsingQtBotForGivenRegimes. --- .../expectedPDFs/diagramForRegimes_name1.pdf | Bin 33078 -> 27282 bytes .../testPrintRegimesAndCopyFiles.py | 24 ++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/tests/trnsysGUI/data/diagramForRegimes/expectedPDFs/diagramForRegimes_name1.pdf b/tests/trnsysGUI/data/diagramForRegimes/expectedPDFs/diagramForRegimes_name1.pdf index 236fee2f86191da80bc1e336d3f12057c0f6c7e6..e75c2966c0ace410e92d6664274dcb255b3dc6bb 100644 GIT binary patch literal 27282 zcmb@t1yo$i@-GYlLV^}*91 zodIf5K6WrWCzy+!iw(lT$;rkDW~T*%Y3Wg(KSwdOHMyIM{hxDs*qee_MGTz{t?kTF zSYH{Mn>v9wfDTIkAmIED0x@@I31w$sLKIeIVUV+<%iV<>2+RUzM`1NK1hKJz0V#xk ze+x?~gUk%Ao$mV>I$42O?U>7AWT9c@9ZqNc7E#->UVFLnPg&GQc) zfC<2$`|*LVe~rWYk1paaw#LqYQdI8b19%d(voW-=1!;ppY`Q3{@*p;V91PsD@PPmN z1DOBs*Fb*}w!5yJ|LFSPuXX>y4IB6$>?prBG_kNX|HF-lowc2#vb~`(p!>f?MPU`T zb+!<;wlH-1OQRxoc8(@aAZ=bw79I!}I~y0kJr5@fCnqll4=)I4<>KK0b8zv3fJQJc z7dIO>F9_fk00%%Cqz|6)0=oP}w$qoT=aX?sjAzXkc0Gt29jqRTX z`G?Uzlm1V@-OuzlG#p?yUM?^<4`8V*|NZ*kCcHE7KVJ8L4GlXFFFS(Af6UH=;*T>sAyVPoTA;pJiH;ot=f6^KLJJX`=GcdcCPKu`oO zxwu%kAl#gQ-~8{Kh3!uIe?x@(AAH`M=pQHfpS|TywEu_R@=s0u;lLaSt*;CnO>Le3 ziruUtcD6teaCQO$#_#EsOr7jp9F2kK&VGjuz>u)5tsT&T{SK}>{!C3Q3}4#a`7_YK z!^zI_JKTW)>-g*PpNQR$^2dk%5zp@I#9h}vOT_&=hR#6vx{qK$U*H!uP7v_9r@Xu41_7VD zyE{U0KqL3Vi*tki)vBRjWNB)A{{zqo`21NT|Aa+tz)1dTyI18Ok!4M7&7EI^0DHQh zPTay8Sh+x~;?}^TC~9hKXJUFcnv*lIlG~uTzu)$mEHUAAoc8h&dybk%GQ;X`_$`(i z;eoYAGW?annJ}G&09FCw=7Y6UQpVc2^4d7f52`-$ZW;L;!2%G6Oi^Zhps?w{GXoSEu^dH-QcH3!Q!}XMW_GbIX2bQMWpdGGj9;7wdf?esx!U zAzv@|+zxJMZ-~EMAGCB)nocht?w6)($KTFxk)KUwJijXaT6o5{M_YNAhc8qtdUC2q&w>-_dts6JwYhKgY zDH)j7>6*PAxjp;Ia_jIo>1)F6<>$WJ8=)P?^AJpOuP5XjxV6aS4OU|UVTEglA+wl* z7gm0^n;FKFtoer)V0k!isNQ9p2q+VO0~10`!N^lUf%2}MDfc#eK01XvPnnqIW<$3( z=kxd5cKyJJ-01MFMWrh$6e((<}32(wl4#Dz4`Rlsov#@=Qwei z?M!l=T@Jp$Cb-%t-3axjOYg;d_%nEXtWzxSqHWU)kvw{Rr%trPEYBaiSXaToRQxFA zp^GYAC3Fo&yl2ifXJ;EPp#lw*YK4Otnm?${8yHU#rB0j1fH`W$+GfU`4?FvP7@Oua zL&{-~MJ44>X{YCyo??Tre6wiiJzr7LyrvFJ$dXX>EjkxRQ0MI z*{)k7& z95?5)=1E0K<}oXEb^09F1WFC;FvdiYCeNluVZicFVJBm`#WyL(05h22NramPI1=?TyXmmx$1es(O7J)ZhW22i1WIsggUU!6`HFbxLj2t zyN%TTJb11#GtPASI?ejZd18VnGdX)=8XHmetM9X0Q?9ONJo3{dzq7rDuh<?Gi=WRkhbZ327Z!19sA5%adWR@yFzDGJ{dM!l1 zX5Qkb*rI?322i1n1uk_pp6qvfN<4qX( z+gLe!8eDP(>FbnN-p~C`N?6Qa?k|7#UD)+?RIlS$K65RR@mu|Pn$w~EJk6c^blT-6 z_=E4S1qH~>M~UZ^E8Mtm-}%X6WiRk-oh!0+)1qBvj9~QD_|Hv`n?De0ghR<$@s!(< zz$i0(q!T`tsea~1_sG#*@ycjr|%G z7kJuoP;JH==9ajdSU5BxWmfmI?~Cz#&%uvy0nq2qe5*23MN)YS(>CueHVR>#=eq~9 zhaAt(ta=_Nee{;C$UOS)=Cj7BpT=~4McL(l7KDa_S<SJUnjer?>yNM# z8^%j1+{Re4HS32)5^x(EVo0A|AHnyCmX1iwCc-|&7t-NKKO0~&<=3!Pi!&>jCyQQu zH;@1NdM}R~rF87c^k6O9YC$tok8-_qkYn(VXj+R7%_P4SdzUOuk~7bE$ogl@rbqCX z1k%PHRv`;w95Mq@3gjA5SqxLBF(*_5%{yD*{1_BXxt#pqT#x83+UY*c`b$zpGkw?> z@kZL|>^9DIaQ-^WPjdXPheW1lxa!)izDh)qwFS~JZ`hY7uJyW6M%o3sv#?MMR^zN_ zp7nmV?6=OUzuYnzRqdY3K!5et_B0L!Qg@T+6qp6k+O)``nb{v)=Tx;S(Gw? zhXiuccI>vjG;C7qg0%(CCXUtTgVd?h26UF&k?8AnX$4&o8`g~FSjGy$Un2}-QI#s< zmB3yvq^DnrXlIw8DjB<+y;+je=}HdY{K*C>HF2t3l;vViz`uQ3!8Rbu5Kj8cyzui% zPB6bfIxX>~Lp|RQ0~D%mYw-j4=rn`iWFzhDQ-k`)X8i=**&ftsNc~m*6Rqmqot!xN zQ-PYa$=rVtV^nAwaAkj#X!LJ)%zb)p_QbbgVw+q8kWAIA+L2;_aRRI)%C(jaD{a-% z`UTP;p5jzk_X!W0Xyz`I;~29K@3MPq-6;Ef4FAO1`-$F8<;dq-VaEeiZ`>}-zR%Ut zR*5Ni@N41bRE4?jax96R>FA`KWu!E^0>msfM=hzEy{={Ni?{}K0Jvs%CL+k)9x7jB z#>SPh_oK++!G#~8t;n&cMlt7knWa7@`-(J#liYSY2NNeRO386EP(wH@`^D*m?&khp zfcRP_O;YYQa7mQ>Vqny=sPM@8Q_V%U607Tpb=8hVxJoMUt1-QxPl6bbX4QZFvTF#j z$R)DfKXa`(7uR!FtvD|*UyPHf=zL+_voI0!-ur1e9Ah8BH3PHmLk_iCKm?n`5@uX# z;-SWvfvQDOF7De!iV4|!ca~R6Gb@?Lh_*Ym?u;gW!+Z5xgbk?=j1EM#h7f5W75!y#NRrFqe1i!yuRNCTDRg4vqG z)_8rQH_ML$ze5QrHQ46cT=)xh$95$3SQ!pb@W8RFqJ?wQqv($^E2%zjs=ECjjWgj{ zY<$Ouqj!wHN%yB(5zAm_4_$fI|4Jv8wY9Pvo)1*~r7siTH5+Cn9vCK|UvBf*BO#@* z^T~3!SToBtvySMk>O%#)7YfZ|B9fWk`?g|z!d=E43T4prYUKOeOWf4mCOxm{K5(x( z`wBudS=3RcAB^_A9QBd;K^NYh@9jb9%9>4R?8mGwJbfZ zw8ZLWiK%8Gdz6jD;<=8Y)Iy^!lwG0m=obSa@25uRo00<^nIF2NPxkiT4%PdX2M0XD zgH|(fdWw}9jzQjq@ylMDmI$+A>j+5 z@1}1jDaB2{!#Any;U}@yaC+uPgfrynnT&X#!&)3ked;AyJ32C1!uzon2Zxl~J5(f* z_M;f%$d4Fun7kdr=niO#D2oX?1fY1(Udxk>C+zv@IdvN}Icplr#gFzq=%;g<<*vZc zFj9j2u8{#6Qg>(=#v4g-qgX{Czr)=2h(XJ5H?tx_SOkr|+hQV*-j`B5J<`v4~N z1@Cxmdm}rf$KW+Ptf9(~CrTYLxClnGIX5XK6WQ3u5(_kgQig53(%p7&C3rke#x72cwerC=C3a61i67xL+RV!m|z%$ zBfAUbwUg)RKP&ehzmnG|4Ri5yid<5=IUH7&U)KD-tY6_;amM7K&3}}DAv<{SG)p;` z(MMA0X4)9-m-Gv9=Z~%>y|^O|d=1^Fo?MOYH8Y_v`Pn5r_iqp`Uc7BUSP5T9H{4E) zANaZap}+Vsu~D7m*tdvqDgGP^F$0;gI(C^;#$KM7Qx=vty{2mUu+;jA%%!3j0HveAE~|-O6Gq{f{8eQjnKwZ9X(SJ4n^WutVI|$Q9dWJ2k9cc z&*gidcfsJ%E$mt*l7nHg6*Q6^{;rZO8`c%nQ^gWc8#S~qrg7$LPo1mf1Pelv}n#JW-LZ^5vvT!BCe-n<~u23ja>O3;Jn|tPmQ{qH(#hMEQVr4 zJd5+wTN*dQx$T|pS=MLyl*O!+!fo|5OFchghbeb-Ug+I2nUB7P^wrR>Uq>whfVn~t zN}k7aWmhm*YeZww!qzcwm%dd z_x-U)*C(+Sb|e_3u8!=>tBi4YU)Ua@1Ed2(vmq2&XMGP%p(x)1q)ts9OqDXf7nH8JMcs4Un1({20ajV#)r$q8X@mu>AxTf*PiZ;k@5Tr}O&G4oh~>=(TBj>3F!tFC=>J_RGf}79Et^lv(7Z@07wTolh`F z3>_Vo-jX|qNN`H%gw@a0JI0C`3T{c(`h_%<@1X`g2*IFVoL_j&vN}UKn#+EvOGTp! zHPWYEKV$5M440Ka?RqtyhHzpE9I0iX9r~y6*OZ80^ON!7Hb#WGypatj+kPN}!%3SW zYvg2Vun|v=#TSUqb*}d+H6fwMTd)w9pLKk;{6<*mC^~f>2jwwyP6A_@dFAWG{E{A? z0a||cWFFjk8x3aI+ovw_JUbo5WW}Fk%QOnj&&rXsDZYvDN%LORUsXI3I(?JQw9oGx z8cmBv-ayG*RJia5oc0QS1+`^w52YoT{BKDfFQ$*T0Sk?!a@A$@Vnr_%~wtgpJ_tQQYf z2#$%qsB>zPVX9$mS-m2~&H`nzz%WY|s~NK8e}QDp-VDhpZSz*B#VTTr!c@<4d+M!5 zbmq2Q$-leKZ4@}y^A%y#d%akg6L_IE!BFNmOzV+>9hPOO_42OskY_s?uhHB?3p@;2t&l4 z1X7xvD#8lMlE$n>su2>l_z~iUs~T;uC$$;F)Jw^d)^hQ>LKD9b2V)*%##)j$9Ovd7 zZFz*ROem=H7pYf{a6PCE=F(FWu+6d(+vR%F7r+@gnWOtUUYU`dN+aCvd@-(AMt?bb zzEF!9ag}(6?CfGBf{sz8Nb=VjZ_}n!Uy|5PxjJJw6JbMgX$O8+2|GqcXUF(DRU{!LXI+tQLRe`nSa;C zmNV@LBj2DFCD16rEcJ_sopzB{xLjc!=SU2v-TvGVY>Xm!EGKOs@nP->n7urFQ*#JP z8o&IqKc_Q{8a}iJWyAh!naNL_@I2-2{hRK1%Lb}%pEj2iaw1=7R7wp*CD_hA3#STv z9KgvjolMF&ojjuR%d$Jw&0Ro-`(kkqt{>cji_d$3AiFz1W-!Cd55`l(My+vpC&3NG$J z^z=x(e8Eg&;CYchJ77Mnt<>FcVD0B59_px(+1-X~1+Z!Rm3=z-$C2ZVoYeJ+bv5un!yv<{dw)U=3`HTufGkxC5CZtVr`BxY{1>&c zwIJLIvLw=w(;4VOPLrefrZ>OtbC6a>5h^P~WWDD|=L%itE>njcK=3Um!7N>DvT~8FARRB!1bg(!eciAlJFa&Z zlm%s{WcP83I35T~a^Qqcl*1x52XcyovpvGQhMbjcxzl!AnB1N}>VM)ZY4Jx2b&_01 z3rZ}QEX)hshj_SmN80^>X7FF6ABm5_WX=uzoy}e?atk^X=94{;l*m`lnHM@m_0W(Z2>lP zxAtMeOELwPwe`YRl`{j>^xqNFx_A}%5_WV?$2STlvdu!$8Rb2O!XF@oH0JUya@sFA zRR(7NWGlYYj^-gowE4QY-+MCu6q@8z%sDum`8pH@D}J!H_BT=Y9WAXndcy#ZA;3bw zn7jp34P>v9&4NB#w=kh5TOKR@Hcz_gXVKSDq)N&df_1Les~g4meh+Ng1wp%)+l zH|EGF6PK?RT1`k;1HiL;ZrU!*o$E}y;39_PXTB|* zGhVr^=ys|NlUO^VwC$~pqIrwXGz2ninwlG?0_9hG)q7?fSu!VZJun=gfdF>4uBXMi zsK#lb_sHazLuQ)AAKnDyxD^%VY7EF6^Bt|27fcifVgsb+-}xY~P&B=vznIec_2?}G zaO-}ND2A~BVvB4KikPSU75@2ZtN`Ri9wA*HiN9UJPG)1zstKhR_{sh3h8 zTQsf*CU4qx#Tg?rQ7giS6_I*Q8ue&dYc<9HVA3J@ggg z*`aC-;}K=uLn*^C)`ADZHpB6-9CD$jT)0NJ;cNCyA{i}jFu+W`KFLn~sqyH=M)L%W%A8CF_F5bZ zf&MBR^S7l?$OeuJ(-Cilc+Qs%vIL+{l|LFVL|f^Gpo7T(R0Eg$lD@)h$vj4J1Q1B~ z81$iV5dcp*x(kC)Vl;1eA}GHVP(hxgPY%5x(16T%Yx|DMN|b?w((eG!qi0J+?^+bl zpar4*xC&6VM$03Uaa7Qt?svOUI%a5_L`otY)I<#x-(5kAhJ&iaM@`U-HG|ivO~Q(L z_U0QM&o#6d5u?zt>D6fAC$e~AMVB^ms3f2rA6{cjQzB0C zh>Ll94HKc4iB^R+8d7_Uc986|vUB53;bO|5$#s$*X@vJ#naGW%T_1#0#CPty;BMH4 zo9#CzP+s<6w6hMYRjrtPNd_f%rX~_CG*>aPsrI_h6-jGVj3EiWxeA;ALKzvd&EUPO z+<<68_X1x}OEH(KERd{MJG?S}hnw|)P%|sllI7kO*aWS#xs?am42s^(^3GsA~H&aZ@VNYcBED6o} zt)Iitw2^6^9~0m=+pKu;wTUG>Jm1pMtxj5%cs(_0#^)2>Wr=t61EBEr>o+-?L`I-a zxra9u0sZT)0{5I&x`{~NO;e!-Qd&7rq1;-K;EIi|(J3sXK8z~TBrp^o-8vUhCPg|n zsJhEm@7)ZXdC~*OLM7f!o@j3p*$o}eTkQtM8x1((1A;(dS3xt5#ORVkxc=fSQw2@i zXhbM)R8fzm1)&2A?qGlw*q%hSE5fg*OiF7SKPn+b@N)?iqFMI>&cbT_Ve>l{rc|G{ zk%fiH9*k&SM%PHr_dr1DAp9cphRQ0Q+NTv`;E5*Hwd{K-7Z4o~j5II}cRqF#ZRf)j z2K#s_#62ePOWC|QfM19V3mY;x0QX?8Ec5QvEHex5G2rJ32rRC4$1M5O5sXD9^X%~_ z2?yG@oE>?u8kn$|hr@7hUoy*=vkwa;b`x#L>HP8}v#R#3|7F;eT3n6&4N|pVvEV?g z%jj7HCBVzJm}1#}ne|=^O4y?1-ADdIY}ET!sx3}Se{08Lw1Iz-237xoN!>Ko(_e|_ zBgTCJwsB^J`N=YAPn7FCr23PSxpQI8 z*Q%b}WlkjAq9aUiXT_T3JRdmC2$HJGV`zhQwB~wNlSvb2-lY84XU$G2ar^M?eNs!e zC5s&7*?_h{=Mt0OI%dp9uK5%eDSD_qZ}W_c?T!V-22O(#PLj9;U)NUIQS;=7MSV$* zX&OPd+ljlxDHk~HW+wYVmgFnM*2pq#UCn7iy$M$bgWWAeoN@82v*lB^p%p7Zwz>Bipe*;@v319y1&}>0B7heWod8bEkaUSB zY+yLahdcBq4@<^hbX!?a-Q^y@A`Pg^bO3c4oGi+11{sRHPfZD&sr;lcW2BXTIEXlV zE8|tpi*n02;Y^!stqbH519X?R=Cx78nMD(}ap?{B>4&uPedctRexz-LPYdQ$ZT3;W zNSs7hlP_0!u;mt&;?Uit+(cSiGfzUOAZfm6zw1g8lw zM^C{&O_LKb+&8T(o%TKF-3v($sq+KUzHMM~z4aBdu6MS%BQn2J=6%lT{`O5`@HBcq zFafp6=gDkZ@ajJZcUypS5r8euQXtpXBQhdeVpwW6OUv4v~1GZ~;+?qKY*2?^pHItbm; zz*GL0?xldIhU8Nq^_eszG(#fkg4y;z?yqy>DA4gNwOY>&VdVzf0nZH&oO*wguOY7J z$U^_<03M9o57gL7`Xh2~{#=wy#2l%6;)AZG`5DZMMr%U02K)OdM1+ zk=^KSTDM(R_P6c-dHRv#K3G&c`Ad%FQNi8L_ut-oacA}BA5|pYXMlolc$cf&T2t}s z4Z-hh`z=|1=amnq?;aYC^H;|W2kj_3%moGqU{j*pge{7^zaM)pZQW)J4F{@!v;X%q zPpJYoZO-T0^N5FpIJbucxL+?b{BC!BkIn48R}o4AH@6`vfp3>{K1fAX3Jg$2jIsXI znfStIn^6;*7Lr<^(YU;#d9f}Mfy=n+tWRwg z@AATjzO8uU&SKg`FP%jfB(p*MK)rN?u`(Z;1YhA}Hr|Rs?QJ=E$w7Qg%M%|@e{Ne- zBpu@?C8YTg`P8z_!|}_tvP2)OsNU5uJ=jmq?}C;T$(5^rgQUW~1j$C>p~&+Ql@P{E zp++o#O(O-9^-bu<;+JIPq*%zF**}%cxXdfq0+nH&DINN{0bF`so9H)USbS} zw=fnY)T?J4mOr(79;kj(3@!m*H)2rE0smtl2r z*_*(AA39A#r2W!QeQl#&h4(g&3kk$jOtRI(p~=?5{>fXNk6a8ZjDbQN93N;7s(G4s zK7G%-|1y?SI5)?H$I`IN5)ad^NxY?OVb@4bfV-xTUMa<|h~*4*-kn|b)vh98PqH4V z9~oHqOVOfFYI$jPo@Q=Fvr=g}L4oaFB2*%%)!Jd^D)jyFS`xOZMwvFX4pn$h>X+{e z>6-_cg#!FdE0g?|R5~o1`eWFUznq$mh)h+B&b>3uKJF{}w9+dmr(@NyEq`AM?SQ@s zrNx3AaL-4*&U=*5_cCcth9aIN$3Yki%0&3a9wSPkr4TXSvgi?$Xo&@gDuce+*bZx! zWVuC5;v8dTLzhHp&|_)cDaXBk4`X7_Yu~toDrU~Mq)W~-gqG@I81ozk-NGq@r}m)i z8&WrmIP!gZsVYfEiid?1LRJ3Z6hV1zP4nvZ3YC^TQSL8mBWbdzU#oa`nhLEo$4Qjd z?=Guu#z9PQe>n0)>byYlk`%Pfe#3*X)1j8bHvE8NFti2kXrt5>v59x;P1}H%W`0jb zC%1%$P~Rm_C!N`7s00R4Ccjuj3R0<9Rd6;3j80HyF>sH8vX-b3U2v~w-1p|_Bl&kS zt%_zJcHentKSH0E&0&`%&u;qa|GX< zJasVV>oUrpE3sJGA>S+{p@cekueufdMfC{>kwY!`mVA0Eqqe-x_wcAPiGz5`591%Y zfOPsO(us!(R?ZX#DCnOXooG8h%7Zq~U_HqtU{pj7SrijpdxVc{^R?li4wH95tX=;A zKLvlkH6JcuJ!`(xcW)u=nDJ%v+=KZNKd}(p{4$+zv0Xy1sgoixUCu@q`ptcT1%Vuu z_HXqjkqVOT$(@@%F3ulOXApXFD3Xy51JLxQ9r5*EKP@R6U5#;z!<=?IP_a9H?EVpX zOfE;zG~nkueN0`*5z)l7L$AM`S^N7rci9UGJcB}Vf(7e`EuG^TtT2@3NV}*5!^B-a z`Eu#bCL8+b5x3SI3UIsKzLHeyB?fFmFK`^3)UsoYcElwRp({jUi~t1@+NE*gXP-V@ zl7{nIOq4nH?H**#&Ly26d;qPjS1ld%FtJGNXhbs&DKl8NVRvL;pkVs>tpPiqsNG3q z+)`1kApzeqeR)tD3og|d=k_+>*}Kq6?9xwGYHc9FMI}x$l(Dp>v~CnaEZ1mt#cU3q z$nNw5ql1sLB#tecH0rw_Wj;Htu`al~JtKG`q$o(E`Od#N$8O%XL6#{d^H^{pKcCj} z2oiuDWM8{lU>CZ@(wafp^(iZu*CT|T(2LrAnHpt;>SG5l33uPOI$U?M5eXY!P}D1H zT0U^rJGb>A1DIlS{{c}#sK=U<%3YeM&OD;bJ7aUzGNznb+tEbd>0!H1uuA zGbe2=pF*46c+A^a_ZFhmPdW!I*2QhR3uUSKHnO9;A7PVp2n**l1dAF67p_stb)r`b z9kW!`Z(+-U91)vVIZsq=mnVz8iM(lWX`iFc1if~Tdzq{6v!{^V%#~ktgdQP;?)TCc zXT93~g$a|Vit4#F75U<=yj}=%s9ND1G>Wd8Y|b(dHHuI&*KA(T-mjxROKj_br{po$ zd1wrdM{90XTuT_iuPxJRA`+Ba99@a5WS>FVEGpaX9)V%gsp`aY{%RCG@~#G_0x z67SqXIZZfyKG*XYJA-i_{hMSQlSI^3R(w%cS`+`lfoJbA)Ik`?v+C15N~Oqw2kev$ z*wmkA1(pVvy10KF2sG0lzX*w+$+2j|p>*;7sm_d5H*Lb%Gbf4|eo`~McY>K+LS^&w zoBa?batI|17k)FOM$c1ic9P9teI zMR|UERD>4#Hhx70mOVfBDjq*CFhQO5X^Vb$M&SJP934e!1FB0m=Dgh_6slplMq7bo z8ecjZ$&{4Ro@k!2rmM=HLn#(g{C(FoF(hd0xWL1Z2ZAlHE=kg%_OCR`HsMQnJTrgJ z65NJ*b#QeII{6Th*&{a4FLRreI;3unQv}LNOqIB^WR`-4q<2+!-(ccvK9s9-pbIV= zf^)bkqfn9&oX+xIKFCuL_4X9)q(mMHAHE3C8jUh!)A_kouCuO-6D-OD#&{DP!tEJn zZs(}`X=-U=X?`V=$`FkY1jBLh34DMb9d+7WHiJ`&(WiG*lReX4jv^Xz3q(S)N&#DN zH=@8R1;WYtJ%4BrPIOG=)gh&X)uYE`9R5I+rMX~;-=GOJ!PYyvOz@ihyIMAJ`4vZB zmwb>|tGo)8(r3pDf|p-S)m1yTh@U$grj_>;#+m?wP1 z1pJ`N)%r21gQc>!hwR-bMg*qo?`k%m7=0{naF{e6*5RZXDUx|SI89(gqu?&}@wFKN ztRH4t8n+Z0c2q0tVmQ!UfmEi(FMF|$pl#z=^2uUmaew_?Kdrkt;+yEbPi39ov{OCh z%Mv8sC--?Lb7J9{d{Xy|q0Dam(4J#L;p)&Mjz%ZILQSN(2HF_jq^8#yfO?u9zceKs zh8X$Mj_`{#z$D!Q#LC^9pH2{1j)qIQ2QZ)n<|RdVF)xZKI#-1)2cNy`-e2bn&FpUio4le8!Rq)I)ea zbXv%MB$o;aBwuuy#*v8n*wpy?fvXP^nWj+t;J3b8rbT3v*Sg`s8 zIRu&3J6k$n5LLjsw<0(R$ky>8#tQhS;tyShNX#^n`xaD5-p>ajLi;#1u=|-eA@rpC zMAELIX1}CO)2EW6JS*|NBKM5vm0EQR+%e?1JrNxS@aNdZEMvZ4QH(MML^%)ZiQBu2 zbj50-mwYH{Xnpi6NlKu*T?N}e!KiSt@qu0nkBshK3}I8`Kt~OKNm*iVH;#+2iT6`v zO+JH`(PoL}z;OK7Sk)+UAM7s5r;i`9hW^AqK#@Ou5+>Vbh5acbc=t=vhW8gnX4kh` zT4eh1Uo%gQANGcxh2Xv)i!piPKnq*7H@!(lZOFwC;g*qXw_n14BGi~Syx1hXloysd zQ4rOSfPMNxy5G352Xh~MS;}8>G_BqK(fCUgoRHvEN8vu`-LUg1{3kfl!nEjxUnZs} zlsIZnjl$p=Nv&~vJu#jK4lTW@?QKXx8L(OI{;s6+x|W2F+CCt^ucyT4lU3uB#1KR4 zQwr8#rr9^HZIumV=NfM-=L(QDgYbC>=p)rJ9CXoBqD&my@ci8w<)kvLcGQlZGjT8J z-!Nk`J*%_t{>E9a`?8kDbrcHDq3c2ZDUt8n7#iF|Va1L^;?rXir~<`65SA4s-OGLS z#9A<>_uH?esM4hiCuhTeXUdT)bBb_}xp#kyea;&t4w-c#41BUY?3Oppz&gso@mr-V>!OYne9oU}f!Bq!JvN_F{GLa)0$RZ7~mI~n9L znj`MED7GTv)S}#MV-m;4FUjDVJo0QcHEl(ZtZU#~5&^C|?XT6YG2TXI)I@5GJ_l?$ zot;PK$QFxbHfROUr4M1P+0r8m;CadpCC^fzv{UafTb(#Qb&lK+Nwq6tbzl*f$Asm~ zqM_jBFs+aN1T4n!TX4@Nn+b762)21?7w*@7*mva!aKCE=T- z_&|9Yq6P~|T>1GRYZ2krQ}8aUYqAQ7RmHC*9g(5NuEliYoj_8{G4FcM9<&k!`C13` z_+^+p^;(L!pyS%cB7;VYOXHjp(QBBoLR_{If(f1l{E@U{qc>|GiG!pDP=bm9-j1g# zOap3&>&ndbBV#m56FM;BjBbGXKzU#*$xFbOrR&Nhq!S5qAKBskM9jw@`N%*KEl&d; zH{5y=-wbNI^oyGmXjt*Q$7NI;et9;l(!i2-Od}&-;$qQL`X52=QXEn}7=yx&ZXL#k zwWcpp8Kah!x&orNK=dbMpZ_SDRi3%QIxaMTK{6;b2>fK^qi4Mp%T6`Vgym-@3Tc7m zMIRS0&lhhEUSKSDq(>2pOXj*~Tp##;^ZWckZY<&PsZPul)4V7_2~0JSEA(;097v?` zd6DqVF}cvx3DMV=0z9NIuAIpwcwV1BK!vF%rV8>!*yV z2^h|kIt@Mb+;O53ivG}#H5QR%IRY=XE6AQe<~YC+v3R8g!QZn(2DU^@RDZU07t>ie ze_oXeA^EJ=JvkD?P$KkZ`o~w*TaCaOMPd&k0oVa4MWYbo3YLdFv`>pebkR|jV2~i3 zs1% zbO{h+b&U)>&8=jmHBezOC-8`Bx9`sW==D{t5L_j3@?wu7gmG=kcZ*d>c^lt$4`4JM6Ds|hr1a_WGx=I|~j3WQk&)KV$P zX#+|(f}flsPLkIYB45R8rh_T0pe<*%u;Ef3UtEs8#D|GpdT|`5&qtZK^Q-I3Xp~=m zgo%>f2^hsO@|qz=7?PWk7rdpB7hFVB@QElD*t=9vM)#c}^PfQLpK=!aWcTn{6Dhp= z0bYN}H9a#V zaWPGDwmP;ezb?`eYhUB5I51bXdG?d}jbm^KMBUnLTdV&E9@QV6p2@u$2sc&ws7d0$ zp1*PUK3qMkt|*H&^o;u!&aGyn8%wxK9@bH)DXnmz!I?G;@GM?g9$cUx1yv8k-|ZB6 zDA1Jbd~BKb`$YcCwbTp&I25PcKSP&2#yq0b83)e%@k`C<1$%(X0^p?f8WHDl+T_B> z+Tj~*@Zy7&y+5Qp9*|R@79h^v&T`+LH5$kv0#3kNZp zY|1TxoyQfJ%KbKNTK-DMgEYVABicklg!rYw`JK5*36}kZh6QZ5L4bYz=Dy+0M2t;EnL2`d=Hy?@+bp%* zo%ZJff<>EZG!o^eKJBmd=LIf^4)rC0T3aA{3b%a+KtVP5mFkqirgnT6k4Mh z-SaEEwoiFuKz$h&nlI3(Fw_sT=-OxRlS{_}`D+gsdAt?30259aDv_|Kji{try#}f_ z1ky}i`Aw1gPoVcFAJH)M6E!o;<=Y~!#E=<~H8UiUDRjw$L(G8v{dL;p15`O@>(r;| zWk?+0;c`t$Uq~q(d3E|ii?QDn{C|Jqc8m`U-5VC(baL5yw{w@9AFZp zNC#%X`Jv)SKeD3kviNpnH#P>q4>L#MO9X&(ZyW&CY3Q)-H(8WBmI^!y}gbpH3xmFx?`%iW89MQw>o?U3+73T zSeHlUspw&C`n6(fP zCZEE_U&QgrfwDcqW$ICx?Y?EUDGai*fM;h;fjQLpDsu2b8p1tmJlL;d?8>AfqNaRb zXf(giIRY{}5s>iJT)q<}D4Ft--VK0+V`V%MCQFv<@hO!fx#ye8J!NG8AwfT2Wp@Wj z{6I{ETVYnB$!HGoRYr5X5ru>Yi9#ORo%%#t0+sES@{%sCsy@+TheyianODrhp@4k@ zRY`8{SDq>&9ON-e(?+NP}kBRQk zLu&d=?R}!f+PCdF*ic?u>@u@hdH#=qOL`;2MPJ zt3&3mi6$%X!_l9&gqvQ#6xGZS+(rG2W&3g)58jGqov=TRM0J!2siC&#+ud_dwbW|R zHLgcEq>)HKePV=O*?CM8L~Ga5kG68Bpu1H}dEjxs6vRC^cgfKZpl3258Ud=Ve(N5s z0KR`+xJIT@G1EJXR5H>^40WVvz(ys`Ht7?YVx)yx0k0c>D@4?qF4n9{c(Pg}joIvP ztKU?VYcK2(#>ZjxED2T5E?HQuJ4)kI_lB?3yU^Lc)SjdNz*>z!YbESs!NIJJrLT5A zMH`+~tAX?g({lyEoeoKRm=P9WpF(DDB!`}^NT<63S!kJbQVMM)7cjV^a>+_>%$mGjY zjQ$ruCIS@D{mDd*;gv>?B77(v(%ch)#fOKdhTCOo6ufKZ8( zjI;}4$w?6aULb+cf@w#lPI~YLWFd^nZ(0P3a)IS{sIkNNRpb@5zzc>LGJtfpy)T&d zKJW>%XWl>xQd05n0aHB%2%QwRr;KVyYdh{7^e$=f6)T|cPIaI3_oFDy_4H9`VIC7} zE^<5+EO2u7=?Uskpzqd!=&kBCrpE4b>d=3N)tb7anGN+TrR!bDv(2vd>6TZsJP-4V@4Ux0mwlD z1e*KQ@RN%2wM~n6vv zdqn=MiBgbRxx37exHLC&GU^mLX+3Cp#VdZNbl-jd=T&^>`9UXw!`28$s!m8xIr}~r z1YVU(3bM@IZ2{JjevDkA>eRg8KX4o@;+@{}nWxzm9Mw+qT0v=|To9a~4a0sjw=k%ZP()7@^|75kL zk`PJeG`qu`zvDbo-C5RQ%k@WAhNd{t zZ!^fdV)L~CPol_-;oj*t}ei`=ARX-4zpjCVYtUW&A9(%hjF_tjXkUD8L7+A<3I&Kntn91Q0k(;q8efUYlAy>^zzK$hw?gsx8Lvb z(>CK*=mx(2DqMn#M|PYanFtTxS&pu76+kcIw_wHvY|c*>t> z2&_bb+3O)*M>?qm8MQxy%q4Xs>-3&edhl0Qx7LtNA?ZAlYM#Q_;e?Diq|;%YiQPxM<{o2bM#0=BxKx}CxflvHKUpl1bVC)D+rh4DE{@?Xo-(1%?bM86!{ha4)bI#BG{BCb}8lA`zLv@9zm_q0rZwAh77Hke< zI5y&2C?obv2%BZyOY`36GE&m0dG?h`7kfzApNpSC6+1sn*F`E#HB>R0tA@@6Unw{t zX<9WaE;I4-u~Nn$&j$9H#)S2N$vOu1=0G(IL`()aBZ)KiOviRJ#1{wK)md!vBD^rq zbC%^VN6)0LHV?1|v3~x1tFiyx6)(FuacVN789voEz74d<1u8qTs~SFhDKWM{h`JBJ8r_JzTp-p1F=W5@mX z7Vjwmm@w!2;Z7@Gkgc=AY#3pEVNKhx?o`7)Wvi^3ifXWd}s?q zBtGenk4$n}i3HoJ3*W=_Q2AA6u`ubRa^cw8WlILWUXvA*YI9KK_xi)x}*>nCk* z&rxLSAbi!+7oT#;ZNlyTXL@u2QAF89v#tN%%M`j^1GX9&uCdXp=!AGw*Q0?PoCEb> zEp`#>Wg0qlbC7s;VxWNs6;!vw&moYh3(w|}hUBMj$!6kw+#68S)80=l*dxw9eGGn5 zez>uQXpkRHGD2oldL{;L5iE!m$}n<}2I}8;t#;1KO;66Kts6MV7)jgy)a@wlL)qWu z*OB$z5IDDEy|=L!|GAYO@jzt#)ok-r6)(6)x0xUVBQTpsIZ z9g?QYN*|xH5#s6>Z6Dbdz>s>Xh^cA8fqza9Js;MeT@^7y?Ng3lGTMOhi9qW#_qR=F z0-p|J)!z3nRFM^x$J*dbFyDQwoqMz8q)M3=m$*&kt&+bdLQzmhxlveC?mdn@I9IN z_1WciD@)_OGkoVl-g(emuKfFmZ}|Q7Z~H}Ap`WG;mv*Nxv`JB|<~=ECoyKCI=rh57 zK8cZ{rQK-kf}@bI?SU$rJ5rgdU)`+-#-1HW_7$D;`}VB9b)ndEn&0r-zHEM~8e6XS zA@jJ(;I`X`jj=^fi=Lx+#x0_6`}Ohr^=Hx^j9QvXc@+)ZzF&0TQ*>+{7CcjakNj3h zte2kKdN6mW#H6>&y&(ryaR+LOU^=7VBRf_rS_0|cI&7?5*awM<8}D8;5Kd8bG|BqdF)I#c%-Avj$EuO^sm~?trg(RB+96* zHjs%OZC31Hyhy8oy3}f5PW+m}X2*aOb}J&=4<9Vt!(>F5_W~5n)Cx|GH2e5jwb`>5 ztezR!^5j#UmP}BrMx8cw@)K_pEWlzBG6>+2wwXKe0{Ff6Yr*-)9U4&I8D0KUZS1ZO z;F=|$>ln=vbhGsvuw!OR!)ws77rVj0)b992Xo&$WX1{d$^2n@Nw{U-TL~cCi%y3Gdh&r^s9R}vnsLgFWbR-2g}*?gM8^Hd(%&PK&Y@V zU@82`^Yjn*9E2Z7r-dbok}-ESb+U2<9E>>PC^fVlpz6D(D+ylQTIgGVO%Tu@+MA)B z%s>HKw52m(tilzQI_A*g6%;`N?lA#4Aa&z~3nKZTLP!xIVF;F#5%8gb&k#WA$0q`Z zBShd>9x_G1z-VPEX>SQAAhG0zlFp`BIxitOoDV510{9$(3|lL#kQa)C^1+1x;h!*& zN~0YW%&jbMxg6_hx|rMPKoBrKBwP@VL|{!}ZwT;HnZqEkAM9|_iZYt!E)W=wn(SY! zSN|r)!!cYzA;N%K4_Ns@cm>08XYv1UgjZ$4HdhVjz@sOtF%7lB#!bVJ^(ewgEl&OlP3UU+yrX+IPE;)+1HNn_ zHlHCj(!F9EwdEEiWN5j-`l(Fv!$z`q0c&A$yM=|T>#F$JZnyjAF_9D*PG;8Rq)RB~ z@4jW^^)^Qx^?0+1j!e&p^DcVc{IEvbz(iHNTrv{iFY4GSF0IglXh2|2T-xZ}CzgV_ zH&oiXNq9N+KGnxFeph~u)(c?3fo8@0VG=i=HD-v)e;lS{lo(mGf7O>AT-!czP2NA)YN{f%!ey^IwpTh6mB(u?D>8C{ zMsVStwKvOs*38M(ul{FR6ri^ZtWV8noVoVg$Xt_4mf>n)N6V3woy*N}M~B3m{KIFB zhy;p$YE6fsh5#G8vie3T(oMIIcMe)B$Lvv#uUyq*wDX|x20Lz%P6?-H_|P$>0{((Z z)KF7bQC`}_&^xKBq&gp-5=97|9rK8`&EVK z9t|?=bWDGdRVpL!l67*t#<(LxyufyjzUL&<%8m|iFl}g}(|p9UTBg%iGH2pn>m;b4+>wZ6EC zm7lvJ+L`fp+XJ#F@;)fd())~JI&H02)h@0qUE&9Q>BI4QMDiwA4lnS%KD5dAo`Rij zz5J+-H)x8*Hs#vOPn15Wp1@6RW;U|J=7zkb~8GG*!_ zTXA24p6lOAj6QrwA#YQcSDFUt*BcWs*4{W5m-)e}bmaRU{jzq9Xq}0e__kg4%k0(U zOj%jAp}Hwb#@&%F9!xt?J3S^*WcS0e)%+I^HstZmwj7w+EF-3b7 zcHVM`DzzDXp~cl*h|Fucq`yeu^1B3Xfb(rN6I@kD13lM=Q0O=z=wwY*p1rm9_R8aZd*tn&sy%5?}iR?T4Av z;!G_hmdwO_I1lr$zS`k`mrr>Y($1@`IB-k6GjF!aY8#RQnE3+dz!=yVl2 zxs#HO$6Oi~Z59iPH6D&2Jr*wX3>oHxeI&6fAMAX1O|>F(_1&$S63cfchuV^o(OIu2 za`N3cS~aaXv-5NF%2Sq{`;YE3K67!4d(x|6I(J8&(Qj&?-kZI8-1_BR*i=kX5>NHs zR{i@`&NR=3mh$ztlw%)fU-5N!y|c!6Ij_T~&Tf@ilQYoWQ@DcAL=n@)Hd{Xkjn#;) zc|w0){WX=LINkS_PQehlc`|M8ovjj|wb^@Q`MUZXv{ZB`DTh8{p#9=%sIuw4vHf|dmpCgG zeh{sc(=%jlcCD^F-&%cf+%FNMm*0WuXdj>SXL?9-G1$fW146LLso{dZdYjgDj;b{3 z%~_e`k#3W+aQgvjzC4&!c%))ntbIfum4xB5F_qLpxnX6JupRG?(7E_R6T2Fc7 z!@Q>!nwlkJZSr@Pr`2xHU|(O^$=Qw-UwifK4+%X;k1@*DmP&2)%ubE0U<<7x%Y#sj zl68xM=8Git#7W+!5xwe7uL8^v2dv-ToaOIJzR+3;AD_Dr;LGGyUTOH0le%iV;BAO| zUvkCk2r3_@Qg6lep4^AD%?!;b2Ti)&IHA9-)RubYyu8bOLo!mP{QW-|?CK(K5Om|O z^y~*sMnq;co0OU07b8Psq6c1Ra6RXN?-Fx*%++6b5HwfsE&)3V>qp!ko`132y-pmb zc^@Ullwr$`q6~)m96E~mP^jZea)?n?P7VdpoMU=S@rq6ZVXLMZBqOV`Bj|d=c0qD! z@^HC5W*{(R;leE=jPI%XYNz~yPa_(ZISy^yg1Y79E-sJM$RbKbl$ESx<2#{CiL@)O z6@vO*d!zR{tV43D(j$f5t1|jcu9tO=?Jtg4d9z^JIywjDNedR0mBX4HO$6e{Jx+^n zZ2C0y8ycq$(1(UMpJbXZ6D{LoiDsb8@=$NCpG|4|w815|W`A%+jv**I^_P5_WI@G3|FNhlg>Yi*6fIDvtlOP7KV~etw#jYOx{j?uyk)7HTt$g z$thOsB+6epztQ8oJrm6(-5uBK6^T9J{&+rW1o?5^iK79#+q*-GS9aw4D2hwXf>2VQ z)0^K*e*Z#y0L`4%smdI$ZphqV*=McqxG{B^DoiT*9dj75`d<~SA1lsMnnf->$V+kB zqo3wJ@9`Xc>NXKKUUwi>V9fooJC5{|n7=YvYDp*TuBy1E$=~H_pKM`!$|5qFM7WXm zNQ~=^6iN8qbB;ZVg|L$;axX@;iPbn_%w+CXJZA8DNoW~me;7b$Id^W&|DmH?C~v%q z`haXuiN=};nU0a9aKwDp9$TYzz=rlJBv&zY=u*mMNUrjmu|OM#OV`_OeeI|E951Dr zbRrJAw|^ptn=1cGB|W;7TU_>N^PIju*ACA}EdCkhhmM0^qfcLnHVd|h#*1e`e`OwR z7h!tPD5jDzQKgWvo4KpJufD50?iXL*Re$AK$e03o8b!Bs4c-EWBF)NWaf>#dF5U@Fyj8r~h_}x4oF(f^N%-++@Ki_kiJyO@ zL=iMt-Oq)X1^8?cTx9O#j2l4&?$M4v!ow(qvPw&Bh?)?*x&*am*9oY*b#USx{T03q zyeX*cBc;+hfrOJhiAF@cac6YM@g?rZ2CZcGP;K7Bce{0(hlF`B;`OlY%QlWn`qo#t zIt9dnzja7R+$lmoH4oFm^OTp2z-wtD7lp18-ZrAGtGO_AD)JIu(KDGF>Qns?E7pGc z)Ad1*$?x(xkwv=|dd6}{>QxaM)1L64p4Fr9MB5VylBUMGcSLGgzop)zDz)HZE~2X} z;j}Ym*=vu`Dd9h{C9ug0?wA3!&)K zvgDSxE%4Qf%N&y%a)^X&W3*Xr=b!XA>E29c-37Coc~s4tYD@~8Uqt2K(Ol~)mwr`& zpJ()j>@*9ts#&TE#*wNtY$lXxtK4LX_S4-bc{-b>v@<+6Yn#h7&%^}?eq&iZS(>a* z*DO+QeP%1Nt_~6XqK^bxK;!WCqT=w)1F6S`4eNrr@pp@~JFIoYWU2;(lJcktp($$5 zQ!*S=#@a18Sd|0y@TDq;nzLPMR!0&}OIbXxu>GL#KFhbTX6~C<|~Tscjm=N~_Np?#?~ z%v&)xQN>Us0mdXp*Z9e6`{H>q6}?cEsG3^oyHRm8MNuW97oY4WEeT6UWyUiwm#)b) z_9wzWhW4(rpm=8*mk}O|_5u!B7x0&uRa&m)mg0xyGC6iB!}au=stg{?HN{rjKX!90 zHsN8bWw+S?r;Hngnsjcq6BCa;Y2DaiUKEZdxzk<5HzOz&8TjHSQignIx@x^o#lCch z6a~g=h~B4lhh8`lg(@NnN#8N-U6IWa>o~YcUE(JfT9(vf;>W9Cr1YerThjzd#!=j? z9+erH=em5v%t*|?+v_%4^IU5qGhJNlgro1++lPl8T~fO@&p&X%2af_%APp|XNHEC!ltuz@i2Zy z?}@67vd=o0g9gOin7QtHvc_Tl=||CC;zB%pw#jo^|TWy`r%PsM@uQ0qe}UuAiC$OobK*_VCA>2i+bAa=s+3+>PveSoBvi;a^*QY+=;! zF?|2&p^6`}k$_mdhE3Jz3rkD<`Vw9^O4wu=?ZJd6%GBYWig{5^a7!B5^|0I}l}N=Y z+$=|-bsv5SQ%DOvKsmDIIi*s1T}@0o5*_!&6SUmlezSDiE%czU_$=>M>UK423e-ki zSjm7*E}I|^ZEP;_g|L!o#g}-@bDe8pQgxzy#QmjkO4^xaXT=_h%~8LL4|=~e^qy`B z#TcaPdG$WZ(~yUrt%>Xirv840t}lFq+nV1plhf2cl>G&Y`lFW7bgqz3HzQS5+s0ds zG>2`{jcQWg#?7y6tYhINm6xNB26u|o+orZ}KG{=OyV-w)*onYocnatJB`a0;j$`TU z#WmZJCN8qYQvoZ&&!(Eagp_Zj^#G(khm@0M{W4MHdVLl3Li3-1&M^{!rQ;TaB87k9 zIavB{97p%R@f;AH!qvnD7wbY%1`CK_u^t!+zZBZp9GeA&e?xV!7>TDdKvNX$EgS%G zID}ur+|mkQN}do-Nf1ZFoD0IQ?qp`}1mZeCI2FwRFk|K7351%ij*hnGc37ZB00OX; zWBlbGKnViFLQa6M99%%lL0(Zt6%82Df9jL)>tYGm4WWR19fCkW!5grj3t~URAqYVs z+#AF>KmhROXC8@!Lf}w11PK%VB?EyWAc7(w5A@(5Fay>ORt84^U0_EL=m-fw0rd1A zR`-AC{vkgR9|U01|A)#PTWv*qE6`vdFo`J^MY6E6H*@;IE)OvQZDdaZKrb^Zz^abR z9sf18LpvVd^Z%hywWT%xY)^=pxdku;S`7!v9rp$A&-UX5I{%b72J}E(fCdy-87wio zGdA#s6WSiI=A*D2_Yx449C#gbzyJ0<45wvc@!#SfEa=lfi)>0 zfJ7W8LNd4H zc64yWPQByzpHuXoXbJzrWW;t5h!pcb&q7&y&?DFx_G^alD*OaO&CmeX1alWeNP%Ie zy#|0$wH&nVt+1U40r5tF=wI08zXK=y05b*u#nFFsbky+Y9sC;*JswRU%m4_HL&C3Y z1tPPM7?R*1RBW&d2UjrTL0p-i^8$pkk&y%UZSDaki=rJ+llqZL|9i@LIDyeA0D%dU zV22a#1rY+%76Gw<{E}fKQD9#X`(H9B9Kj{!>>3-05$+Pyqm+|1N`y{BaE^ zT;PxTK?RY2+7kiMa{g-%CLoOXqb^V+{Es?AMG*fV-9PO?p?|a=40O>Sx(Fm#oqwx~ z(4XxGbg?lgurKU5aB)HdRNv`1c9f=-7Z~!`e+L}@T!Eg%{={fFH~^IY`1A1!j&^c6 U9&RupAwejFgpEyBU5@1c0mGX$tN;K2 literal 33078 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 z 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 rU?9OxK`oEQ42B01tP=bW+V Date: Wed, 26 Jun 2024 17:08:17 +0200 Subject: [PATCH 42/56] Fixed testUsingQtbot --- .../diagramForRegimes_diagram.pdf | Bin 47255 -> 39639 bytes .../expectedPDFs/diagramForRegimes_name1.pdf | Bin 27282 -> 27282 bytes .../expectedPDFs/diagramForRegimes_name1.svg | 2274 +++++++++++++---- .../expectedPDFs/diagramForRegimes_name2.pdf | Bin 33092 -> 27356 bytes .../renderDiagramOnPDFfromPython.py | 2 +- 5 files changed, 1842 insertions(+), 434 deletions(-) diff --git a/tests/trnsysGUI/data/diagramForRegimes/expectedPDFs/diagramForRegimes_diagram.pdf b/tests/trnsysGUI/data/diagramForRegimes/expectedPDFs/diagramForRegimes_diagram.pdf index c0e948010babf277b855b32d159c8350cd29c836..3442689d23c7872dea7df8d4d7f0063457848182 100644 GIT binary patch literal 39639 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 Iq73c-0OGTtf&c&j literal 47255 zcmeFa2S60dwl+G5fMk)N``;PY>kNf@aInH3$OjmcU`l`OQs%rJBYl;$5%&7}shOYm+e8 zso1FO3@tGP1ugIj?2Mg_On?Lw22uh!fv7;-AQlii z{4dAZ$rg6D5(Z8{ZV7%4HV#fUFb4-an2np8mywNwj*X3u0Yg|A!^GD3_+A`{_jJE+ zLd7a>;ACKJXNJM5XkcdINW}@9a2Fv1*MG?%>E;&8pgH>6S%E`g`_&}bDjfIT^ zgVo4@ik*cGkV5q2e^FUwDpLb%NBB7gj#gBxckFCU{wxpo>E*S6+dDa#IM`CLN|?A< z7@6Fa7SlN^G!H@l@>D}7aJ8b2N?Ln$98%I+!m-p01qmybU%OF<9jdoE$9Nj_ZPlosWxygOmOE zQa~vXzu@8FVBrJvaDw@$IC(i)*m*hFIQjlk8|=q<&f4i&DbH^CpQwIz#E$Xn>mM#J zA^`0FwbPtd{C|r8T!fzp!Evwrr4S%?`@aE#e`F!{GoFBRC7ieZB?QMJ{6q-AzZwEW z*84Xh;5{ZFI1BLrd0U|5@7!R?ZP}xr-B19(q6-2~=$b5eT1jq6s zLcoDYj6VheT!f$33pfy|@RvY<$b7#Z0=T??fdG*he-MHbGW%J*fCG^Ve+dML%=d3X z!1ISW1U@_ZS40Gt_b(7265|g-a6)E34FW_e{3Q?|GT+|-!HGfnr`67hNQ^%S!3mlD zEC@Iesqj}oz=_Cwza9d(yokMk6OkBy3<9_aKTj8MB2wWmfdG;D{!IwLXQMG@?jI#0 zxV(RX0FfAf5Q1Y7ej)^jRQO9EKxDqZ0fG~Q5`l;iiSY*^I3cs2MMOaB`L#ncE=1=0 z^$@`2MeGG!h{X6~5Wq$FdA)!OkqUoBFW^FCzJC`2z(Qx{IOZTQ{0QKse`OKD<^2l; zh{X7V5d7THF&82g{t^ffneT6a;KZQ(lZdzwiSY*^I3cs2Mns5I_$wgbMr6K!69Vo( z)G=H!v;RmhI58;ygn%277=H``xClRwh`14{@RvY<$b7#Z0=T@0LMCSV&AUH87|AYXTZ2cei zf)g_PSrC8`sqj}o07hiKUk?FXUPK}SBNF3}^#ZsEKTj8c5vlN(K!C`6|0V=*QxsT3 zJ~c|&0n7AX8KrP}{{jIbG5#O~CuH{1dI2I8{t^ffneT6a;KZOrARW^x{fIi|IWZ{zgn$>37=H``xClRwh9~sWNiSCWDHg{3u7m9DlWjOSjNP{%-jin zC}!d0sA%FKZfA2J@F%u)qT&UddH;)VuC#-JI|l1*6I(Oj3Vf%dODPL$z|okBRmvLh zVU{p4vNJY0_WgBq0vxYxFx*}n=~H2{S(MWCsn!c*vP~=1ErO4ReCSI?tZMyr2#p|P zF#5>~MzG0TD%9v<{Nk0COWsB|4q&h-w2T{b-(j$v^aEHis9wC1_c_vI$B5_GrtYHN zgA8D2wN3NfF}b;>L`YO*ww`v*H%!r42@-t-vqMvDfIfUy7Nsxp0RQd|teQe*O#Aa9 z$-@?PU3^tnytIyIIe9RcPtq(s;Wyv zMlBF#U-W;NK8s>tVkWu{j>;(`dB%_Xd9k3T^Z-n45=iaN;Qx#t(_Hlax$3;W98cpd zuI&t=lBb;9n@JR;H3m(Y|;ZoQKzAgT=3p<@T`(|SGiKZk>G z?8(Z>$$949&4;KYPMYI?qA>s-<;RZd$4=<*<_EOqvzBpcYo4_X3GsXXrCq=VVUwVX zx1?mHKuAbPAbsE;2sQ!|2c1JgI)0zNkWrA2U#RELBcq_9qM;psE}&zgU$}sA0SyfU z8v_Fq3wWWSJjKu9P+X^#th`a(K~d>#cAC=v!Ha6;ilp!mqh=YYbZoIeko?FIY}I**5PiJDy$ z6<^5!jmDmU<59%B3$$XnHH3G&*RFCJI{2bv5M91POmgiy9X-PhE^aUnFCV|SgrtKd9x#wMm_<`$NYPR=f_Ztfm_{*MC!p9BR*Mm>*?iGA_%RbtZnkrBPK`uN%u5$ne=h2SkLOSOPe30?ZqfoP>UJ_M8GqA^};dpd`KrG^2ZVfsu z=iN0zLx*k*qN`j}*Vd0kgG=^fg8BZhB>O|KKjj(*VId;{;34CIL_koVr6t_K0Vq1_ zbmy>R9hA(kUiVrT6z>}abHRa2i0d@{d;BHEReFkH%I9oX$*YVbR;q$@!RP&S(o?#v%vj@voc zBVyn)agA+pXXMAS5k3LIdp!%`B_fkwHcen4 zjKCTCaLQqk5fZzErCE3UJs-$!oDSXL~uWn5y$YO`yU+H8;6B2kih@ zI_uSPzd=zULDsLN(p_l{nT4Gl`iof?f|nQS)-nayr>s`PA*@{A?AL)z9JHAYP_oev zsnm~3W1o33E|pw{N^@0SgMr@Xe|1}eO7wXd!9dBhQ*>mQ}33RzYXjirWQQ|k=xeGYNkI2b` zv)|c9?|U6^dDmCtR2!}0@~zFqV(2{yAK@K0e~in9JAqa}cDg&9s;|m6H$=q356Ls9x)WC^&lhH|VELrOK>jhTbRye5 z%Lmo#Es&%g7zmJa{m|&B?2yNG$`~vRTI1e$@x367cr2w?S;S#(w#rqv{vr+AK})Za zqQ?3)0;QXjuz#i~&qgZjU{1C_G$rET0eIAkjSBvx74RQ|eT``E|L3&nUrejxQ5oE? z?M#FIKiF1y_n$NQ`l4W7W_lrF_kDCI-*GU9zRhEw5?k=jC)2l0U?=A|NY3!x+`EH2TSrixWjYDyF@E!|0;4!<2{Z=;D>Ugim3Z z;!#SXbF$0+q>Yc6vYxpv-!CVMyh*`z*EWC#J%fu}z-Jm38-*V_DHd5ywb*a}`7zgs zf;ZG>=e*)tW9iEnw(i4u{TVTR&#@|Hy+`NtonbIoX~7^84GRkRJ~NuXnc&`*YmToY z-P`X_SFeu(>KP#O$uNDk9?!X#35pga{8S~ywYc;Qm86!h+eaO%ryQCVp)el@&=qt^ z)@(EmHeMEf7@F*yU~m~=!o}ZyCQ$Np%z5vz2>tZJ@rgdRUX6>GKHU|G6R!IZwZ?8BqV=jV(4{^_F{ z{m%?nqc7vssQa+67Ce$TCqd5E;&I2vFH->Y&gV^nEk?-Q7ySB{7I@c*Gi*hk96FS# z;YNgBT)Zi}xPX>Z<^_ZK@b)L-5M1hc>|26$1@n0nK_+emYR1TcrB4`*x|Q<%i{~X8 zMTun@^wCSd2z9cuFh%=mDz(-Q~CH49G~(6L>}&GAQTXJ2I!YYVK{l8cT*GB5C3DFphj6Y7s2#oWW?y)7 zEnjw}5F2CVx|_}|VtmMqzI`nobZwd;~c)E@Wu%aopv z^+r1XDAJwEh^ER75(3x(A#25-vjg_QL6epIdiYB&9wrr+M%!Ol>qi*gl-_+`(=>xj z`_WT+eRHP);&&jkh)WmbeDKl+U4ThnSpLJ!ulh9WU6b?K9-u9eVY?Xyh}v2N^a4by z0SskZ3rk6~3rM=?HY-U+s)pv9c(e1N%vTTN!y!omkkVg2NdHXlpHR**6SA}Ma-AuD zcDDaIW%HjHBmaX|KV1epW53^8{kK;CpK0~8X}-T`b;L!8U!v7dde5KpJ?w0!bNXiu z`?p&Et=505_1|j!KdIKwCb|Er*3U-yf5tWV7it|?{QqMi1b+O#SP21&@Yi9@f2Y`2 zUST>B^btQ?oilh6Aol1<%09hS#Od1DxZqmiPtG53(ZG3+(VxdOvE9cf=g6X6SABRXkF@N-gz4Hk zzZO(z;4LXherhxc!;{S|0-bxcrtV31Tg>=}y@#=VxOM4RZO_%MR4?Ii;aJ+N^u5;D z@XU4I(4SgVjKx|axiR{btU4zxq};kn4j&w=QuGnqbGg%Gbn#{%y4lcD{0z5#cn&rs zr6M(Dae75ZR2IyoX{d zND+V;oqM64xh0clV4j%rlVpt!T6Hxp-dyi>iEk?!m6upF|$waAodXLPJBXOgayCi_6mFcf%J_!bdpZ2hTlN z#fFH;M<@IUXUrO+6$iL)RTkcO6LD3+7fPb%LG*rvVSCd3G0qn%C4KNPeu)!CuQTm! z?Jd-M_pb{dj*8Cb#OttM9o6P43X6CA5N3)=5oMZRTE+E1x0iW7arO1}+g>rzHEJ)Y zCleP`^n4#FWyM{B)lGy|;Z+Toc|YO1NpFk? z%1~_Zpj#FX?tJPh*OVD=$&@r(zg0OTPUyk5V}f6s-rnsfec|%PcaY$4z4p&X2l{h? z0#YGf7+$b1t?|A`A+l9%FR~?_DRm6uZxn2zrt7SF=w99}x0^0*nzp;T6`ZltJ1Hmp zJ*VU0(EGdCU2FLt4oRZWtD_r@Ir<9nRS5Qk9@O&JsZ6{M>1uT=>?(h7OA8cZ-`H)G zkQTA%AZ{uhs+cJ20Mq=^92Pj~Gvg2vi2iK6xuEw2In4__;g`%To2j7P#U5>e)N!mj zj!IS~Lu~hwlFS`-gDK+I^h`{L=4u|11zo$$Uxp7Zxz=WHzrt$W>UQ9nzOy%T;WbuX zmKNpO=TWzqk4pOThjRSOGK0bbUUO`N9(gam?$gR}CM%ocKc8*a>T+JLdTXm|W>wzq z-P1kbflE&GsPZ6^lC@@_(^g<;)p9kPUsaLYVn3#(fbOn&YQ4-tal7Yrde;*4@ma^hf8#@Z~PL`KM-N1$6p)v`r=&735e?B@Jd65Bv~j}7VF>*R$8E|h&0$CcHMQ7P^$ljRn)m#Wm(6cxZQ1u4*j)@HOQ-0%6EB6(=+dg+9AWVdbb=W| z_H0=0=x#+XX@t_q0hF`XnLaCa5W}`nI(sYc!|NJf*A!CLQ0b(@)bedi!LAYW4v{`1 zQSTg61tkp)?%tUjjEv=NEVtts@(hhMioYqa*tBhEG4U)-mS>CN_tQaFZy34|UagLx zd`cIu539V!B{#u&2UJTU@X>&Z6^r|F{pa)FAVn3o z57(J51mRu{mYS#RmBhYMtsp)}csIShQo5cUSuNWV66tq8=`Ax%j0t=z?`!wABwon^ zSM4*iBF|^ZpMMopn zPrM|eH@4kk9~NHr2Qki#+dors(n~%_x~xqZaE>uAigS&)#5q)~lvridd+_Md9sT9c zHtw@f_jeG-eylQIf3>UghEaWK+7G2rtC`2{IMnvgBs{H4oY3P5!qkZTUhc7T$=Xq- zwD|+^0=L>dRqsdZ(b3$LmF1xY9q0_Z6cw(*B7tK<0h`)0LR~!jWJ?BLaUSCt%pq&{ z-gkb}Q+a-Ib1(FjBY*sSq)!0PR(4qLYq>i{PVu!A1}_v2iMi)<_&ehb_O4sU_PrLM zwZ2i9kZ*^^xol^)9IYjnxko9bpk2fG_UJildjsKlfy~GYy1N$PNmu6dUuY)aOX-lI z><}zGA+3S7BfrkZOt@!)t*Cv~O*vWU&UGZprhD(Nl;C|M)(2l~y}vB$CCbSg?Oa#n zsT%CX)t)RtZS@@ug>H{v-WKD2%R>W2jCD2Z(b(vPa6ws4GU+P2fjY_jwKt`Y2sC=8 zU4+F&DRTFfT`mb{Q{D0)R?qai_+;=iTYNGevY*H&!nCJL;%N_c(v4eiTJGPDZ7f&! zwCJWZ9>yPveo8CKP4v#oTBK~v&S$(^FeGxN zE@EVCG)caXtSurQX8EXTm505d>?0kS+9}@;{p$KU??V;NtkhZGxTcf4tK3zcd~ZCdk>@PJJcLX2?&YrTt$&L+%E0 z`|Udc_X+v`fbYaYVlaq4vC?YC<0!h2G8A=0wbz*6ECA(`>@_r-_C*%gko)(t&s(!h z&|jV8lez`k&}3XDU458<0;T-6sj+nFTY^mwt%WT%w4~X4QS_PVm9Mws{ZY`bFo7r8 z`2?#(%vkTiKrP82C(5;3Fc5^cu^tz4LocY%-IMaY0_)>L`n7mVh_<-3J+)2Fryh=^ z4wp!R!*@!p9P#g}nJ4{4BJ2c8oufB}+Nx{K`_yH1?@${t5lz6ETdrX@58R%4=A4Ah3v>Ex+ zT-I+uqkJaUr6CSZt3zXgPI<)M1KEY;ej+is?y3T{?zAq`&^x2+k0Yxutsn4tWJ6Wx zk>@NKm-Qf~BK~?8W0y6r?)Wa^ZoSl!9FXj5d@ih9s*|kv(xiD9$7Qnv*Wc6OC}z9U zPuFDmwsQjR+i?C+r3-CLqc$-@ZOU_#;9K#{o2UXe(Oz`_IXRBB;FFL0d5JZ6f*`4& z5A9{L#m=giD@L2)gU5F>a??StiOG5N(}$|DNKq?OcM^`0tEV&ui~TFO0$MdTjO0RI zByB|9dX$7h^AH4bcr0Tw%}vGH;Ye;b=qTnpF;#f9AqWFm_7#Tbwj~F~T)L2C-V$mI zwl!|P>U(Yyi|lY{x)ZN`2A5z_v$E}ey?us`ocj&23t=SEEMmU080a%s*T)}n9yhUl zKPY-Ku%4g`Nd??)+SUW!Ls8eIij&+N>%QFNJ`my%KrO9!N>lHdQdv|QzyNZ^q!l}G zO?d9xGLb^EdPp|2mbg3B=K3li_dpv`U4OeY?p9nw5d}p)9pnvjp!)o^*R^#eB33vm|TBUUtgo05ALB> z)X71WcfSU#mAv5S$2}8DJiS;m5;snI_gSD$+PFYwjl*??hsbh z=B~jHzPIS+;$+iy#dE1L=cb`x`3`=5btwcX zJDznpRf#0Nap-Z!DqZ^l7b(xmyzR0X*$i(sGK4aHaaekVc524{TCe8EhJqNilv$oT zw>R85GXu}BGSd1gw4u}aa_XTI2Ddxj+R|}XPL*nw!fBt#^ck?@IWka9k^H2M7H!J4 zk-kzk-YFBmAp@dga^Sp>R3pw>f);!WZycobP6gxfel>3R9V%u)h@1q@`nR$MFD zXV$Hyl=t#hW9FioB6NSe?-8rjc?mg(d$$`H?dZo%p+j#jLL6s+=H;d~Jzvv_-Z~kM zzC_O@Lg1$2%-F8VdSNM-kr31I{$psnmv!Pa64MtM<3L4G|3^3X^Vg7*j)GG*poE&? zt8S4#NBCxXjA|9$?YhiSqHBcj#p`rQzFf45lA)~*Ey%d-^0wT2PsHUuXeOgrDDZ_R z9fW*FFI=;4CvMX2f?Gm^X2471{rHulz~s&}IWzO8Pj)YTxK&T18p+K8Cb+DqK=Y6f zAOuzvz*~vtqo78Hg@?_+ipBxu0!c@b8DVdcE0n*?DJP;^<70BUZ;KY^4Nhx27FV&B z5%K{nZ(~U3npqtTl;2q|mp($y z$v{>nKR83ja~q-OrS(L@r`o`bc-w^x%IQ`-Xe|?2p+~O%73Ljzf-l#$78L8J_)3!$ z@Dzp{u*<7d+DWZk&79(FG>Uz4h1q4-gr|GtggM>M8_XRLO?eIA?IkSwtR##d3iN}E z53oIXATw()(1G$)RWf$`=LXLpgNn$xVcA=mPrehj%94U^QrQ?!M26nfT(=wE_Ysg@ ztLCd4sNTmebe&j}6~MlAFe4pwUe43$akp$KL;3P&A7NHHpS9JI`IS!IP42-KKwB_}zn`c`mhq$)&O_YK=_Ct1H8c^P8!7vr4U;)~Z^> zn;G16ICgViqr#vrr7II_TD5lTq&ul=6ZNaO=CAHNTHBpreN-Wo1u>KF&LUcpTiX{; z9v;$O=xQaos`bIvX7O6{TvV&uG%JiNV zcwO4IVa=i{E|rV3DmT4vc%brO;acde6rQ~qYo^dzU`72vN_K6hrM8xW@yq4L1Wc)- zvhn08(#&tx(AUuIgOXe3$$YOGCzr>NC4dz?w_1~=Ppg(nHP&h3T|Rx#Z2<$G-|jnskt8!yStHuEE=9uU4cm|Uq2aI(_#FMj3dzE2Jf;5zV%wAhfkeb+sTm_kZS zu9=qaDu2`xz;8hh9TS_~Eb?zS|@%P8a~>}B+5vnF04GnF*0GdzbES3keu?SHc~(;$K_%vfA| zbbYn87@fs0?VF>eoE77qk9pMcu1iz}_4|z(t#6;xC!*(^eIN{vQ&QimTjY9oQ0Alf z6On8e6B30Tlpj+gog*A-U0rs7F!@!S-q z=0Asn%=5`b1xeR-Z^cS?*>2N(2vjb4H21vS{cDc@t?w>Uaf&S8FdupXj*J9~NXMQA zU3xjO%d}nx`d0j5v$HGXK~p+-GjbtKAB!uOlb;tB+^)M(62hc4KUBt)ghsecdU)d~ z${WX1w|k40JK^v;*tLr}PitaP?IYoId+sH1d@fn~Xkqh-E8pMZ>8KszU+*0USd+_B zl&*I0njV=}QC5}=*7bhDkNx!$b&cUyhq5l9M+*eF;_p?ifmR^vlTo2Fdbu;uaoX(2 z$2az#a^yu@h!KoMhRk|rH;>3ov@~w9(2+;4x#F1gyo*(=H)OxR6P2z>(a&i5j$k}8 zI65V9#x#~AYUKOslSuCtHGc0mo~i@r7b5L)_mWg*b17ej(~h(rOayu~t*0ImJeXo# zo|#N5!1V(>kTvY+`8kH0Q@^dt&K4NVv1AI>CA9{+++;~Tx^JMz0R7_VK8zNqkX%0x z^|R5H*NL1eBfJ{#5%o&v8e`Hty<6X_DTZ5os<@bs)34cCNco1zd6aTP@E2bt_m`%R zj*pLay1TnGDhO^i8OOL^i7_+fW2%dk6^t}bqtAXTd(GHegn^HTL7<30Nq6J`%e%9R z0x~mWM{HTeQDvooa>%;&7zPU6PNTL!8Bcr01>WhuZ!NW#Qdw3I7ILM}&?2r)Ri*Xn zzRwKn%E5X#6utW3x_74tn)ek?_1;4fk8vzJGRWf!k<77nGS=+Yodd?Z#aBO8bPX1k z=MBGC`Vi}oGrl3q^@i`jwkq{N8QQLgEn*=gwyQVbsr+HIeQk9b<){~zNj}p;HKuxK zK*2#LpLslHEnP}cSBK@hPKQpNH{pS#r_Z|dit>7Ay&j&Yg|{=H%o~+rm3!%GFz5KD z@MHyyB!{1re$GfE!`NP`#{?NK|75)ykeE zP-tFdO&|V*f8T<{0_TdD%R|qR)20h=zF&OS?j%6yC0CcFXUN5{Z}ljzqxlwoO0fDe zStbK*6nS}tCzmlDo9eN#0uz_v?Z(o^n34kqVGd|53`AK)zd*rI7BJq~$RFKau`Wpw zn=#nI`o@mibKN>|T=wwW1$W}t>}2KisMYkDSw{&S!h#SwXzdQ=z7n~++v~(I&8lIJ z=T~>_U8>V}U-CS0e~NrAucaW}kiLGL{UeU^<)bmRrLW$hka!r#Kr4);4HCAhio{fH zd~kDsvm9^l#fDHtbtS|#ld_=t5HEacqCvqQcY0!IAKGP!Cng`AoK?h4PN{<@7;@uU zZTa)p#Z9E`8;|@MZ`fL>ZFbHGj=KhMaei}lg@N8`sV(pvlKLe>h7X`b;?|wD5jzHD zlL{~pwXItb3=~7TC^7&8wJJb1pd_2?gSQ4XeKe9Z>IycgsYB?;NZnyK1uFk{h6K0t3{sfi0 z4aY-b2VxmDDOo&n&;8*1*9Wvx>#@sY>--{^Zeb#3A05Se3rXv~WIJWDJ{iEC+WVdu zJlJ_ZN7iy6x1K2$#h>PYJ>&7FmO$n_?(pRue?U45y(c!=OPK~H*aesd@6Gp(QAcjA zt@v_sfr%82_f*$o4N)~-#(#}?A0vC!#wTF>y1c+t%1bUKZDK*bX}Ypf2ecT;I>jq0 zcO0~iFg(A4P)G5j!iCm_eW66_EJ-PH+?91@Hf=H4Ojw#gKfl`~b3VO6l#0xS07)vC z{_VNb4{njqWW>apOdQZGZTd5(!!Iqydf?XTpiXTKrSv3+97x}-+K4!OBA)p{mZTNG z;%T5jG@g2Xg`S05=5Lw14eXBiRy+YTh02!A?-Ldzins1Q7TkyVBBuVyYpb8$X(cO z2yoqQ^`R4Cv07)GRE%K_6(%bW7jO>hIi5r!e_gAlGt4vM@FxqGXG9h_5S8GI8KA zbN7KAzh2(a2e%OFoyIw%CgN|iN2|4!=HC6)Yue%d)kswrihZk1ZG`)6?y7?a^@bNj zhF;MH)@3t9e;L0Q_P!K55W`?Y?lyURONIQN%{s}L^3+6NiiP237Hjqk@d|fewwR1O z!Va-~bOQD(*Ljcy?(ljH&EA{6x_IkuvDEi)ezFH)Nw=KV?pY`~s5+$LXlV7XLeXv} z1~c{ulhFgC+LbCiPidQTt!irx$r-vs5QTagaCMNbT5<4qB)Y*>5<>l~wSv5qjjSc? z_LjG8F9dX{)_5V0%&t=S#Ljrp&`%L%v%aLLwoJ=JFSd{7crSV`BR*f^Vv4q*9&1)? ztuR-i6{!xbZgJ$2Ot5uw8_26%L26W8OctX_eU)A0e86xwF?kcJT8JQB1_ZNS^UdR| zZ?6JEJ}wkH3|f+S9hHyhsB25iUJFovjrLT+*~C~MYh{a8kP{gsM3-RFX~3C4W21Ru*`7^n-}2|b8| zfkNKmYOW_7;;&8@`-vEbqkB60VCan>-dKP1iqXrv3;pBrcbc*Xs=kv9%$UR%ty#`B zk=ZbbKVG+lmibH$hFz+yuU-?Y4$!nsHZb!_UbM*?(b3SBxL#ZmAb)pVmrlCL$>iFt zBGL1HulA&82z+wYYDAt2b9Q;7ee=mp4Vn&+%{r7cS!bE3%^O^Z?LfBa&RWgVFDZ{G zz24e>fRXS_SDlc4lCp!Nq2oi1dInZ5^5d0uaJ8w=WT6kHj|ui=C_3NdDjBpxyk?xb z7w}&sL<`=w60ow8n{u$uYA%W#?v*ACy`^aFJ4E})mnmefw4U`Atq!0wPRdqFccxQg5@V?EouF=<5ldbUw|fyJd(TjFPTuHn^^ z)_rF$B)@Ru8_%c+i8lk#)A*|`vO_Pc@kb{IyX9?ki29_Pmt9Xz+Kb3M zH_VA7LX;~8EPW0V6)~)7cmqfCW$*>Ob zbGE&R(WcoKF{XT1Uq_lJKD_o6>h|Glv4*xN16KF^>{Tb;?cFrs`{P0K*+=A`x|{y7 zy9=0&gZmG6)4y!N@}Kk3`>VSte4iBrXZ!!oE5%6vCR!j2CK5{h1SK?sRD}o9OWpvY z1fJA*!myvv0_s6set0Dz%vXu+9tfmi-&XlgR#g7j(}kP;PoaN}k1gVA%Go|Kf2^kb zgU9V}$Hd=`iGRCe;>l{t@rufS|M}; zAElNvPd`Lz`5*iF{jY@n3$>hvJNScI{=w((H?{nxmj8>X<;)}EFVylsc8K_2^|HTO zEoVC{ojptN-&4!)upl zv+m!{y1zq<{0=ShJG99EZ$pc)|FMfBVr&t1j$bqV@ekJ1KTLT1wx0fmpls|MX9M-W zSWmzHIbC=YM0ie@SmB6c5!|#Q|pm6?9fd$0<%K_@1~YXL5q6fcM!oIr*r7_gM)-{9;t#Y4q?3Lxzzi_H2p$Shb%00IF2&YPbyY$I+_y_d@wh>R+3uwU8#>@F-_uD?=Ea@W|acAJ>R%neYEaF znXm(ct%S3hayDQE?`pnO54OPE>n;^(zS{1Yk4>NusXScUKt9@p_&`_YFE8Qm zy=tV~73otKJPL^rS(`YTn$`2!geV_az$O$}Ct$631J#G$S-02c6?{DQs-zDM#V=^B z7nTG%x-fRc81AXpmoo1YAP;|Qy7r!Vc)6uesE_%w0yVgNl3svJZ6to^)(6uDq;mf6 z9Nvag>ksChMi#qd_Cc(z7?BP$ork3OC9rY%gD12<3g1Wa$n`#45vd+*gb9t#BrN#A zjv&Q8JmHN#hw=t@l8f*3L7TgSlhQiFXWehkOFJ82vKw=THIlRtd17t4BfD^CAEmJ! zdA*a9VlX)=C)8{uw$ODaJxp(weqqzdox;=mkzbnqyjOEv5;#?R#9o`W$0MyO$RRu5v%G9FV(``Yb77=s)4t|sEx}yi1jMxxFlx4`${+9_eo<%YV32-Dq8ev z8gSvBi&+OUeW>J7usOUTt!rN(j4NC%A+C9k7F$s0dm=S+#&|o)V;8c4Cyw(K=)Fd^ zHSSv3D~lBsyl|O>(}x>nLhGL&I_ZQa_qRt3-Qmu9ibLV~#tPR(<-sQ<7v8MAz*oiU z3*RS)v!0fR!ZZ$?SC*7Xs~eQMHgT3VCpYC1Nn<|7L|(VK&GPtT%3@C;c_a7qD8JpU zr@cP>vB0ekOHOX3+nFk1ccFj4nBtw{t_`-%q&jK6?ziB1?X;~{ksAVIk^=b37KQfg zc6^tuvR5#qm+x!aD7eTy%`V(8iFK)S@ApE$Js$18Gv$))eVVj5Q1Hk?D+r>tM?VIaWALNd_ z21_S8XH>GsZH_0KrjkIu2A39Dk>$49)4jGMb9}P-;V5IrJwxdAM3Sjz=gr$5QJ!6e zp>_QB*o_W*DWCb(!h2#yRk9ER7svLF>vsxvz_2P=RH@NR=&x8dUL;e{+gh2bln_FD8QDXfE{Jp?$G

    T{CM?h| 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 diff --git a/tests/trnsysGUI/data/diagramForRegimes/expectedPDFs/diagramForRegimes_name1.pdf b/tests/trnsysGUI/data/diagramForRegimes/expectedPDFs/diagramForRegimes_name1.pdf index e75c2966c0ace410e92d6664274dcb255b3dc6bb..c58105fd0faff41060b9df990856a601a740344b 100644 GIT binary patch delta 18 ZcmbPqm2uKl#tGT1W+vvQMjH#1vH(O_28I9t delta 18 ZcmbPqm2uKl#tGT1rp6{Fh8qi%vH(OU27dqm diff --git a/tests/trnsysGUI/data/diagramForRegimes/expectedPDFs/diagramForRegimes_name1.svg b/tests/trnsysGUI/data/diagramForRegimes/expectedPDFs/diagramForRegimes_name1.svg index a00f9b97..3dcfa7c1 100644 --- a/tests/trnsysGUI/data/diagramForRegimes/expectedPDFs/diagramForRegimes_name1.svg +++ b/tests/trnsysGUI/data/diagramForRegimes/expectedPDFs/diagramForRegimes_name1.svg @@ -13,1908 +13,3316 @@ font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="norm > - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Pump4_Tee26 + + + + + + + + + + + + + + + + + + + + + +M = 500.0 kg/h, T: 1.2°C + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + - - - - + - - - + - - - - + - - - + - - - - - - - - - - - - - - - - - - + - - - - - - + - - - - - - - + - - - - + - - - - - - - - - - - - - - - - - - + - + - - - - - - + - - - - - - - + - - - - - - - + - - - - + - - - + - - - - - - - - - - - - - - - - - - + - - - - - - + - - - - - - - + - - - - - + - - - - - - - - - - - - - - - - - - + - + - - - - - - + - - - - - - + - - - - - + - - - - + - - - - + - - - + - + - - + + + + + + + + + + + + + + + + + - + - + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + - + - + - - + - + - + - - + - + - + - - + - + - + - - + - + - + + + + + - - - - - - + - - - - + - - - - - - - - - - - - - - - - + - + - + - - + - + - + - - + - + - + - - + - + - + - - + - + - + - - + - + - + - - + - + - + - - + - + - + - - + - + - + - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - + - - - - + - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - + - - - - + - - - - + - - - - + - - - - + - + - + - - + - + - + - - + - + - + - - - - - - + - - - - + - - - - + - - - - + - - - - + - + - + - - + - + - + - - + - + - + - - - - - - + - - - - + - - - - + + + + + + + + + + + - diff --git a/tests/trnsysGUI/data/diagramForRegimes/expectedPDFs/diagramForRegimes_name2.pdf b/tests/trnsysGUI/data/diagramForRegimes/expectedPDFs/diagramForRegimes_name2.pdf index 33328c89d4d31355137b8a92c72e6dbd22c63d45..ba688164076cc8428328a765ad4e930bcd6fc8d1 100644 GIT binary patch literal 27356 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 A`v3p{ literal 33092 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 diff --git a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py index 77adc887..58c0b27c 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py +++ b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py @@ -101,7 +101,7 @@ def _adjustPumpsAndValves(pumpsAndValves, regimeRow, pumpTapPairs, mainTaps) -> blockItemName = blockItem.displayName desiredValue = regimeRow[blockItemName] if isinstance(blockItem, _pump.Pump): - blockItem.massFlowRateInKgPerH = desiredValue + blockItem._massFlowRateInKgPerH = desiredValue if pumpTapPairs and (blockItemName in pumpTapPairs): associatedTap = pumpTapPairs[blockItemName] mainTaps[associatedTap].massFlowRateInKgPerH = desiredValue From c35c8be65bb52e07d0fe9aa39889dc6e69ebd50f Mon Sep 17 00:00:00 2001 From: ahobeost Date: Wed, 26 Jun 2024 21:41:38 +0200 Subject: [PATCH 43/56] Fixed last test. --- .../diagramWithTapForRegimes_dummy_regime.pdf | Bin 8899 -> 4357 bytes .../testPrintRegimesAndCopyFiles.py | 16 +++++++++++++--- .../renderDiagramOnPDFfromPython.py | 10 +++++++--- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/tests/trnsysGUI/data/diagramWithTapForRegimes/expectedPDFs/diagramWithTapForRegimes_dummy_regime.pdf b/tests/trnsysGUI/data/diagramWithTapForRegimes/expectedPDFs/diagramWithTapForRegimes_dummy_regime.pdf index dc98b4b40cfd13a70ab180f5818f1413a5f7867d..965bcc9068307b8ab3abe0a16317f1560a7abffd 100644 GIT binary patch delta 3507 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 Q^r3J=kQfAFhBg=bKR2MUA^-pY literal 8899 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

      x<`VbWEXC+U$r>gv|DZQ%w0k9R-VsR{ zK--R=MJc|5SvT{*gb~-TrpDySciw)mb0ga`87srY;VyaC80burn%Z+hJfGdCR9$hA zq@m{cv~6dL9bEL;# zt;M|VOzGBkeHwO|Qqp^mYW1zWaeds77S(#nLF%Hft+%M70c_VJa=ecgJ0)9>eD@7hQK-JQ(n)$JqILfAqU*nsI`F7Bv1WaxpqJ zemLHtIQ_;|(`=8gCXH1cp&U7ZHNEnRVevGqhKa0A$%)W+K6SUN>s_8@spk-)K+8s- z4YiMNXnZSbVihBgQ0aX0%4VTbvaX{ka=?n()Qjd9-i;)U3+V#ZbvYYK(cn)z%N~+2FfZDwrsZ?1s?kX!eE$4r?t0I|H1B2ixX;yTB2nBW$Ne>Sv~w6@0L4w zLdSPmfwxH+-m*idLgSb?H;yjnlcDub#-)<3`B1*!MjH}^Zur;^pQAriL&xTY`MSy8 zeRM94JysqTd7!7scE&pY8_cJ?rndT$K%JGHvst)ev1s-=F6Z`|baCemjagQ>Pe=M< zf}3}{+wW<^%14OoZJ9xH7yr?{(Ie+8YRA#ADBQcCh>^V_H}kkNsC#d1Z{Byo-cqGr zCp2W(aj9al-U{cG?p_0pA6Izgez-tw)~Zo^Z`i}}F}3HU0S3JDklfK8+gNd2WRgYf z_@T}`99Q73sOmocsCS{b+ciSn^Wd$36Llie z1+ePfncbuJPIG67$kzJBnvS0{a4;9E_a4@)xG;m=ODM1DRi%3tP(#T=o9A*pMD3ce zoM>{|SDIEm3EwEUrH+@;B`wVvI zPMj)Fq<0Cg?Ct2uEOnjhw#lF8G*gaY7he6b zXD|Zvi_hbN*W^>P`up#XyJ-g#W!@01o24|2(NO~`br$5V8C9yr;}`98AXGA)eMaA% z7}2gTG`Sw4Fc?T|$-7*0s4u2k&{wo17S#+0*m&P2!zYE`BTd}-5w+d+TM5soTcehj ziZG#mYmIOLA;MInG1<_gUPMao5>CA6eJa_0SvsmoleaW(Nd2DPW%gl#@#KIKUaHB# z%;zS+R)L#!0V}|l#Z)cZ*Um4zU2Lk5+P!E`XVl-WuQGfDHEW``+IM;HQEHPKourOK=DB%Am*3vL*Xv!!Mzy8jv zj8a}p!zizjSs8;~Lqnr6Yvcof{u=qPC=dewzAnJJW*lJBUuYDvBf%9w#4U blockItem._massFlowRateInKgPerH = desiredValue if pumpTapPairs and (blockItemName in pumpTapPairs): associatedTap = pumpTapPairs[blockItemName] - mainTaps[associatedTap].massFlowRateInKgPerH = desiredValue + if isinstance(associatedTap, list): + for tap in associatedTap: + mainTaps[tap]._massFlowRateInKgPerH = desiredValue + else: + mainTaps[associatedTap]._massFlowRateInKgPerH = desiredValue elif isinstance(blockItem, _tv.TVentil): blockItem.positionForMassFlowSolver = desiredValue else: From 5d1db426b371a3a0201c7fd5f9b60a404b57847c Mon Sep 17 00:00:00 2001 From: ahobeost Date: Wed, 26 Jun 2024 22:04:52 +0200 Subject: [PATCH 44/56] Changes for CI --- .../testExportRegimeTemplate.py | 2 +- .../testPrintRegimesAndCopyFiles.py | 50 +++++++++++-------- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py index 42c05374..fc7e0736 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py @@ -1,5 +1,5 @@ -import pandas as _pd import pathlib as _pl +import pandas as _pd import trnsysGUI as _GUI import trnsysGUI.pythonInterface.regimeExporter.exportRegimes as _er diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py index 5062c643..796c1d0c 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py @@ -1,9 +1,8 @@ import dataclasses as _dc -import matplotlib.testing.compare as _mpltc # type: ignore[import] import os as _os import pathlib as _pl -import pytest as _pt import typing as _tp +import matplotlib.testing.compare as _mpltc # type: ignore[import] import pytrnsys.utils.log as _ulog @@ -144,19 +143,25 @@ def testUsingQtBot(self, qtbot): regimeExporter = _rdopfp.RegimeExporter(_PROJECT_NAME, _DATA_DIR, _RESULTS_DIR, _REGIMES_FILENAME, mainWindow) regimeExporter.export() - files_to_compare = {'new_file': [_NEW_DIAGRAM_PATH, _NEW_NAME1_PATH, _NEW_NAME1_SVG_PATH, _NEW_NAME2_PATH], - 'expected_file': [_EXPECTED_DIAGRAM_PATH, _EXPECTED_NAME1_PATH, _EXPECTED_NAME1_SVG_PATH, - _EXPECTED_NAME2_PATH]} + filesToCompare = { + "new_file": [_NEW_DIAGRAM_PATH, _NEW_NAME1_PATH, _NEW_NAME1_SVG_PATH, _NEW_NAME2_PATH], + "expected_file": [ + _EXPECTED_DIAGRAM_PATH, + _EXPECTED_NAME1_PATH, + _EXPECTED_NAME1_SVG_PATH, + _EXPECTED_NAME2_PATH, + ], + } errors = [] - for i, new_file in enumerate(files_to_compare['new_file']): + for i, newFile in enumerate(filesToCompare["new_file"]): try: - self._fileExistsAndIsCorrect(new_file, files_to_compare['expected_file'][i]) - except AssertionError as current_error: - errors.append(current_error) + self._fileExistsAndIsCorrect(newFile, filesToCompare["expected_file"][i]) + except AssertionError as currentError: + errors.append(currentError) if errors: - raise Exception(errors) + raise ExceptionGroup("multiple errors", errors) @staticmethod def _fileExistsAndIsCorrect(producedFile, expectedFile): @@ -172,21 +177,21 @@ def testUsingQtBotForGivenRegimes(self, qtbot): errors = [] try: self._fileExistsAndIsCorrect(_NEW_NAME1_PATH_2, _EXPECTED_NAME1_PATH) - except AssertionError as current_error: - errors.append(current_error) + except AssertionError as currentError: + errors.append(currentError) try: assert not _NEW_DIAGRAM_PATH_2.is_file() - except AssertionError as current_error: - errors.append(current_error) + except AssertionError as currentError: + errors.append(currentError) try: assert not _NEW_NAME2_PATH_2.is_file() - except AssertionError as current_error: - errors.append(current_error) + except AssertionError as currentError: + errors.append(currentError) if errors: - raise Exception(errors) + raise ExceptionGroup("multiple errors", errors) def testUsingQtBotForRegimeWithTap(self, qtbot): pumpTapPairs = {"Pump5": ["WtSp1", "WtTp3"]} @@ -211,16 +216,17 @@ def testUsingQtBotForRegimeWithTap(self, qtbot): errors = [] try: self._fileExistsAndIsCorrect(pathFinder2.newPdfPath, pathFinder2.expectedPdfPath) - except AssertionError as current_error: - errors.append(current_error) + except AssertionError as currentError: + errors.append(currentError) pathFinder2.setFileEnding("_diagram") try: assert not pathFinder2.newPdfPath.is_file() - except AssertionError as current_error: - errors.append(current_error) + except AssertionError as currentError: + errors.append(currentError) if errors: - raise Exception(errors) + raise ExceptionGroup("multiple errors", errors) + # non-qtbot solution? From 88b24de34ac3c339dcca61d1fb0015a30bf58122 Mon Sep 17 00:00:00 2001 From: ahobeost Date: Tue, 2 Jul 2024 12:50:16 +0200 Subject: [PATCH 45/56] Made massFlowRateInKgPerH public --- trnsysGUI/pumpsAndTaps/_pumpsAndTabsBase.py | 10 +++++----- trnsysGUI/pumpsAndTaps/pump.py | 2 +- trnsysGUI/pumpsAndTaps/tap.py | 2 +- trnsysGUI/pumpsAndTaps/tapMains.py | 2 +- .../regimeExporter/renderDiagramOnPDFfromPython.py | 6 +++--- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/trnsysGUI/pumpsAndTaps/_pumpsAndTabsBase.py b/trnsysGUI/pumpsAndTaps/_pumpsAndTabsBase.py index 6cbe826c..4795b21a 100644 --- a/trnsysGUI/pumpsAndTaps/_pumpsAndTabsBase.py +++ b/trnsysGUI/pumpsAndTaps/_pumpsAndTabsBase.py @@ -25,7 +25,7 @@ def __init__(self, trnsysType: str, editor, displayName: str) -> None: self.w = 40 self.h = 40 - self._massFlowRateInKgPerH = _defaults.DEFAULT_MASS_FLOW_RATE + self.massFlowRateInKgPerH = _defaults.DEFAULT_MASS_FLOW_RATE @classmethod @_tp.override @@ -60,7 +60,7 @@ def _createBlockItemWithPrescribedMassFlowForEncode(self) -> _ser.BlockItemWithP blockItemWithPrescribedMassFlowModel = _ser.BlockItemWithPrescribedMassFlowBaseModel( blockItemModel, - self._massFlowRateInKgPerH, + self.massFlowRateInKgPerH, ) return blockItemWithPrescribedMassFlowModel @@ -71,10 +71,10 @@ def _applyBlockItemModelWithPrescribedMassFlowForDecode( blockItemModel = blockItemWithPrescribedMassFlow.blockItem self._decodeBaseModel(blockItemModel) - self._massFlowRateInKgPerH = blockItemWithPrescribedMassFlow.massFlowRateInKgPerH + self.massFlowRateInKgPerH = blockItemWithPrescribedMassFlow.massFlowRateInKgPerH def mouseDoubleClickEvent(self, event: _qtw.QGraphicsSceneMouseEvent) -> None: - dialogModel = _dialog.Model(self.displayName, self.flippedH, self.flippedV, self._massFlowRateInKgPerH) + dialogModel = _dialog.Model(self.displayName, self.flippedH, self.flippedV, self.massFlowRateInKgPerH) maybeCancelled = _dialog.Dialog.showDialogAndGetResult(dialogModel, self._renameHelper) if _cancel.isCancelled(maybeCancelled): @@ -87,4 +87,4 @@ def mouseDoubleClickEvent(self, event: _qtw.QGraphicsSceneMouseEvent) -> None: self.setDisplayName(newDialogModel.name) self.updateFlipStateH(newDialogModel.isHorizontallyFlipped) self.updateFlipStateV(newDialogModel.isVerticallyFlipped) - self._massFlowRateInKgPerH = newDialogModel.massFlowRateKgPerH + self.massFlowRateInKgPerH = newDialogModel.massFlowRateKgPerH diff --git a/trnsysGUI/pumpsAndTaps/pump.py b/trnsysGUI/pumpsAndTaps/pump.py index bf71c13d..a366c9db 100644 --- a/trnsysGUI/pumpsAndTaps/pump.py +++ b/trnsysGUI/pumpsAndTaps/pump.py @@ -50,7 +50,7 @@ def _getImageAccessor(cls) -> _img.SvgImageAccessor: # pylint: disable=argument return _img.PUMP_SVG def _getCanonicalMassFlowRate(self) -> float: - return self._massFlowRateInKgPerH + return self.massFlowRateInKgPerH def encode(self) -> _tp.Tuple[str, _dcj.JsonDict]: blockItemWithPrescribedMassFlowModel = self._createBlockItemWithPrescribedMassFlowForEncode() diff --git a/trnsysGUI/pumpsAndTaps/tap.py b/trnsysGUI/pumpsAndTaps/tap.py index 3cb75231..ccd76173 100644 --- a/trnsysGUI/pumpsAndTaps/tap.py +++ b/trnsysGUI/pumpsAndTaps/tap.py @@ -23,7 +23,7 @@ def _getImageAccessor(cls) -> _img.SvgImageAccessor: # pylint: disable=argument return _img.TAP_SVG def _getCanonicalMassFlowRate(self) -> float: - return -self._massFlowRateInKgPerH + return -self.massFlowRateInKgPerH def exportPipeAndTeeTypesForTemp(self, startingUnit: int) -> _tp.Tuple[str, int]: fromAdjacentHasPiping = _hecom.getAdjacentConnection(self._graphicalPortItem) diff --git a/trnsysGUI/pumpsAndTaps/tapMains.py b/trnsysGUI/pumpsAndTaps/tapMains.py index 85b392ef..8d001c36 100644 --- a/trnsysGUI/pumpsAndTaps/tapMains.py +++ b/trnsysGUI/pumpsAndTaps/tapMains.py @@ -22,7 +22,7 @@ def _getImageAccessor(cls) -> _img.SvgImageAccessor: # pylint: disable=argument return _img.TAP_MAINS_SVG def _getCanonicalMassFlowRate(self) -> float: - return self._massFlowRateInKgPerH + return self.massFlowRateInKgPerH def exportPipeAndTeeTypesForTemp(self, startingUnit: int) -> _tp.Tuple[str, int]: temperatureVariable = _temps.getTemperatureVariableName( diff --git a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py index a2d0f527..40a8de97 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py +++ b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py @@ -101,14 +101,14 @@ def _adjustPumpsAndValves(pumpsAndValves, regimeRow, pumpTapPairs, mainTaps) -> blockItemName = blockItem.displayName desiredValue = regimeRow[blockItemName] if isinstance(blockItem, _pump.Pump): - blockItem._massFlowRateInKgPerH = desiredValue + blockItem.massFlowRateInKgPerH = desiredValue if pumpTapPairs and (blockItemName in pumpTapPairs): associatedTap = pumpTapPairs[blockItemName] if isinstance(associatedTap, list): for tap in associatedTap: - mainTaps[tap]._massFlowRateInKgPerH = desiredValue + mainTaps[tap].massFlowRateInKgPerH = desiredValue else: - mainTaps[associatedTap]._massFlowRateInKgPerH = desiredValue + mainTaps[associatedTap].massFlowRateInKgPerH = desiredValue elif isinstance(blockItem, _tv.TVentil): blockItem.positionForMassFlowSolver = desiredValue else: From e1d823676923609906b946cb1f344b113208133a Mon Sep 17 00:00:00 2001 From: ahobeost Date: Tue, 2 Jul 2024 12:58:50 +0200 Subject: [PATCH 46/56] Adjustments for CI --- trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py b/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py index 65dc5cdd..59101e1f 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py +++ b/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py @@ -22,8 +22,8 @@ def getPumpsAndValvesWithValuesFromJson(projectJson): if "BlockName" in curDict: curBlockName = curDict["BlockName"] if curBlockName == "Pump": - curPump = _pu._PumpModelVersion1.from_dict(curDict) - data[curPump.BlockDisplayName] = curPump.massFlowRateInKgPerH + curPump = _pu.PumpModel.from_dict(curDict) + data[curPump.BlockDisplayName] = curPump.blockItemWithPrescribedMassFlow.massFlowRateInKgPerH elif curBlockName == "TVentil": desiredValueName = "PositionForMassFlowSolver" data = getData(curDict, data, desiredValueName) From b905717a28f148cf80699dd11766d3edc5861825 Mon Sep 17 00:00:00 2001 From: ahobeost Date: Tue, 2 Jul 2024 13:34:44 +0200 Subject: [PATCH 47/56] Added taps to inputs csv and refactoring --- .../data/diagramWithTapForRegimes/regimes.csv | 6 +-- .../testPrintRegimesAndCopyFiles.py | 3 +- .../regimeExporter/exportRegimes.py | 22 ++++++----- .../regimeExporter/getDesiredRegimes.py | 13 ------- .../renderDiagramOnPDFfromPython.py | 39 ++++++++----------- 5 files changed, 32 insertions(+), 51 deletions(-) diff --git a/tests/trnsysGUI/data/diagramWithTapForRegimes/regimes.csv b/tests/trnsysGUI/data/diagramWithTapForRegimes/regimes.csv index 24c664d5..f0076ecc 100644 --- a/tests/trnsysGUI/data/diagramWithTapForRegimes/regimes.csv +++ b/tests/trnsysGUI/data/diagramWithTapForRegimes/regimes.csv @@ -1,3 +1,3 @@ -regimeName,Pump5 -dummy_regime,500.0 -other_regime,600.0 +regimeName,Pump5,WtSp1,WtTp3 +dummy_regime,500.0,500.0,500.0 +other_regime,600.0,600.0,600.0 diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py index 796c1d0c..66d25a3f 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py @@ -194,7 +194,6 @@ def testUsingQtBotForGivenRegimes(self, qtbot): raise ExceptionGroup("multiple errors", errors) def testUsingQtBotForRegimeWithTap(self, qtbot): - pumpTapPairs = {"Pump5": ["WtSp1", "WtTp3"]} onlyTheseRegimes = ["dummy_regime"] projectName = "diagramWithTapForRegimes" regimeEnding = "_dummy_regime" @@ -211,7 +210,7 @@ def testUsingQtBotForRegimeWithTap(self, qtbot): mainWindow = _createMainWindow(dataDir, projectName, qtbot) regimeExporter = _rdopfp.RegimeExporter(projectName, dataDir, resultsDir, _REGIMES_FILENAME, mainWindow) - regimeExporter.export(pumpTapPairs=pumpTapPairs, onlyTheseRegimes=onlyTheseRegimes) + regimeExporter.export(onlyTheseRegimes=onlyTheseRegimes) errors = [] try: diff --git a/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py b/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py index 59101e1f..76d54260 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py +++ b/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py @@ -17,16 +17,18 @@ def getPumpsAndValvesWithValuesFromJson(projectJson): data = {} undesiredBlocks = [".__BlockDct__", "IDs", "Strings"] for block in jsonValues["Blocks"]: - if block not in undesiredBlocks: - curDict = jsonValues["Blocks"][block] - if "BlockName" in curDict: - curBlockName = curDict["BlockName"] - if curBlockName == "Pump": - curPump = _pu.PumpModel.from_dict(curDict) - data[curPump.BlockDisplayName] = curPump.blockItemWithPrescribedMassFlow.massFlowRateInKgPerH - elif curBlockName == "TVentil": - desiredValueName = "PositionForMassFlowSolver" - data = getData(curDict, data, desiredValueName) + if block in undesiredBlocks: + continue + + curDict = jsonValues["Blocks"][block] + if "BlockName" in curDict: + curBlockName = curDict["BlockName"] + if curBlockName == "Pump": + curPump = _pu.PumpModel.from_dict(curDict) + data[curPump.BlockDisplayName] = curPump.blockItemWithPrescribedMassFlow.massFlowRateInKgPerH + elif curBlockName == "TVentil": + desiredValueName = "PositionForMassFlowSolver" + data = getData(curDict, data, desiredValueName) pumpsAndValvesAndValues = _pd.DataFrame(data, index=["dummy_regime"]) pumpsAndValvesAndValues.index.name = "regimeName" return pumpsAndValvesAndValues diff --git a/trnsysGUI/pythonInterface/regimeExporter/getDesiredRegimes.py b/trnsysGUI/pythonInterface/regimeExporter/getDesiredRegimes.py index 4e7ce141..e77e823b 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/getDesiredRegimes.py +++ b/trnsysGUI/pythonInterface/regimeExporter/getDesiredRegimes.py @@ -1,7 +1,5 @@ import pandas as _pd -# dealing with files where the regimeName column is not provided correctly - def getRegimesFromFile(fileName): table = _pd.read_csv(fileName) @@ -11,17 +9,6 @@ def getRegimesFromFile(fileName): raise ValueError(f"Column name '{colName}' not found.") -# error handling? -# - will throw "fileNotFoundError" as it is. -# -# -# regimeName, name1, name2, name3 -# regime, value1, value2, value3 -# -# if isPump(name): -# if isValve(name): - - def getRegimes(filePath, onlyTheseRegimes): regimeValues = getRegimesFromFile(filePath) regimeValues = regimeValues.set_index("regimeName") diff --git a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py index 40a8de97..294884a0 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py +++ b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py @@ -37,17 +37,17 @@ def temperaturesPrintFilePath(self): return self.projectDir / temperaturesPintFileName def export( - self, pumpTapPairs: _tp.Optional[_tp.Dict] = None, onlyTheseRegimes: _tp.Optional[_tp.Sequence[str]] = None + self, onlyTheseRegimes: _tp.Optional[_tp.Sequence[str]] = None ) -> None: if not onlyTheseRegimes: self._makeDiagramFiles() regimeValues = _gdr.getRegimes(self.projectDir / self.regimesFileName, onlyTheseRegimes) - pumpsAndValvesNames = list(regimeValues.columns) - pumpsAndValves, mainTaps = self.getPumpsAndValvesAndMainTaps(pumpsAndValvesNames) + pumpsAndValvesAndTapsNames = list(regimeValues.columns) + pumpsAndValvesAndTaps = self.getPumpsAndValvesAndMainTaps(pumpsAndValvesAndTapsNames) - self._simulateAndVisualizeMassFlows(mainTaps, pumpTapPairs, pumpsAndValves, regimeValues) + self._simulateAndVisualizeMassFlows(pumpsAndValvesAndTaps, regimeValues) def _makeDiagramFiles(self, regimeName="diagram") -> None: pdfName = self.resultsDir / f"{self.projectName}_{regimeName}.pdf" @@ -56,24 +56,21 @@ def _makeDiagramFiles(self, regimeName="diagram") -> None: self._printDiagramToSVG(svgName) def getPumpsAndValvesAndMainTaps(self, pumpsAndValvesNames): - pumpsAndValves = [] - mainTaps = {} + pumpsAndValvesAndTaps = [] blockItemsAndConnections = self.mainWindow.editor.trnsysObj for blockItem in blockItemsAndConnections: - if isinstance(blockItem, (_pump.Pump, _tv.TVentil)): + if isinstance(blockItem, (_pump.Pump, _tv.TVentil, _tb.TapBase)): if blockItem.displayName in pumpsAndValvesNames: - pumpsAndValves.append(blockItem) - elif isinstance(blockItem, _tb.TapBase): - mainTaps[blockItem.displayName] = blockItem + pumpsAndValvesAndTaps.append(blockItem) - return pumpsAndValves, mainTaps + return pumpsAndValvesAndTaps - def _simulateAndVisualizeMassFlows(self, mainTaps, pumpTapPairs, pumpsAndValves, regimeValues) -> None: + def _simulateAndVisualizeMassFlows(self, pumpsAndValvesAndTaps, regimeValues) -> None: for regimeName in regimeValues.index: regimeRow = regimeValues.loc[regimeName] - self._adjustPumpsAndValves(pumpsAndValves, regimeRow, pumpTapPairs, mainTaps) + self._adjustPumpsAndValves(pumpsAndValvesAndTaps, regimeRow) exception = runMassFlowSolver(self.mainWindow) @@ -95,22 +92,18 @@ def _simulateAndVisualizeMassFlows(self, mainTaps, pumpTapPairs, pumpsAndValves, massFlowSolverVisualizer.close() @staticmethod - def _adjustPumpsAndValves(pumpsAndValves, regimeRow, pumpTapPairs, mainTaps) -> None: + def _adjustPumpsAndValves(pumpsAndValvesAndTaps, regimeRow) -> None: - for blockItem in pumpsAndValves: + for blockItem in pumpsAndValvesAndTaps: blockItemName = blockItem.displayName desiredValue = regimeRow[blockItemName] - if isinstance(blockItem, _pump.Pump): + + if isinstance(blockItem, (_pump.Pump, _tb.TapBase)): blockItem.massFlowRateInKgPerH = desiredValue - if pumpTapPairs and (blockItemName in pumpTapPairs): - associatedTap = pumpTapPairs[blockItemName] - if isinstance(associatedTap, list): - for tap in associatedTap: - mainTaps[tap].massFlowRateInKgPerH = desiredValue - else: - mainTaps[associatedTap].massFlowRateInKgPerH = desiredValue + elif isinstance(blockItem, _tv.TVentil): blockItem.positionForMassFlowSolver = desiredValue + else: raise AssertionError(f"Encountered blockItem of type {blockItem}, instead of a pump or a Valve") From b050e489b142d1b05586e5e86721e6aacb0bf78a Mon Sep 17 00:00:00 2001 From: ahobeost Date: Tue, 2 Jul 2024 14:47:25 +0200 Subject: [PATCH 48/56] Added Taps to possible regime.csv inputs. --- .../diagramWithTapForRegimes.json | 111 ++++++++++-------- .../expectedCSVs/expectedRegimeTemplate.csv | 2 + .../testExportRegimeTemplate.py | 24 ++-- .../testPrintRegimesAndCopyFiles.py | 1 + .../regimeExporter/exportRegimes.py | 12 +- 5 files changed, 84 insertions(+), 66 deletions(-) create mode 100644 tests/trnsysGUI/data/diagramWithTapForRegimes/expectedCSVs/expectedRegimeTemplate.csv diff --git a/tests/trnsysGUI/data/diagramWithTapForRegimes/diagramWithTapForRegimes.json b/tests/trnsysGUI/data/diagramWithTapForRegimes/diagramWithTapForRegimes.json index 4e2860e3..8adc5b40 100644 --- a/tests/trnsysGUI/data/diagramWithTapForRegimes/diagramWithTapForRegimes.json +++ b/tests/trnsysGUI/data/diagramWithTapForRegimes/diagramWithTapForRegimes.json @@ -5,63 +5,70 @@ ".__BlockDict__": true, "BlockDisplayName": "WtSp1", "BlockName": "WTap_main", - "Id": 1, - "__version__": "bbc03f36-d1a1-4d97-a9c0-d212ea3a0203", - "blockPosition": [ - -85.0, - -303.0 - ], - "flippedH": false, - "flippedV": false, - "portsIdsIn": [], - "portsIdsOut": [ - 2 - ], - "rotationN": 0, - "trnsysId": 1 + "__version__": "14afd9a0-54d6-44c7-b147-c79af3b782bb", + "blockItemWithPrescribedMassFlow": { + "__version__": "e9fd1a0e-c00a-46e2-abfb-7381fa1b2e2d", + "blockItem": { + "__version__": "7b792574-5fa6-4c3e-b2e3-7e4eb71d7746", + "blockPosition": [ + -85.0, + -303.0 + ], + "flippedH": false, + "flippedV": false, + "rotationN": 0, + "trnsysId": 1 + }, + "massFlowRateInKgPerH": 1000.0 + }, + "portId": 2 }, - "Block-3": { + "Block-2": { ".__BlockDict__": true, "BlockDisplayName": "WtTp3", "BlockName": "WTap", - "Id": 3, - "__version__": "bbc03f36-d1a1-4d97-a9c0-d212ea3a0203", - "blockPosition": [ - -86.0, - -375.0 - ], - "flippedH": false, - "flippedV": false, - "portsIdsIn": [ - 4 - ], - "portsIdsOut": [], - "rotationN": 0, - "trnsysId": 2 + "__version__": "14afd9a0-54d6-44c7-b147-c79af3b782bb", + "blockItemWithPrescribedMassFlow": { + "__version__": "e9fd1a0e-c00a-46e2-abfb-7381fa1b2e2d", + "blockItem": { + "__version__": "7b792574-5fa6-4c3e-b2e3-7e4eb71d7746", + "blockPosition": [ + -86.0, + -375.0 + ], + "flippedH": false, + "flippedV": false, + "rotationN": 0, + "trnsysId": 2 + }, + "massFlowRateInKgPerH": 1000.0 + }, + "portId": 4 }, - "Block-5": { + "Block-3": { ".__BlockDict__": true, "BlockDisplayName": "Pump5", "BlockName": "Pump", - "Id": 5, - "__version__": "9552365f-ef11-4fac-ba35-644e94b54088", - "blockPosition": [ - -166.0, - -302.0 - ], - "flippedH": false, - "flippedV": false, - "massFlowRateInKgPerH": 500, - "portsIdsIn": [ - 6 - ], - "portsIdsOut": [ - 7 - ], - "rotationN": -1, - "trnsysId": 3 + "__version__": "3d1e7f06-c7a6-49af-98b8-f593b34c5754", + "blockItemWithPrescribedMassFlow": { + "__version__": "e9fd1a0e-c00a-46e2-abfb-7381fa1b2e2d", + "blockItem": { + "__version__": "7b792574-5fa6-4c3e-b2e3-7e4eb71d7746", + "blockPosition": [ + -166.0, + -302.0 + ], + "flippedH": false, + "flippedV": false, + "rotationN": -1, + "trnsysId": 3 + }, + "massFlowRateInKgPerH": 500.0 + }, + "inputPortId": 6, + "outputPortId": 7 }, - "Connection-8": { + "Connection-4": { ".__ConnectionDict__": true, "__version__": "74032e79-2abc-4fcf-9328-5d697ef31023", "connectionId": 1, @@ -99,7 +106,7 @@ "name": "loop1UVal" } }, - "Connection-9": { + "Connection-5": { ".__ConnectionDict__": true, "__version__": "74032e79-2abc-4fcf-9328-5d697ef31023", "connectionId": 2, @@ -134,10 +141,10 @@ } }, "IDs": { - "GlobalId": 10, + "GlobalId": 11, "__idDct__": true, - "globalConnID": 3, - "trnsysID": 6 + "globalConnID": 4, + "trnsysID": 7 }, "Strings": { "DiagramName": "diagramWithTapForRegimes.json", diff --git a/tests/trnsysGUI/data/diagramWithTapForRegimes/expectedCSVs/expectedRegimeTemplate.csv b/tests/trnsysGUI/data/diagramWithTapForRegimes/expectedCSVs/expectedRegimeTemplate.csv new file mode 100644 index 00000000..6de041e9 --- /dev/null +++ b/tests/trnsysGUI/data/diagramWithTapForRegimes/expectedCSVs/expectedRegimeTemplate.csv @@ -0,0 +1,2 @@ +regimeName,Pump5,WtSp1,WtTp3 +dummy_regime,500.0,1000.0,1000.0 diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py index fc7e0736..4185196e 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py @@ -1,23 +1,27 @@ import pathlib as _pl import pandas as _pd +import pytest as _pt +import unittest as _ut import trnsysGUI as _GUI import trnsysGUI.pythonInterface.regimeExporter.exportRegimes as _er -_PROJECT_NAME = "diagramForRegimes" -_DATA_DIR = _pl.Path(_GUI.__file__).parent / f"..\\tests\\trnsysGUI\\data\\{_PROJECT_NAME}" -_EXPECTED_CVSS_DIR = _DATA_DIR / "expectedCSVs" +_DATA_DIR_BASE = _pl.Path(_GUI.__file__).parent / f"..\\tests\\trnsysGUI\\data\\" class TestExportRegimeTemplate: - def testExportTemplate(self): - projectJson = _DATA_DIR / f"{_PROJECT_NAME}.json" - regimeFileName = _DATA_DIR / "regimeTemplate.csv" - expectedFileName = _EXPECTED_CVSS_DIR / "expectedRegimeTemplate.csv" - _er.exportRegimeTemplate(projectJson, regimeFileName) + @_pt.mark.parametrize("projectName", ["diagramForRegimes", "diagramWithTapForRegimes"]) + def testExportTemplate(self, projectName): + dataDir = _DATA_DIR_BASE / f"{projectName}" + expectedCsvDir = dataDir / "expectedCSVs" + projectJson = dataDir / f"{projectName}.json" + regimeFilePath = dataDir / "regimeTemplate.csv" + expectedFilePath = expectedCsvDir / "expectedRegimeTemplate.csv" - expectedContent = _pd.read_csv(expectedFileName) - actualContent = _pd.read_csv(regimeFileName) + _er.exportRegimeTemplate(projectJson, regimeFilePath) + + expectedContent = _pd.read_csv(expectedFilePath) + actualContent = _pd.read_csv(regimeFilePath) _pd.testing.assert_frame_equal(expectedContent, actualContent, check_dtype=False) diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py index 66d25a3f..8c56d070 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py @@ -135,6 +135,7 @@ def _createMainWindow(projectFolder, projectName, qtbot): class TestPrintRegimesAndCopyFiles: def testMplInstallation(self): + """ Checks whether Inkscape is installed correctly. """ assert "pdf" in _mpltc.comparable_formats() assert "svg" in _mpltc.comparable_formats() diff --git a/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py b/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py index 76d54260..476b614f 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py +++ b/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py @@ -2,7 +2,7 @@ import pandas as _pd -import trnsysGUI.pumpsAndTaps._serialization as _pu +import trnsysGUI.pumpsAndTaps._serialization as _se def exportRegimeTemplate(projectJson, regimeFileName): @@ -24,20 +24,24 @@ def getPumpsAndValvesWithValuesFromJson(projectJson): if "BlockName" in curDict: curBlockName = curDict["BlockName"] if curBlockName == "Pump": - curPump = _pu.PumpModel.from_dict(curDict) + curPump = _se.PumpModel.from_dict(curDict) data[curPump.BlockDisplayName] = curPump.blockItemWithPrescribedMassFlow.massFlowRateInKgPerH elif curBlockName == "TVentil": desiredValueName = "PositionForMassFlowSolver" data = getData(curDict, data, desiredValueName) + elif curBlockName == "WTap_main" or curBlockName == "WTap": + curTap = _se.TerminalWithPrescribedMassFlowModel.from_dict(curDict) + data[curTap.BlockDisplayName] = curTap.blockItemWithPrescribedMassFlow.massFlowRateInKgPerH + pumpsAndValvesAndValues = _pd.DataFrame(data, index=["dummy_regime"]) pumpsAndValvesAndValues.index.name = "regimeName" return pumpsAndValvesAndValues def getData(curDict, data, desiredValueName): - bockItemName = curDict["BlockDisplayName"] + blockItemName = curDict["BlockDisplayName"] value = float(curDict[desiredValueName]) - data[bockItemName] = value + data[blockItemName] = value return data From 02edd75a62e41ac8d4c8bf0af56e6b75d69b57d4 Mon Sep 17 00:00:00 2001 From: ahobeost Date: Tue, 2 Jul 2024 15:00:08 +0200 Subject: [PATCH 49/56] Cleanup for CI --- tests/trnsysGUI/pumpsAndTaps/testSerialization.py | 2 +- .../regimeExporter/testExportRegimeTemplate.py | 1 - trnsysGUI/pumpsAndTaps/_pumpsAndTabsBase.py | 2 +- trnsysGUI/pumpsAndTaps/_tapBase.py | 2 +- trnsysGUI/pumpsAndTaps/pump.py | 2 +- .../pumpsAndTaps/{_serialization.py => serialization.py} | 0 trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py | 6 ++++-- 7 files changed, 8 insertions(+), 7 deletions(-) rename trnsysGUI/pumpsAndTaps/{_serialization.py => serialization.py} (100%) diff --git a/tests/trnsysGUI/pumpsAndTaps/testSerialization.py b/tests/trnsysGUI/pumpsAndTaps/testSerialization.py index b9d86a79..b8f609fe 100644 --- a/tests/trnsysGUI/pumpsAndTaps/testSerialization.py +++ b/tests/trnsysGUI/pumpsAndTaps/testSerialization.py @@ -1,7 +1,7 @@ import json as _json import pathlib as _pl -import trnsysGUI.pumpsAndTaps._serialization as _ser +import trnsysGUI.pumpsAndTaps.serialization as _ser class TestSerialization: diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py index 4185196e..e17ef7d6 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py @@ -1,7 +1,6 @@ import pathlib as _pl import pandas as _pd import pytest as _pt -import unittest as _ut import trnsysGUI as _GUI import trnsysGUI.pythonInterface.regimeExporter.exportRegimes as _er diff --git a/trnsysGUI/pumpsAndTaps/_pumpsAndTabsBase.py b/trnsysGUI/pumpsAndTaps/_pumpsAndTabsBase.py index 4795b21a..89cf5e27 100644 --- a/trnsysGUI/pumpsAndTaps/_pumpsAndTabsBase.py +++ b/trnsysGUI/pumpsAndTaps/_pumpsAndTabsBase.py @@ -13,7 +13,7 @@ from . import _defaults from . import _dialog -from . import _serialization as _ser +from . import serialization as _ser class PumpsAndTabsBase(_bip.BlockItemHasInternalPiping, _gimx.SvgBlockItemGraphicItemMixin): diff --git a/trnsysGUI/pumpsAndTaps/_tapBase.py b/trnsysGUI/pumpsAndTaps/_tapBase.py index 193d0277..fe14e761 100644 --- a/trnsysGUI/pumpsAndTaps/_tapBase.py +++ b/trnsysGUI/pumpsAndTaps/_tapBase.py @@ -4,7 +4,7 @@ from trnsysGUI import createSinglePipePortItem as _cspi, internalPiping as _ip from trnsysGUI.massFlowSolver import networkModel as _mfn -from trnsysGUI.pumpsAndTaps import _pumpsAndTabsBase as _ptb, _serialization as _ser +from trnsysGUI.pumpsAndTaps import _pumpsAndTabsBase as _ptb, serialization as _ser class TapBase(_ptb.PumpsAndTabsBase): diff --git a/trnsysGUI/pumpsAndTaps/pump.py b/trnsysGUI/pumpsAndTaps/pump.py index a366c9db..e21b8329 100644 --- a/trnsysGUI/pumpsAndTaps/pump.py +++ b/trnsysGUI/pumpsAndTaps/pump.py @@ -10,7 +10,7 @@ import trnsysGUI.internalPiping as _ip import trnsysGUI.massFlowSolver.networkModel as _mfn from . import _pumpsAndTabsBase as _patb -from . import _serialization as _ser +from . import serialization as _ser class Pump(_patb.PumpsAndTabsBase): # pylint: disable=too-many-instance-attributes diff --git a/trnsysGUI/pumpsAndTaps/_serialization.py b/trnsysGUI/pumpsAndTaps/serialization.py similarity index 100% rename from trnsysGUI/pumpsAndTaps/_serialization.py rename to trnsysGUI/pumpsAndTaps/serialization.py diff --git a/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py b/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py index 476b614f..75d3fab4 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py +++ b/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py @@ -2,7 +2,7 @@ import pandas as _pd -import trnsysGUI.pumpsAndTaps._serialization as _se +import trnsysGUI.pumpsAndTaps.serialization as _se def exportRegimeTemplate(projectJson, regimeFileName): @@ -26,10 +26,12 @@ def getPumpsAndValvesWithValuesFromJson(projectJson): if curBlockName == "Pump": curPump = _se.PumpModel.from_dict(curDict) data[curPump.BlockDisplayName] = curPump.blockItemWithPrescribedMassFlow.massFlowRateInKgPerH + elif curBlockName == "TVentil": desiredValueName = "PositionForMassFlowSolver" data = getData(curDict, data, desiredValueName) - elif curBlockName == "WTap_main" or curBlockName == "WTap": + + elif curBlockName in ("WTap_main", "WTap"): curTap = _se.TerminalWithPrescribedMassFlowModel.from_dict(curDict) data[curTap.BlockDisplayName] = curTap.blockItemWithPrescribedMassFlow.massFlowRateInKgPerH From c4a8b4a85d9b7095fa6b7fae2dcb1e76a86637ca Mon Sep 17 00:00:00 2001 From: ahobeost Date: Tue, 2 Jul 2024 17:23:35 +0200 Subject: [PATCH 50/56] CI adjustments --- .../regimeExporter/testExportRegimeTemplate.py | 2 +- .../regimeExporter/testPrintRegimesAndCopyFiles.py | 2 +- .../regimeExporter/renderDiagramOnPDFfromPython.py | 4 +--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py index e17ef7d6..50a85810 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py @@ -5,7 +5,7 @@ import trnsysGUI as _GUI import trnsysGUI.pythonInterface.regimeExporter.exportRegimes as _er -_DATA_DIR_BASE = _pl.Path(_GUI.__file__).parent / f"..\\tests\\trnsysGUI\\data\\" +_DATA_DIR_BASE = _pl.Path(_GUI.__file__).parent / "..\\tests\\trnsysGUI\\data\\" class TestExportRegimeTemplate: diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py index 8c56d070..ebbad662 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py @@ -135,7 +135,7 @@ def _createMainWindow(projectFolder, projectName, qtbot): class TestPrintRegimesAndCopyFiles: def testMplInstallation(self): - """ Checks whether Inkscape is installed correctly. """ + """Checks whether Inkscape is installed correctly.""" assert "pdf" in _mpltc.comparable_formats() assert "svg" in _mpltc.comparable_formats() diff --git a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py index 294884a0..d56d141d 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py +++ b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py @@ -36,9 +36,7 @@ def temperaturesPrintFilePath(self): temperaturesPintFileName = f"{self.projectName}_T.prt" return self.projectDir / temperaturesPintFileName - def export( - self, onlyTheseRegimes: _tp.Optional[_tp.Sequence[str]] = None - ) -> None: + def export(self, onlyTheseRegimes: _tp.Optional[_tp.Sequence[str]] = None) -> None: if not onlyTheseRegimes: self._makeDiagramFiles() From be26b6760a234220babb4dd60c22ccd3339b811c Mon Sep 17 00:00:00 2001 From: ahobeost Date: Wed, 3 Jul 2024 09:46:39 +0200 Subject: [PATCH 51/56] Refactoring --- .../regimeExporter/exportRegimes.py | 50 +++++++++++-------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py b/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py index 75d3fab4..fa6ca460 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py +++ b/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py @@ -15,29 +15,35 @@ def getPumpsAndValvesWithValuesFromJson(projectJson): jsonValues = json.load(openFile) data = {} + blocks = jsonValues["Blocks"] undesiredBlocks = [".__BlockDct__", "IDs", "Strings"] - for block in jsonValues["Blocks"]: - if block in undesiredBlocks: - continue - - curDict = jsonValues["Blocks"][block] - if "BlockName" in curDict: - curBlockName = curDict["BlockName"] - if curBlockName == "Pump": - curPump = _se.PumpModel.from_dict(curDict) - data[curPump.BlockDisplayName] = curPump.blockItemWithPrescribedMassFlow.massFlowRateInKgPerH - - elif curBlockName == "TVentil": - desiredValueName = "PositionForMassFlowSolver" - data = getData(curDict, data, desiredValueName) - - elif curBlockName in ("WTap_main", "WTap"): - curTap = _se.TerminalWithPrescribedMassFlowModel.from_dict(curDict) - data[curTap.BlockDisplayName] = curTap.blockItemWithPrescribedMassFlow.massFlowRateInKgPerH - - pumpsAndValvesAndValues = _pd.DataFrame(data, index=["dummy_regime"]) - pumpsAndValvesAndValues.index.name = "regimeName" - return pumpsAndValvesAndValues + # blockItemsInJson = filter(lambda x: x not in undesiredBlocks, blocks) + # blockNamesInJson = list(filter(lambda block: "BlockName" in blocks[block], blockItemsInJson)) + blockItemsInJson = [x for x in blocks if x not in undesiredBlocks] + blockNamesInJson = [x for x in blockItemsInJson if "BlockName" in blocks[x]] + + # pumps = list(filter(lambda block: "Pump" in blocks[block]["BlockName"], blockNamesInJson)) + pumps = [x for x in blockNamesInJson if blocks[x]["BlockName"] == "Pump"] + for pump in pumps: + curPump = _se.PumpModel.from_dict(blocks[pump]) + data[curPump.BlockDisplayName] = curPump.blockItemWithPrescribedMassFlow.massFlowRateInKgPerH + + # valves = list(filter(lambda block: "TVentil" in blocks[block]["BlockName"], blockNamesInJson)) + valves = [x for x in blockNamesInJson if blocks[x]["BlockName"] == "TVentil"] + for valve in valves: + desiredValueName = "PositionForMassFlowSolver" + data = getData(blocks[valve], data, desiredValueName) + + # taps = list(filter(lambda block: blocks[block]["BlockName"] in ("WTap_main", "WTap"), blockNamesInJson)) + taps = [x for x in blockNamesInJson if blocks[x]["BlockName"] in ("WTap_main", "WTap")] + for tap in taps: + curTap = _se.TerminalWithPrescribedMassFlowModel.from_dict(blocks[tap]) + data[curTap.BlockDisplayName] = curTap.blockItemWithPrescribedMassFlow.massFlowRateInKgPerH + + componentsAndValues = _pd.DataFrame(data, index=["dummy_regime"]) + componentsAndValues.index.name = "regimeName" + + return componentsAndValues def getData(curDict, data, desiredValueName): From 2e4ba57adf8388c96acee8277c398cc6f68c41d3 Mon Sep 17 00:00:00 2001 From: ahobeost Date: Wed, 3 Jul 2024 10:17:24 +0200 Subject: [PATCH 52/56] Added example with sources and sinks, with a working template export. --- .../ddck/generic/end.ddck | 14 + .../ddck/generic/head.ddck | 110 +++++ .../diagramWithSourceSinksForRegimes.json | 375 ++++++++++++++++++ .../expectedCSVs/expectedRegimeTemplate.csv | 2 + .../testExportRegimeTemplate.py | 2 +- .../regimeExporter/exportRegimes.py | 6 + trnsysGUI/sourceSinkBase.py | 5 +- 7 files changed, 512 insertions(+), 2 deletions(-) create mode 100644 tests/trnsysGUI/data/diagramWithSourceSinksForRegimes/ddck/generic/end.ddck create mode 100644 tests/trnsysGUI/data/diagramWithSourceSinksForRegimes/ddck/generic/head.ddck create mode 100644 tests/trnsysGUI/data/diagramWithSourceSinksForRegimes/diagramWithSourceSinksForRegimes.json create mode 100644 tests/trnsysGUI/data/diagramWithSourceSinksForRegimes/expectedCSVs/expectedRegimeTemplate.csv diff --git a/tests/trnsysGUI/data/diagramWithSourceSinksForRegimes/ddck/generic/end.ddck b/tests/trnsysGUI/data/diagramWithSourceSinksForRegimes/ddck/generic/end.ddck new file mode 100644 index 00000000..86bc6bfd --- /dev/null +++ b/tests/trnsysGUI/data/diagramWithSourceSinksForRegimes/ddck/generic/end.ddck @@ -0,0 +1,14 @@ +******************************* +**BEGIN Head.ddck +******************************* + +***************************************** +** Contact person: Dani Carbonell +** Date: 30.09.2016 +***************************************** + +END + +******************************* +**END End.ddck +******************************* diff --git a/tests/trnsysGUI/data/diagramWithSourceSinksForRegimes/ddck/generic/head.ddck b/tests/trnsysGUI/data/diagramWithSourceSinksForRegimes/ddck/generic/head.ddck new file mode 100644 index 00000000..b20348bd --- /dev/null +++ b/tests/trnsysGUI/data/diagramWithSourceSinksForRegimes/ddck/generic/head.ddck @@ -0,0 +1,110 @@ +******************************* +**BEGIN Head.ddck +******************************* + +***************************************** +** Contact person: Dani Carbonell +** Date: 30.09.2016 +***************************************** + +*************************************************************************** +** Description: +** Basic TRNSYS variables including fluid properties +*************************************************************************** + +VERSION 17 + +************************************** +***Simulation time ****** +************************************** + +CONSTANTS 3 +START = 0 +STOP = 8760 +dtSim = 1/30. ! time step in hours + +************************************** +***TRNSYS SIMULATION constants ****** +************************************** + +CONSTANTS 13 +nIteTrnsys = 30 ! TRNSYS Limit of iterations +nWarnTrnsys = 12000 ! TRNSYS Limit of warnings +nCallTraceTrnys = 31 ! TRNSYS limit of calls to a component before it will be traced +FrInte_Tol = 0.003 ! TRNSYS solver tolerances +FrConv_Tol = 0.0005 ! TRNSYS solver tolerances +nan_check_bool = 1 ! TRNSYS nan check boolean +time_report = 1 ! TRNSYS time report +solver_equation = 0 ! TRNSYS EQUATION SOLVER statement +debug_statement = 0 ! TRNSYS Overwrite DEBUG statement +solver_statement = 0 ! TRNSYS Solver statement +min_relax_factor = 1 ! TRNSYS Minimum relaxation factor +max_relac_factor = 1 ! TRNSYS Maximum relaxation factor +solver_integration = 1 ! TRNSYS numerical integration solver method + + +************************************** +***TRNSYS SIMULATION SET-UP ****** +************************************** + +SIMULATION START STOP dtSim +TOLERANCES FrInte_Tol FrConv_Tol +LIMITS nIteTrnsys nWarnTrnsys nCallTraceTrnys ! Limit of Iterations, limit of warnings, limit of calls to a component before it will be traced +DFQ solver_integration ! TRNSYS numerical integration solver method +WIDTH 132 ! TRNSYS output file width, number of characters +LIST ! NOLIST statement + +SOLVER solver_statement min_relax_factor max_relac_factor ! Solver statement, Minimum relaxation factor, Maximum relaxation factor +NAN_CHECK nan_check_bool ! Nan DEBUG statement +OVERWRITE_CHECK debug_statement ! Overwrite DEBUG statement +EQSOLVER solver_equation ! EQUATION SOLVER statement +TIME_REPORT time_report + + +************************************** +*** MASS FLOW SOLVER CONSTANTS ****** +************************************** + +CONSTANTS 3 +mfrSolverAbsTol = 1e-8 +mfrSolverRelTol = 1e-8 +mfrTolSwitchThreshold = 1e2 + +************************************** +***User defined printer settings****** +************************************** + +CONSTANTS 3 + +tStrtUser = START ! START start time of user defined printer +tEndUser = STOP ! END time of user defined printer +dtPrUser = dtSim ! timestep of user defined printer + +************************************** +***Generic Constants ****** +************************************** + +CONSTANTS 6 +versionDeck = 1 !can be changed from config file to adapt processes and so on +PI = 3.1415926 +Zero = 0 +Nix = 0 +notused = 0 +NPlotsPerSim = 18 + +************************************** +***Constant fluid properties ****** +************************************** + +CONSTANTS 7 +CPBRI = 3.8160 ! spec. heat of Glycol [kJ/kgK]; Value for an average pipe temperature with 55 °C Tyfocor LS +RHOBRI = 1016.0 ! density Glycol [kg/m³]; Value for an average pipe temperature with 55 °C Tyfocor L +CPWAT = 4.19 ! spec. heat of Water [kJ/kgK] at 20 °C +RHOWAT = 998.0 ! density of Water [kg/m³] at20 °C +LAMWAT = 0.58 ! heat conductivity W/(mK) +CPWAT_SI = CPWAT*1000 ! J/(kgK) +CPBRI_SI = CPBRI*1000 ! J/(kgK) + +******************************* +**END Head.dck +******************************* diff --git a/tests/trnsysGUI/data/diagramWithSourceSinksForRegimes/diagramWithSourceSinksForRegimes.json b/tests/trnsysGUI/data/diagramWithSourceSinksForRegimes/diagramWithSourceSinksForRegimes.json new file mode 100644 index 00000000..4a76b5ff --- /dev/null +++ b/tests/trnsysGUI/data/diagramWithSourceSinksForRegimes/diagramWithSourceSinksForRegimes.json @@ -0,0 +1,375 @@ +{ + "Blocks": { + ".__BlockDct__": true, + "Block-1": { + ".__BlockDict__": true, + "BlockDisplayName": "QSrc", + "BlockName": "Source", + "__version__": "e8cfde2f-8239-4338-a5f0-63a7abb93900", + "blockPosition": [ + -960.0, + -140.0 + ], + "flippedH": false, + "flippedV": false, + "portsIdsIn": [ + 1 + ], + "portsIdsOut": [ + 2 + ], + "rotationN": 1, + "trnsysId": 1 + }, + "Block-2": { + ".__BlockDict__": true, + "BlockDisplayName": "QSnk", + "BlockName": "Sink", + "__version__": "e8cfde2f-8239-4338-a5f0-63a7abb93900", + "blockPosition": [ + -620.0, + -60.0 + ], + "flippedH": false, + "flippedV": false, + "portsIdsIn": [ + 3 + ], + "portsIdsOut": [ + 4 + ], + "rotationN": -1, + "trnsysId": 2 + }, + "Block-3": { + ".__BlockDict__": true, + "BlockDisplayName": "Tee", + "BlockName": "TeePiece", + "__version__": "d8a12235-c3f9-4742-bb7b-2c92a26d66c5", + "teePieceModel": { + "__version__": "260c8083-5343-4345-8cb3-0cdd374bc076", + "blockItemModel": { + "__version__": "7b792574-5fa6-4c3e-b2e3-7e4eb71d7746", + "blockPosition": [ + -880.0, + -40.0 + ], + "flippedH": false, + "flippedV": false, + "rotationN": 1, + "trnsysId": 3 + }, + "inputPortId": 5, + "outputPortIds": [ + 6, + 7 + ] + } + }, + "Block-4": { + ".__BlockDict__": true, + "BlockDisplayName": "Tee2", + "BlockName": "TeePiece", + "__version__": "d8a12235-c3f9-4742-bb7b-2c92a26d66c5", + "teePieceModel": { + "__version__": "260c8083-5343-4345-8cb3-0cdd374bc076", + "blockItemModel": { + "__version__": "7b792574-5fa6-4c3e-b2e3-7e4eb71d7746", + "blockPosition": [ + -700.0, + -180.0 + ], + "flippedH": false, + "flippedV": false, + "rotationN": -2, + "trnsysId": 4 + }, + "inputPortId": 8, + "outputPortIds": [ + 9, + 10 + ] + } + }, + "Block-5": { + ".__BlockDict__": true, + "BlockDisplayName": "IceS", + "BlockName": "IceStorage", + "__version__": "e8cfde2f-8239-4338-a5f0-63a7abb93900", + "blockPosition": [ + -840.0, + -160.0 + ], + "flippedH": false, + "flippedV": false, + "portsIdsIn": [ + 11 + ], + "portsIdsOut": [ + 12 + ], + "rotationN": 0, + "trnsysId": 5 + }, + "Connection-10": { + ".__ConnectionDict__": true, + "__version__": "74032e79-2abc-4fcf-9328-5d697ef31023", + "connectionId": 5, + "diameterInCm": { + "name": "loop1Dia" + }, + "fromPortId": 10, + "id": 17, + "labelPos": [ + -717.0, + -177.0 + ], + "lengthInM": { + "name": "loop1Len" + }, + "massFlowLabelPos": [ + -717.0, + -177.0 + ], + "name": "Tee2_IceS", + "segmentsCorners": [ + [ + -720.0, + -192.666 + ], + [ + -720.0, + -192.666 + ] + ], + "shallBeSimulated": true, + "toPortId": 11, + "trnsysId": 10, + "uValueInWPerM2K": { + "name": "loop1UVal" + } + }, + "Connection-11": { + ".__ConnectionDict__": true, + "__version__": "74032e79-2abc-4fcf-9328-5d697ef31023", + "connectionId": 6, + "diameterInCm": { + "name": "loop1Dia" + }, + "fromPortId": 8, + "id": 18, + "labelPos": [ + -697.0, + -197.0 + ], + "lengthInM": { + "name": "loop1Len" + }, + "massFlowLabelPos": [ + -697.0, + -197.0 + ], + "name": "Tee2_QSnk", + "segmentsCorners": [ + [ + -628.5, + -200.0 + ], + [ + -628.5, + -100.0 + ] + ], + "shallBeSimulated": true, + "toPortId": 3, + "trnsysId": 11, + "uValueInWPerM2K": { + "name": "loop1UVal" + } + }, + "Connection-6": { + ".__ConnectionDict__": true, + "__version__": "74032e79-2abc-4fcf-9328-5d697ef31023", + "connectionId": 1, + "diameterInCm": { + "name": "loop1Dia" + }, + "fromPortId": 2, + "id": 13, + "labelPos": [ + -937.0, + -83.0 + ], + "lengthInM": { + "name": "loop1Len" + }, + "massFlowLabelPos": [ + -937.0, + -83.0 + ], + "name": "QSrc_Tee2", + "segmentsCorners": [ + [ + -960.0, + -99.0 + ], + [ + -845.0, + -99.0 + ], + [ + -845.0, + -200.0 + ] + ], + "shallBeSimulated": true, + "toPortId": 9, + "trnsysId": 6, + "uValueInWPerM2K": { + "name": "loop1UVal" + } + }, + "Connection-7": { + ".__ConnectionDict__": true, + "__version__": "74032e79-2abc-4fcf-9328-5d697ef31023", + "connectionId": 2, + "diameterInCm": { + "name": "loop1Dia" + }, + "fromPortId": 1, + "id": 14, + "labelPos": [ + -937.0, + -103.0 + ], + "lengthInM": { + "name": "loop1Len" + }, + "massFlowLabelPos": [ + -937.0, + -103.0 + ], + "name": "QSrc_Tee", + "segmentsCorners": [ + [ + -960.0, + -120.0 + ], + [ + -900.0, + -120.0 + ] + ], + "shallBeSimulated": true, + "toPortId": 5, + "trnsysId": 7, + "uValueInWPerM2K": { + "name": "loop1UVal" + } + }, + "Connection-8": { + ".__ConnectionDict__": true, + "__version__": "74032e79-2abc-4fcf-9328-5d697ef31023", + "connectionId": 3, + "diameterInCm": { + "name": "loop1Dia" + }, + "fromPortId": 4, + "id": 15, + "labelPos": [ + -563.0, + -77.0 + ], + "lengthInM": { + "name": "loop1Len" + }, + "massFlowLabelPos": [ + -563.0, + -77.0 + ], + "name": "QSnk_Tee", + "segmentsCorners": [ + [ + -620.0, + -2.0 + ], + [ + -900.0, + -2.0 + ] + ], + "shallBeSimulated": true, + "toPortId": 6, + "trnsysId": 8, + "uValueInWPerM2K": { + "name": "loop1UVal" + } + }, + "Connection-9": { + ".__ConnectionDict__": true, + "__version__": "74032e79-2abc-4fcf-9328-5d697ef31023", + "connectionId": 4, + "diameterInCm": { + "name": "loop1Dia" + }, + "fromPortId": 12, + "id": 16, + "labelPos": [ + -723.0, + -63.0 + ], + "lengthInM": { + "name": "loop1Len" + }, + "massFlowLabelPos": [ + -723.0, + -63.0 + ], + "name": "IceS_Tee", + "segmentsCorners": [ + [ + -723.0, + -60.0 + ], + [ + -723.0, + -20.0 + ] + ], + "shallBeSimulated": true, + "toPortId": 7, + "trnsysId": 9, + "uValueInWPerM2K": { + "name": "loop1UVal" + } + }, + "IDs": { + "GlobalId": 25, + "__idDct__": true, + "globalConnID": 11, + "trnsysID": 17 + }, + "Strings": { + "DiagramName": "diagramWithSourceSinksForRegimes.json", + "ProjectFolder": "C:\\Users\\alex.hobe\\Projects\\pytrnsys_gui\\tests\\trnsysGUI\\data\\diagramWithSourceSinksForRegimes", + "__nameDct__": true + } + }, + "hydraulicLoops": [ + { + "__version__": "990b8023-eb4b-408e-8d54-23caa5916b2a", + "connectionsTrnsysId": [ + 6, + 7, + 8, + 9, + 10, + 11 + ], + "fluidName": "water", + "hasUserDefinedName": false, + "name": "loop1", + "useLoopWideDefaults": true + } + ] +} \ No newline at end of file diff --git a/tests/trnsysGUI/data/diagramWithSourceSinksForRegimes/expectedCSVs/expectedRegimeTemplate.csv b/tests/trnsysGUI/data/diagramWithSourceSinksForRegimes/expectedCSVs/expectedRegimeTemplate.csv new file mode 100644 index 00000000..a4a68496 --- /dev/null +++ b/tests/trnsysGUI/data/diagramWithSourceSinksForRegimes/expectedCSVs/expectedRegimeTemplate.csv @@ -0,0 +1,2 @@ +regimeName,QSnk,QSrc +dummy_regime,500.0,500.0 diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py index 50a85810..36ecd0ca 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py @@ -10,7 +10,7 @@ class TestExportRegimeTemplate: - @_pt.mark.parametrize("projectName", ["diagramForRegimes", "diagramWithTapForRegimes"]) + @_pt.mark.parametrize("projectName", ["diagramForRegimes", "diagramWithTapForRegimes", "diagramWithSourceSinksForRegimes"]) def testExportTemplate(self, projectName): dataDir = _DATA_DIR_BASE / f"{projectName}" expectedCsvDir = dataDir / "expectedCSVs" diff --git a/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py b/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py index fa6ca460..8910ceca 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py +++ b/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py @@ -40,6 +40,12 @@ def getPumpsAndValvesWithValuesFromJson(projectJson): curTap = _se.TerminalWithPrescribedMassFlowModel.from_dict(blocks[tap]) data[curTap.BlockDisplayName] = curTap.blockItemWithPrescribedMassFlow.massFlowRateInKgPerH + sourceSinks = [x for x in blockNamesInJson if blocks[x]["BlockName"] in ("Sink", "Source", "SourceSink", "Geotherm", "Water")] + for sourceSink in sourceSinks: + """ This isn't in the json yet, so I am applying a default value directly at first. """ + BlockDisplayName = blocks[sourceSink]["BlockDisplayName"] + data[BlockDisplayName] = 500.0 + componentsAndValues = _pd.DataFrame(data, index=["dummy_regime"]) componentsAndValues.index.name = "regimeName" diff --git a/trnsysGUI/sourceSinkBase.py b/trnsysGUI/sourceSinkBase.py index 977830d3..b401ea85 100644 --- a/trnsysGUI/sourceSinkBase.py +++ b/trnsysGUI/sourceSinkBase.py @@ -7,6 +7,7 @@ import trnsysGUI.images as _img import trnsysGUI.internalPiping as _ip import trnsysGUI.massFlowSolver.networkModel as _mfn +import trnsysGUI.pumpsAndTaps._defaults as _defaults class SourceSinkBase(_bip.BlockItemHasInternalPiping, _gimx.SvgBlockItemGraphicItemMixin): @@ -16,6 +17,8 @@ def __init__(self, trnsysType: str, editor, displayName: str) -> None: self.w = 60 self.h = 60 + self.massFlowRateInKgPerH = _defaults.DEFAULT_MASS_FLOW_RATE + self.inputs.append(_cspi.createSinglePipePortItem("i", 1, self)) self.outputs.append(_cspi.createSinglePipePortItem("o", 1, self)) @@ -67,5 +70,5 @@ def getInternalPiping(self) -> _ip.InternalPiping: def exportMassFlows(self): equationNr = 1 - massFlowLine = f"Mfr{self.displayName} = 500\n" + massFlowLine = f"Mfr{self.displayName} = {self.massFlowRateInKgPerH}\n" return massFlowLine, equationNr From 1072898b34965d71fef6a36298fe3a66e95ffa0d Mon Sep 17 00:00:00 2001 From: ahobeost Date: Wed, 3 Jul 2024 13:50:27 +0200 Subject: [PATCH 53/56] Added source sink functionality and refactoring --- ...iagramWithSourceSinksForRegimes_charge.pdf | Bin 0 -> 12373 bytes ...rceSinksForRegimes_charge_while_direct.pdf | Bin 0 -> 12343 bytes ...agramWithSourceSinksForRegimes_diagram.pdf | Bin 0 -> 21205 bytes ...iagramWithSourceSinksForRegimes_direct.pdf | Bin 0 -> 12355 bytes ...ramWithSourceSinksForRegimes_discharge.pdf | Bin 0 -> 12354 bytes .../regimes.csv | 5 ++ .../testExportRegimeTemplate.py | 4 +- .../testPrintRegimesAndCopyFiles.py | 55 +++++++++++++++++- trnsysGUI/pumpsAndTaps/_pumpsAndTabsBase.py | 3 +- .../{_defaults.py => defaults.py} | 0 trnsysGUI/pumpsAndTaps/serialization.py | 4 +- .../regimeExporter/exportRegimes.py | 39 ++++++------- .../renderDiagramOnPDFfromPython.py | 5 +- trnsysGUI/sourceSinkBase.py | 2 +- 14 files changed, 86 insertions(+), 31 deletions(-) create mode 100644 tests/trnsysGUI/data/diagramWithSourceSinksForRegimes/expectedPDFs/diagramWithSourceSinksForRegimes_charge.pdf create mode 100644 tests/trnsysGUI/data/diagramWithSourceSinksForRegimes/expectedPDFs/diagramWithSourceSinksForRegimes_charge_while_direct.pdf create mode 100644 tests/trnsysGUI/data/diagramWithSourceSinksForRegimes/expectedPDFs/diagramWithSourceSinksForRegimes_diagram.pdf create mode 100644 tests/trnsysGUI/data/diagramWithSourceSinksForRegimes/expectedPDFs/diagramWithSourceSinksForRegimes_direct.pdf create mode 100644 tests/trnsysGUI/data/diagramWithSourceSinksForRegimes/expectedPDFs/diagramWithSourceSinksForRegimes_discharge.pdf create mode 100644 tests/trnsysGUI/data/diagramWithSourceSinksForRegimes/regimes.csv rename trnsysGUI/pumpsAndTaps/{_defaults.py => defaults.py} (100%) diff --git a/tests/trnsysGUI/data/diagramWithSourceSinksForRegimes/expectedPDFs/diagramWithSourceSinksForRegimes_charge.pdf b/tests/trnsysGUI/data/diagramWithSourceSinksForRegimes/expectedPDFs/diagramWithSourceSinksForRegimes_charge.pdf new file mode 100644 index 0000000000000000000000000000000000000000..667961c55eb070937344bb7794bae4e323327a03 GIT binary patch literal 12373 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 RFmwT4Fflv3>}@&X{{?AJop1mE literal 0 HcmV?d00001 diff --git a/tests/trnsysGUI/data/diagramWithSourceSinksForRegimes/expectedPDFs/diagramWithSourceSinksForRegimes_charge_while_direct.pdf b/tests/trnsysGUI/data/diagramWithSourceSinksForRegimes/expectedPDFs/diagramWithSourceSinksForRegimes_charge_while_direct.pdf new file mode 100644 index 0000000000000000000000000000000000000000..918e3f5452740071ebc97884d31e89a5aa33789a GIT binary patch literal 12343 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 literal 0 HcmV?d00001 diff --git a/tests/trnsysGUI/data/diagramWithSourceSinksForRegimes/expectedPDFs/diagramWithSourceSinksForRegimes_direct.pdf b/tests/trnsysGUI/data/diagramWithSourceSinksForRegimes/expectedPDFs/diagramWithSourceSinksForRegimes_direct.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b39b458f4cc325e0f16f9d4c5bc0a13fca811438 GIT binary patch literal 12355 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 G?*9V&+@J~o literal 0 HcmV?d00001 diff --git a/tests/trnsysGUI/data/diagramWithSourceSinksForRegimes/regimes.csv b/tests/trnsysGUI/data/diagramWithSourceSinksForRegimes/regimes.csv new file mode 100644 index 00000000..40b957ee --- /dev/null +++ b/tests/trnsysGUI/data/diagramWithSourceSinksForRegimes/regimes.csv @@ -0,0 +1,5 @@ +regimeName,QSrc,QSnk +direct,500.0,500.0 +charge,500.0,0.0 +discharge,0.0,500.0 +charge_while_direct,1000.0,500.0 diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py index 36ecd0ca..77487448 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testExportRegimeTemplate.py @@ -10,7 +10,9 @@ class TestExportRegimeTemplate: - @_pt.mark.parametrize("projectName", ["diagramForRegimes", "diagramWithTapForRegimes", "diagramWithSourceSinksForRegimes"]) + @_pt.mark.parametrize( + "projectName", ["diagramForRegimes", "diagramWithTapForRegimes", "diagramWithSourceSinksForRegimes"] + ) def testExportTemplate(self, projectName): dataDir = _DATA_DIR_BASE / f"{projectName}" expectedCsvDir = dataDir / "expectedCSVs" diff --git a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py index ebbad662..ce9b49cd 100644 --- a/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py +++ b/tests/trnsysGUI/pythonInterface/regimeExporter/testPrintRegimesAndCopyFiles.py @@ -117,6 +117,35 @@ def _ensureDirExists(dirPath): _NEW_NAME2_PATH = pathFinder.newPdfPath _NEW_NAME2_PATH_2 = pathFinder.alternatePdfPath +_PROJECT_NAME3 = "diagramWithSourceSinksForRegimes" +pathFinder3 = PathFinder( + _PROJECT_NAME3, _BASE_FOLDER_FILE_PATH, _EXPECTED_FILES_PATH, _RESULTS_DIR_NAME, _RESULTS_DIR_NAME_2 +) +_dataDir = pathFinder3.projectDir +_resultsDir = pathFinder3.resultsDir + +_ensureDirExists(_resultsDir) + +pathFinder3.setFileEnding("_diagram") +expectedDiagramPath = pathFinder3.expectedPdfPath +newDiagramPath = pathFinder3.newPdfPath + +pathFinder3.setFileEnding("_direct") +expectedName1Path = pathFinder3.expectedPdfPath +newName1Path = pathFinder3.newPdfPath + +pathFinder3.setFileEnding("_charge") +expectedName2Path = pathFinder3.expectedPdfPath +newName2Path = pathFinder3.newPdfPath + +pathFinder3.setFileEnding("_discharge") +expectedName3Path = pathFinder3.expectedPdfPath +newName3Path = pathFinder3.newPdfPath + +pathFinder3.setFileEnding("_charge_while_direct") +expectedName4Path = pathFinder3.expectedPdfPath +newName4Path = pathFinder3.newPdfPath + def _createMainWindow(projectFolder, projectName, qtbot): projectJsonFilePath = projectFolder / f"{projectName}.json" @@ -228,5 +257,29 @@ def testUsingQtBotForRegimeWithTap(self, qtbot): if errors: raise ExceptionGroup("multiple errors", errors) + def testUsingQtBotForRegimeWithSourceSinks(self, qtbot): + + mainWindow = _createMainWindow(_dataDir, _PROJECT_NAME3, qtbot) + regimeExporter = _rdopfp.RegimeExporter(_PROJECT_NAME3, _dataDir, _resultsDir, _REGIMES_FILENAME, mainWindow) + regimeExporter.export() + + filesToCompare = { + "new_file": [newDiagramPath, newName1Path, newName2Path, newName3Path, newName4Path], + "expected_file": [ + expectedDiagramPath, + expectedName1Path, + expectedName2Path, + expectedName3Path, + expectedName4Path, + ], + } + + errors = [] + for i, newFile in enumerate(filesToCompare["new_file"]): + try: + self._fileExistsAndIsCorrect(newFile, filesToCompare["expected_file"][i]) + except AssertionError as currentError: + errors.append(currentError) -# non-qtbot solution? + if errors: + raise ExceptionGroup("multiple errors", errors) diff --git a/trnsysGUI/pumpsAndTaps/_pumpsAndTabsBase.py b/trnsysGUI/pumpsAndTaps/_pumpsAndTabsBase.py index 89cf5e27..2dd60fa9 100644 --- a/trnsysGUI/pumpsAndTaps/_pumpsAndTabsBase.py +++ b/trnsysGUI/pumpsAndTaps/_pumpsAndTabsBase.py @@ -10,8 +10,7 @@ import trnsysGUI.internalPiping as _ip import trnsysGUI.massFlowSolver.names as _mnames import trnsysGUI.names.rename as _rename - -from . import _defaults +import trnsysGUI.pumpsAndTaps.defaults as _defaults from . import _dialog from . import serialization as _ser diff --git a/trnsysGUI/pumpsAndTaps/_defaults.py b/trnsysGUI/pumpsAndTaps/defaults.py similarity index 100% rename from trnsysGUI/pumpsAndTaps/_defaults.py rename to trnsysGUI/pumpsAndTaps/defaults.py diff --git a/trnsysGUI/pumpsAndTaps/serialization.py b/trnsysGUI/pumpsAndTaps/serialization.py index e753168e..afd687ab 100644 --- a/trnsysGUI/pumpsAndTaps/serialization.py +++ b/trnsysGUI/pumpsAndTaps/serialization.py @@ -3,12 +3,12 @@ import uuid as _uuid import dataclasses_jsonschema as _dcj - import pytrnsys.utils.serialization as _ser + import trnsysGUI.blockItemModel as _bim import trnsysGUI.blockItems.names as _bnames +import trnsysGUI.pumpsAndTaps.defaults as _defaults import trnsysGUI.serialization as _gser -from . import _defaults @_dc.dataclass diff --git a/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py b/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py index 8910ceca..6b24c319 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py +++ b/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py @@ -15,36 +15,31 @@ def getPumpsAndValvesWithValuesFromJson(projectJson): jsonValues = json.load(openFile) data = {} - blocks = jsonValues["Blocks"] - undesiredBlocks = [".__BlockDct__", "IDs", "Strings"] - # blockItemsInJson = filter(lambda x: x not in undesiredBlocks, blocks) - # blockNamesInJson = list(filter(lambda block: "BlockName" in blocks[block], blockItemsInJson)) - blockItemsInJson = [x for x in blocks if x not in undesiredBlocks] - blockNamesInJson = [x for x in blockItemsInJson if "BlockName" in blocks[x]] - - # pumps = list(filter(lambda block: "Pump" in blocks[block]["BlockName"], blockNamesInJson)) - pumps = [x for x in blockNamesInJson if blocks[x]["BlockName"] == "Pump"] + blockItemsAndConnections = jsonValues["Blocks"].values() + blockItems = [bc for bc in blockItemsAndConnections if isinstance(bc, dict) and ".__BlockDict__" in bc] + + pumps = [b for b in blockItems if b["BlockName"] == "Pump"] for pump in pumps: - curPump = _se.PumpModel.from_dict(blocks[pump]) - data[curPump.BlockDisplayName] = curPump.blockItemWithPrescribedMassFlow.massFlowRateInKgPerH + curBlockItem = _se.PumpModel.from_dict(pump) + data[curBlockItem.BlockDisplayName] = curBlockItem.blockItemWithPrescribedMassFlow.massFlowRateInKgPerH - # valves = list(filter(lambda block: "TVentil" in blocks[block]["BlockName"], blockNamesInJson)) - valves = [x for x in blockNamesInJson if blocks[x]["BlockName"] == "TVentil"] + valves = [b for b in blockItems if b["BlockName"] == "TVentil"] for valve in valves: desiredValueName = "PositionForMassFlowSolver" - data = getData(blocks[valve], data, desiredValueName) + data = getData(valve, data, desiredValueName) - # taps = list(filter(lambda block: blocks[block]["BlockName"] in ("WTap_main", "WTap"), blockNamesInJson)) - taps = [x for x in blockNamesInJson if blocks[x]["BlockName"] in ("WTap_main", "WTap")] + taps = [b for b in blockItems if b["BlockName"] in ("WTap_main", "WTap")] for tap in taps: - curTap = _se.TerminalWithPrescribedMassFlowModel.from_dict(blocks[tap]) - data[curTap.BlockDisplayName] = curTap.blockItemWithPrescribedMassFlow.massFlowRateInKgPerH + curBlockItem = _se.TerminalWithPrescribedMassFlowModel.from_dict(tap) + data[curBlockItem.BlockDisplayName] = curBlockItem.blockItemWithPrescribedMassFlow.massFlowRateInKgPerH - sourceSinks = [x for x in blockNamesInJson if blocks[x]["BlockName"] in ("Sink", "Source", "SourceSink", "Geotherm", "Water")] + sourceSinks = [ + b for b in blockItems if b["BlockName"] in ("Sink", "Source", "SourceSink", "Geotherm", "Water") + ] for sourceSink in sourceSinks: - """ This isn't in the json yet, so I am applying a default value directly at first. """ - BlockDisplayName = blocks[sourceSink]["BlockDisplayName"] - data[BlockDisplayName] = 500.0 + # This isn't in the json yet, so I am applying a default value directly at first. + blockDisplayName = sourceSink["BlockDisplayName"] + data[blockDisplayName] = 500.0 componentsAndValues = _pd.DataFrame(data, index=["dummy_regime"]) componentsAndValues.index.name = "regimeName" diff --git a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py index d56d141d..80de031c 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py +++ b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py @@ -16,6 +16,7 @@ import trnsysGUI.pythonInterface.regimeExporter.getDesiredRegimes as _gdr import trnsysGUI.TVentil as _tv import trnsysGUI.pumpsAndTaps._tapBase as _tb +import trnsysGUI.sourceSinkBase as _ssb @_dc.dataclass @@ -57,7 +58,7 @@ def getPumpsAndValvesAndMainTaps(self, pumpsAndValvesNames): pumpsAndValvesAndTaps = [] blockItemsAndConnections = self.mainWindow.editor.trnsysObj for blockItem in blockItemsAndConnections: - if isinstance(blockItem, (_pump.Pump, _tv.TVentil, _tb.TapBase)): + if isinstance(blockItem, (_pump.Pump, _tv.TVentil, _tb.TapBase, _ssb.SourceSinkBase)): if blockItem.displayName in pumpsAndValvesNames: pumpsAndValvesAndTaps.append(blockItem) @@ -96,7 +97,7 @@ def _adjustPumpsAndValves(pumpsAndValvesAndTaps, regimeRow) -> None: blockItemName = blockItem.displayName desiredValue = regimeRow[blockItemName] - if isinstance(blockItem, (_pump.Pump, _tb.TapBase)): + if isinstance(blockItem, (_pump.Pump, _tb.TapBase, _ssb.SourceSinkBase)): blockItem.massFlowRateInKgPerH = desiredValue elif isinstance(blockItem, _tv.TVentil): diff --git a/trnsysGUI/sourceSinkBase.py b/trnsysGUI/sourceSinkBase.py index b401ea85..aca07d7a 100644 --- a/trnsysGUI/sourceSinkBase.py +++ b/trnsysGUI/sourceSinkBase.py @@ -7,7 +7,7 @@ import trnsysGUI.images as _img import trnsysGUI.internalPiping as _ip import trnsysGUI.massFlowSolver.networkModel as _mfn -import trnsysGUI.pumpsAndTaps._defaults as _defaults +import trnsysGUI.pumpsAndTaps.defaults as _defaults class SourceSinkBase(_bip.BlockItemHasInternalPiping, _gimx.SvgBlockItemGraphicItemMixin): From 5283dc0ada6c071232d3909d7f2843d8caca03c2 Mon Sep 17 00:00:00 2001 From: ahobeost Date: Wed, 3 Jul 2024 15:02:22 +0200 Subject: [PATCH 54/56] Refactoring and adding type information --- .../regimeExporter/getDesiredRegimes.py | 7 +- .../renderDiagramOnPDFfromPython.py | 124 ++++++++---------- 2 files changed, 60 insertions(+), 71 deletions(-) diff --git a/trnsysGUI/pythonInterface/regimeExporter/getDesiredRegimes.py b/trnsysGUI/pythonInterface/regimeExporter/getDesiredRegimes.py index e77e823b..53f40025 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/getDesiredRegimes.py +++ b/trnsysGUI/pythonInterface/regimeExporter/getDesiredRegimes.py @@ -1,7 +1,10 @@ +import collections.abc as _cabc +import pathlib as _pl + import pandas as _pd -def getRegimesFromFile(fileName): +def getRegimesFromFile(fileName: _pl.Path) -> _pd.DataFrame: table = _pd.read_csv(fileName) colName = "regimeName" if colName in table.keys(): @@ -9,7 +12,7 @@ def getRegimesFromFile(fileName): raise ValueError(f"Column name '{colName}' not found.") -def getRegimes(filePath, onlyTheseRegimes): +def getRegimes(filePath: _pl.Path, onlyTheseRegimes: _cabc.Sequence[str] | None) -> _pd.DataFrame: regimeValues = getRegimesFromFile(filePath) regimeValues = regimeValues.set_index("regimeName") if onlyTheseRegimes: diff --git a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py index 80de031c..807d31e7 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py +++ b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py @@ -4,21 +4,26 @@ import subprocess as _sp import typing as _tp +import PyQt5.QtCore as _qtc import PyQt5.QtGui as _qtg import PyQt5.QtPrintSupport as _qtp import PyQt5.QtSvg as _qtsvg -import PyQt5.QtCore as _qtc +import pandas as _pd -import trnsysGUI.diagram.Editor as _de import trnsysGUI.MassFlowVisualizer as _mfv +import trnsysGUI.TVentil as _tv +import trnsysGUI.diagram.Editor as _de import trnsysGUI.mainWindow as _mw +import trnsysGUI.pumpsAndTaps._tapBase as _tb import trnsysGUI.pumpsAndTaps.pump as _pump import trnsysGUI.pythonInterface.regimeExporter.getDesiredRegimes as _gdr -import trnsysGUI.TVentil as _tv -import trnsysGUI.pumpsAndTaps._tapBase as _tb import trnsysGUI.sourceSinkBase as _ssb +_BlockItems = (_pump.Pump, _tv.TVentil, _tb.TapBase, _ssb.SourceSinkBase) +_BlockItem = _pump.Pump | _tv.TVentil | _tb.TapBase | _ssb.SourceSinkBase + + @_dc.dataclass class RegimeExporter: projectName: str @@ -28,12 +33,12 @@ class RegimeExporter: mainWindow: _mw.MainWindow # type: ignore[name-defined] @property - def massFlowRatesPrintFilePath(self): + def massFlowRatesPrintFilePath(self) -> _pl.Path: massFlowRatesPrintFileName = f"{self.projectName}_Mfr.prt" return self.projectDir / massFlowRatesPrintFileName @property - def temperaturesPrintFilePath(self): + def temperaturesPrintFilePath(self) -> _pl.Path: temperaturesPintFileName = f"{self.projectName}_T.prt" return self.projectDir / temperaturesPintFileName @@ -43,39 +48,37 @@ def export(self, onlyTheseRegimes: _tp.Optional[_tp.Sequence[str]] = None) -> No self._makeDiagramFiles() regimeValues = _gdr.getRegimes(self.projectDir / self.regimesFileName, onlyTheseRegimes) - pumpsAndValvesAndTapsNames = list(regimeValues.columns) - pumpsAndValvesAndTaps = self.getPumpsAndValvesAndMainTaps(pumpsAndValvesAndTapsNames) + relevantNames = list(regimeValues.columns) + relevantBlockItems = self.getRelevantBlockItems(relevantNames) - self._simulateAndVisualizeMassFlows(pumpsAndValvesAndTaps, regimeValues) + self._simulateAndVisualizeMassFlows(relevantBlockItems, regimeValues) - def _makeDiagramFiles(self, regimeName="diagram") -> None: + def _makeDiagramFiles(self, regimeName: str = "diagram") -> None: pdfName = self.resultsDir / f"{self.projectName}_{regimeName}.pdf" svgName = self.resultsDir / f"{self.projectName}_{regimeName}.svg" self._printDiagramToPDF(pdfName) self._printDiagramToSVG(svgName) - def getPumpsAndValvesAndMainTaps(self, pumpsAndValvesNames): - pumpsAndValvesAndTaps = [] + def getRelevantBlockItems(self, relevantNames: _tp.Sequence[str]) -> _tp.Sequence[_BlockItem]: blockItemsAndConnections = self.mainWindow.editor.trnsysObj - for blockItem in blockItemsAndConnections: - if isinstance(blockItem, (_pump.Pump, _tv.TVentil, _tb.TapBase, _ssb.SourceSinkBase)): - if blockItem.displayName in pumpsAndValvesNames: - pumpsAndValvesAndTaps.append(blockItem) + + pumpsAndValvesAndTaps = [ + b for b in blockItemsAndConnections if isinstance(b, _BlockItems) and b.displayName in relevantNames + ] return pumpsAndValvesAndTaps - def _simulateAndVisualizeMassFlows(self, pumpsAndValvesAndTaps, regimeValues) -> None: + def _simulateAndVisualizeMassFlows(self, relevantBlockItems: _tp.Sequence[_BlockItem], regimeValues: _pd.DataFrame) -> None: for regimeName in regimeValues.index: regimeRow = regimeValues.loc[regimeName] - self._adjustPumpsAndValves(pumpsAndValvesAndTaps, regimeRow) - - exception = runMassFlowSolver(self.mainWindow) + self._adjustPumpsAndValves(relevantBlockItems, regimeRow) - if not exception: + try: + _exportMassFlowSolverDeckAndRunTrnsys(self.mainWindow.editor) timeStep = 2 - else: + except (FileNotFoundError, _sp.CalledProcessError): regimeName = regimeName + "_FAILED" timeStep = 1 @@ -91,55 +94,46 @@ def _simulateAndVisualizeMassFlows(self, pumpsAndValvesAndTaps, regimeValues) -> massFlowSolverVisualizer.close() @staticmethod - def _adjustPumpsAndValves(pumpsAndValvesAndTaps, regimeRow) -> None: + def _adjustPumpsAndValves(relevantBlockItems: _tp.Sequence[_BlockItem], regimeRow: _pd.Series) -> None: - for blockItem in pumpsAndValvesAndTaps: + for blockItem in relevantBlockItems: blockItemName = blockItem.displayName desiredValue = regimeRow[blockItemName] - if isinstance(blockItem, (_pump.Pump, _tb.TapBase, _ssb.SourceSinkBase)): - blockItem.massFlowRateInKgPerH = desiredValue - - elif isinstance(blockItem, _tv.TVentil): - blockItem.positionForMassFlowSolver = desiredValue - - else: - raise AssertionError(f"Encountered blockItem of type {blockItem}, instead of a pump or a Valve") + match blockItem: + case _pump.Pump() | _tb.TapBase() | _ssb.SourceSinkBase() as hasMassFlowRate: + hasMassFlowRate.massFlowRateInKgPerH = desiredValue + case _tv.TVentil() as valve: + valve.positionForMassFlowSolver = desiredValue + case _: + _tp.assert_never(blockItem) def _printDiagramToPDF(self, fileName: _pl.Path) -> None: - if fileName != "": - printer = _qtp.QPrinter(_qtp.QPrinter.HighResolution) - printer.setOrientation(_qtp.QPrinter.Landscape) - printer.setOutputFormat(_qtp.QPrinter.PdfFormat) - printer.setOutputFileName(str(fileName)) - painter = _qtg.QPainter(printer) - self.mainWindow.editor.diagramScene.render(painter) - painter.end() + printer = _qtp.QPrinter(_qtp.QPrinter.HighResolution) + printer.setOrientation(_qtp.QPrinter.Landscape) + printer.setOutputFormat(_qtp.QPrinter.PdfFormat) + printer.setOutputFileName(str(fileName)) + painter = _qtg.QPainter(printer) + self.mainWindow.editor.diagramScene.render(painter) + painter.end() def _printDiagramToSVG(self, fileName: _pl.Path) -> None: # upside down and tiny compared to canvas - if fileName != "": - generator = _qtsvg.QSvgGenerator() - generator.setSize(_qtc.QSize(1600, 1600)) - generator.setViewBox(_qtc.QRect(0, 0, 1600, 1600)) - generator.setFileName(str(fileName)) - painter = _qtg.QPainter(generator) - self.mainWindow.editor.diagramScene.render(painter) - painter.end() - - -def runMassFlowSolver(mainWindow) -> _tp.Optional[Exception]: - exception = _exportMassFlowSolverDeckAndRunTrnsys(mainWindow.editor) - return exception + generator = _qtsvg.QSvgGenerator() + generator.setSize(_qtc.QSize(1600, 1600)) + generator.setViewBox(_qtc.QRect(0, 0, 1600, 1600)) + generator.setFileName(str(fileName)) + painter = _qtg.QPainter(generator) + self.mainWindow.editor.diagramScene.render(painter) + painter.end() -def _exportMassFlowSolverDeckAndRunTrnsys(editor: _de.Editor): # type: ignore[name-defined] +def _exportMassFlowSolverDeckAndRunTrnsys(editor: _de.Editor) -> None: # type: ignore[name-defined] exportedFilePath = str(_exportHydraulic(editor, formatting="mfs")) trnExePath = str(_getTrnExePath()) - _, exception = runDck(trnExePath, exportedFilePath) - return exception + runDck(trnExePath, exportedFilePath) def _exportHydraulic(editor: _de.Editor, *, formatting) -> str: # type: ignore[name-defined] @@ -147,7 +141,7 @@ def _exportHydraulic(editor: _de.Editor, *, formatting) -> str: # type: ignore[ return exportedFilePath -def _getTrnExePath(): +def _getTrnExePath() -> _pl.PureWindowsPath: isRunDuringCi = _os.environ.get("CI") == "true" if isRunDuringCi: return _pl.PureWindowsPath(r"C:\CI-Progams\TRNSYS18\Exe\TrnEXE.exe") @@ -155,16 +149,8 @@ def _getTrnExePath(): return _pl.PureWindowsPath(r"C:\TRNSYS18\Exe\TrnEXE.exe") -def runDck(cmd, dckName): - exception = None - try: - if _os.path.isfile(dckName): - _sp.run([cmd, dckName, "/H"], shell=True, check=True) - skipOthers = False - else: - raise FileNotFoundError("File not found: " + dckName) - except _sp.CalledProcessError as caughtException: - skipOthers = True - exception = caughtException +def runDck(cmd: str, dckName: str) -> None: + if not _os.path.isfile(dckName): + raise FileNotFoundError("File not found: " + dckName) - return skipOthers, exception + _sp.run([cmd, dckName, "/H"], shell=True, check=True) From cec2b14fff05669aaf8713203a12138cd3f3ef4a Mon Sep 17 00:00:00 2001 From: ahobeost Date: Wed, 3 Jul 2024 15:35:05 +0200 Subject: [PATCH 55/56] Refactoring for CI --- .../regimeExporter/exportRegimes.py | 53 +++++++++++++------ .../renderDiagramOnPDFfromPython.py | 4 +- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py b/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py index 6b24c319..a27169af 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py +++ b/trnsysGUI/pythonInterface/regimeExporter/exportRegimes.py @@ -18,33 +18,52 @@ def getPumpsAndValvesWithValuesFromJson(projectJson): blockItemsAndConnections = jsonValues["Blocks"].values() blockItems = [bc for bc in blockItemsAndConnections if isinstance(bc, dict) and ".__BlockDict__" in bc] - pumps = [b for b in blockItems if b["BlockName"] == "Pump"] - for pump in pumps: - curBlockItem = _se.PumpModel.from_dict(pump) + data = _getPumps(blockItems, data) + data = _getValves(blockItems, data) + data = _getTaps(blockItems, data) + data = _getSourceSinks(blockItems, data) + + componentsAndValues = _pd.DataFrame(data, index=["dummy_regime"]) + componentsAndValues.index.name = "regimeName" + + return componentsAndValues + + +def _getSourceSinks(blockItems, data): + sourceSinks = [b for b in blockItems if b["BlockName"] in ("Sink", "Source", "SourceSink", "Geotherm", "Water")] + for sourceSink in sourceSinks: + # This isn't in the json yet, so I am applying a default value directly at first. + blockDisplayName = sourceSink["BlockDisplayName"] + data[blockDisplayName] = 500.0 + + return data + + +def _getTaps(blockItems, data): + taps = [b for b in blockItems if b["BlockName"] in ("WTap_main", "WTap")] + for tap in taps: + curBlockItem = _se.TerminalWithPrescribedMassFlowModel.from_dict(tap) data[curBlockItem.BlockDisplayName] = curBlockItem.blockItemWithPrescribedMassFlow.massFlowRateInKgPerH + return data + + +def _getValves(blockItems, data): valves = [b for b in blockItems if b["BlockName"] == "TVentil"] for valve in valves: desiredValueName = "PositionForMassFlowSolver" data = getData(valve, data, desiredValueName) - taps = [b for b in blockItems if b["BlockName"] in ("WTap_main", "WTap")] - for tap in taps: - curBlockItem = _se.TerminalWithPrescribedMassFlowModel.from_dict(tap) - data[curBlockItem.BlockDisplayName] = curBlockItem.blockItemWithPrescribedMassFlow.massFlowRateInKgPerH + return data - sourceSinks = [ - b for b in blockItems if b["BlockName"] in ("Sink", "Source", "SourceSink", "Geotherm", "Water") - ] - for sourceSink in sourceSinks: - # This isn't in the json yet, so I am applying a default value directly at first. - blockDisplayName = sourceSink["BlockDisplayName"] - data[blockDisplayName] = 500.0 - componentsAndValues = _pd.DataFrame(data, index=["dummy_regime"]) - componentsAndValues.index.name = "regimeName" +def _getPumps(blockItems, data): + pumps = [b for b in blockItems if b["BlockName"] == "Pump"] + for pump in pumps: + curBlockItem = _se.PumpModel.from_dict(pump) + data[curBlockItem.BlockDisplayName] = curBlockItem.blockItemWithPrescribedMassFlow.massFlowRateInKgPerH - return componentsAndValues + return data def getData(curDict, data, desiredValueName): diff --git a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py index 807d31e7..f94d588a 100644 --- a/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py +++ b/trnsysGUI/pythonInterface/regimeExporter/renderDiagramOnPDFfromPython.py @@ -68,7 +68,9 @@ def getRelevantBlockItems(self, relevantNames: _tp.Sequence[str]) -> _tp.Sequenc return pumpsAndValvesAndTaps - def _simulateAndVisualizeMassFlows(self, relevantBlockItems: _tp.Sequence[_BlockItem], regimeValues: _pd.DataFrame) -> None: + def _simulateAndVisualizeMassFlows( + self, relevantBlockItems: _tp.Sequence[_BlockItem], regimeValues: _pd.DataFrame + ) -> None: for regimeName in regimeValues.index: regimeRow = regimeValues.loc[regimeName] From b11b53f184e8cf821c45e59f9fbef3738cc24eea Mon Sep 17 00:00:00 2001 From: ahobeost Date: Wed, 3 Jul 2024 15:48:27 +0200 Subject: [PATCH 56/56] Changed massflow of SourceSinkBase for CI. --- trnsysGUI/sourceSinkBase.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/trnsysGUI/sourceSinkBase.py b/trnsysGUI/sourceSinkBase.py index aca07d7a..61827331 100644 --- a/trnsysGUI/sourceSinkBase.py +++ b/trnsysGUI/sourceSinkBase.py @@ -7,7 +7,6 @@ import trnsysGUI.images as _img import trnsysGUI.internalPiping as _ip import trnsysGUI.massFlowSolver.networkModel as _mfn -import trnsysGUI.pumpsAndTaps.defaults as _defaults class SourceSinkBase(_bip.BlockItemHasInternalPiping, _gimx.SvgBlockItemGraphicItemMixin): @@ -17,7 +16,7 @@ def __init__(self, trnsysType: str, editor, displayName: str) -> None: self.w = 60 self.h = 60 - self.massFlowRateInKgPerH = _defaults.DEFAULT_MASS_FLOW_RATE + self.massFlowRateInKgPerH = 500 self.inputs.append(_cspi.createSinglePipePortItem("i", 1, self)) self.outputs.append(_cspi.createSinglePipePortItem("o", 1, self))