• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SPF-OST / pytrnsys_gui / 11576810878

29 Oct 2024 03:09PM UTC coverage: 67.508% (-0.08%) from 67.591%
11576810878

push

github

web-flow
Merge pull request #564 from SPF-OST/560-black-change-line-length-to-pep8-standard-of-79-and-check-ci-reaction

changed line length in black to 79

1054 of 1475 new or added lines in 174 files covered. (71.46%)

150 existing lines in 74 files now uncovered.

10399 of 15404 relevant lines covered (67.51%)

0.68 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.48
/trnsysGUI/storageTank/widget.py
1
import dataclasses as _dc
1✔
2
import pathlib as _pl
1✔
3
import random as _rnd
1✔
4
import typing as _tp
1✔
5

6
import PyQt5.QtGui as _qtg
1✔
7
import PyQt5.QtWidgets as _qtw
1✔
8
import dataclasses_jsonschema as _dcj
1✔
9

10
import trnsysGUI.blockItemGraphicItemMixins as _gimx
1✔
11
import trnsysGUI.blockItemHasInternalPiping as _bip
1✔
12
import trnsysGUI.components.ddckFolderHelpers as _dfh
1✔
13
import trnsysGUI.connection.names as _cnames
1✔
14
import trnsysGUI.createSinglePipePortItem as _cspi
1✔
15
import trnsysGUI.hydraulicLoops.model as _hlm
1✔
16
import trnsysGUI.hydraulicLoops.names as _lnames
1✔
17
import trnsysGUI.images as _img
1✔
18
import trnsysGUI.internalPiping as _ip
1✔
19
import trnsysGUI.massFlowSolver.names as _mnames
1✔
20
import trnsysGUI.massFlowSolver.networkModel as _mfn
1✔
21
import trnsysGUI.names.rename as _rename
1✔
22
import trnsysGUI.storageTank.side as _sd
1✔
23
import trnsysGUI.temperatures as _temps
1✔
24
from trnsysGUI import idGenerator as _id
1✔
25
from trnsysGUI.directPortPair import DirectPortPair
1✔
26
from trnsysGUI.heatExchanger import HeatExchanger  # type: ignore[attr-defined]
1✔
27
from trnsysGUI.singlePipePortItem import SinglePipePortItem
1✔
28
from trnsysGUI.storageTank import model as _model
1✔
29
from trnsysGUI.storageTank.ConfigureStorageDialog import ConfigureStorageDialog
1✔
30
from trnsysGUI.type1924.createType1924 import Type1924_TesPlugFlow  # type: ignore[attr-defined]
1✔
31

32
InOut = _tp.Literal["In", "Out"]
1✔
33
_T_co = _tp.TypeVar("_T_co", covariant=True)
1✔
34

35

36
@_dc.dataclass
1✔
37
class PortIds:
1✔
38
    inputId: int
1✔
39
    outputId: int
1✔
40

41

42
class StorageTank(
1✔
43
    _bip.BlockItemHasInternalPiping, _gimx.SvgBlockItemGraphicItemMixin
44
):
45
    # pylint: disable=too-many-instance-attributes,too-many-public-methods
46
    HEAT_EXCHANGER_WIDTH = 40
1✔
47

48
    def __init__(self, trnsysType: str, editor, displayName: str) -> None:
1✔
49
        super().__init__(trnsysType, editor, displayName)
1✔
50

51
        self.parent = editor
1✔
52

53
        self._hydraulicLoops: _tp.Optional[_hlm.HydraulicLoops] = None
1✔
54

55
        self.dckFilePath = ""
1✔
56

57
        self.directPortPairs: _tp.List[DirectPortPair] = []
1✔
58

59
        self.heatExchangers: _tp.List[HeatExchanger] = []
1✔
60

61
        idGenerator: _id.IdGenerator = self.editor.idGen
1✔
62
        self.nTes = idGenerator.getStoragenTes()
1✔
63
        self.storageType = idGenerator.getStorageType()
1✔
64

65
        self.changeSize()
1✔
66

67
    def setHydraulicLoops(self, hydraulicLoops: _hlm.HydraulicLoops) -> None:
1✔
68
        self._hydraulicLoops = hydraulicLoops
1✔
69

70
    def getDisplayName(self) -> str:
1✔
71
        return self.displayName
1✔
72

73
    @classmethod
1✔
74
    @_tp.override
1✔
75
    def hasDdckPlaceHolders(cls) -> bool:
1✔
76
        return False
1✔
77

78
    @classmethod
1✔
79
    @_tp.override
1✔
80
    def hasDdckDirectory(cls) -> bool:
1✔
81
        return True
×
82

83
    @property
1✔
84
    def leftDirectPortPairsPortItems(self):
1✔
85
        return self._getDirectPortPairPortItems(_sd.Side.LEFT)
1✔
86

87
    @property
1✔
88
    def rightDirectPortPairsPortItems(self):
1✔
89
        return self._getDirectPortPairPortItems(_sd.Side.RIGHT)
1✔
90

91
    def _getDirectPortPairPortItems(self, side: _sd.Side):
1✔
92
        return [
1✔
93
            p
94
            for dpp in self.directPortPairs
95
            if dpp.side == side
96
            for p in [dpp.fromPort, dpp.toPort]
97
        ]
98

99
    @classmethod
1✔
100
    @_tp.override
1✔
101
    # pylint: disable=arguments-differ
102
    def _getImageAccessor(
1✔
103
        cls,
104
    ) -> _img.SvgImageAccessor:
105
        return _img.STORAGE_TANK_SVG
×
106

107
    # Setter functions
108
    def setParent(self, p):
1✔
109
        self.logger.debug("Setting parent of Storage Tank (and its hx)")
1✔
110
        self.parent = p
1✔
111

112
        for heatExchanger in self.heatExchangers:
1✔
113
            heatExchanger.storageTank = self
1✔
114

115
    def addDirectPortPair(  # pylint: disable=too-many-arguments
1✔
116
        self,
117
        trnsysId: int,
118
        side: _sd.Side,
119
        relativeInputHeight: float,
120
        relativeOutputHeight: float,
121
        storageTankHeight: float,
122
        portIds: _tp.Optional[PortIds] = None,
123
    ):
124
        inputPort = self._createPort(
1✔
125
            "i", relativeInputHeight, storageTankHeight, side
126
        )
127
        outputPort = self._createPort(
1✔
128
            "o", relativeOutputHeight, storageTankHeight, side
129
        )
130

131
        randomInt = int(_rnd.uniform(20, 200))
1✔
132
        randomColor = _qtg.QColor(randomInt, randomInt, randomInt)
1✔
133
        self._setPortColor(inputPort, randomColor)
1✔
134
        self._setPortColor(outputPort, randomColor)
1✔
135

136
        if portIds:
1✔
137
            inputPort.id = portIds.inputId
1✔
138
            outputPort.id = portIds.outputId
1✔
139

140
        directPortPair = DirectPortPair(
1✔
141
            trnsysId,
142
            inputPort,
143
            outputPort,
144
            relativeInputHeight,
145
            relativeOutputHeight,
146
            side,
147
        )
148

149
        self.directPortPairs.append(directPortPair)
1✔
150

151
        self.inputs = [*self.inputs, directPortPair.fromPort]
1✔
152
        self.outputs = [*self.outputs, directPortPair.toPort]
1✔
153

154
    def _createPort(
1✔
155
        self,
156
        name: str,
157
        relativeHeight: float,
158
        storageTankHeight: float,
159
        side: _sd.Side,
160
    ) -> SinglePipePortItem:
161
        portItem = _cspi.createSinglePipePortItem(name, self)
1✔
162
        portItem.setZValue(100)
1✔
163
        xPos = 0 if side == _sd.Side.LEFT else self.w
1✔
164
        yPos = storageTankHeight - relativeHeight * storageTankHeight
1✔
165
        portItem.setPos(xPos, yPos)
1✔
166
        return portItem
1✔
167

168
    @staticmethod
1✔
169
    def _setPortColor(
1✔
170
        portItem: SinglePipePortItem, color: _qtg.QColor
171
    ) -> None:
172
        portItem.innerCircle.setBrush(color)
1✔
173
        portItem.visibleColor = color
1✔
174

175
    def addHeatExchanger(
1✔
176
        self, name, trnsysId, side, relativeInputHeight, relativeOutputHeight
177
    ):
178
        heatExchanger = HeatExchanger(
1✔
179
            trnsysId=trnsysId,
180
            sideNr=side.toSideNr(),
181
            width=self.HEAT_EXCHANGER_WIDTH,
182
            relativeInputHeight=relativeInputHeight,
183
            relativeOutputHeight=relativeOutputHeight,
184
            storageTankWidth=self.w,
185
            storageTankHeight=self.h,
186
            storageTank=self,
187
            name=name,
188
        )
189
        return heatExchanger
1✔
190

191
    def updateImage(self):
1✔
192
        super().updateImage()
1✔
193
        self.label.setPos(self.label.pos().x(), self.h)
1✔
194

195
    def setSize(self, *, width: int, height: int) -> None:
1✔
196
        self.prepareGeometryChange()
×
197

198
        deltaH = height - self.h
×
199
        deltaW = width - self.w
×
200
        self.w = width
×
201
        self.h = height
×
202
        self._updatePortItemPositionsAfterTankSizeChange(deltaW, deltaH)
×
203
        self._updateHeatExchangersAfterTankSizeChange()
×
204

205
    def _updatePortItemPositionsAfterTankSizeChange(
1✔
206
        self, deltaW: int, deltaH: int
207
    ) -> None:
208
        for portItem in self.inputs + self.outputs:
×
209
            oldRelativeHeight = portItem.pos().y() / self.h
×
210
            if portItem.side == 0:
×
NEW
211
                portItem.setPos(
×
212
                    portItem.pos().x(), oldRelativeHeight * (self.h + deltaH)
213
                )
214
            else:
NEW
215
                portItem.setPos(
×
216
                    portItem.pos().x() + deltaW,
217
                    oldRelativeHeight * (self.h + deltaH),
218
                )
219

220
    def _updateHeatExchangersAfterTankSizeChange(self):
1✔
221
        for heatExchanger in self.heatExchangers:
×
222
            heatExchanger.setTankSize(self.w, self.h)
×
223

224
    def encode(self):
1✔
225
        if not self.isVisible():
1✔
226
            raise RuntimeError("Cannot encode an invisible storage tank.")
×
227

228
        heatExchangerModels = self._getHeatExchangerModelsForEncode()
1✔
229
        portPairModels = self._getDirectPortPairModelsForEncode()
1✔
230
        position = float(self.pos().x()), float(self.pos().y())
1✔
231

232
        storageTankModel = _model.StorageTank(
1✔
233
            self.flippedH,
234
            self.flippedV,
235
            self.name,
236
            self.displayName,
237
            self.trnsysId,
238
            self.h,
239
            position,
240
            heatExchangerModels,
241
            portPairModels,
242
        )
243

244
        dictName = "Block-"
1✔
245
        return dictName, storageTankModel.to_dict()
1✔
246

247
    def _getDirectPortPairModelsForEncode(self):
1✔
248
        portPairModels = []
1✔
249
        for directPort in self.directPortPairs:
1✔
250
            side = _sd.Side.createFromSideNr(directPort.fromPort.side)
1✔
251

252
            inputPortModel = _model.Port(
1✔
253
                directPort.fromPort.id, directPort.relativeInputHeight
254
            )
255

256
            outputPortModel = _model.Port(
1✔
257
                directPort.toPort.id, directPort.relativeOutputHeight
258
            )
259

260
            portPairModel = _model.PortPair(
1✔
261
                side, directPort.trnsysId, inputPortModel, outputPortModel
262
            )
263

264
            directPortPairModel = _model.DirectPortPair(portPairModel)
1✔
265

266
            portPairModels.append(directPortPairModel)
1✔
267

268
        return portPairModels
1✔
269

270
    def _getHeatExchangerModelsForEncode(self):
1✔
271
        heatExchangerModels = []
1✔
272
        for heatExchanger in self.heatExchangers:
1✔
273
            side = _sd.Side.createFromSideNr(heatExchanger.sSide)
1✔
274

275
            inputPort = _model.Port(
1✔
276
                heatExchanger.port1.id,
277
                heatExchanger.relativeInputHeight,
278
            )
279

280
            outputPort = _model.Port(
1✔
281
                heatExchanger.port2.id,
282
                heatExchanger.relativeOutputHeight,
283
            )
284

285
            portPair = _model.PortPair(
1✔
286
                side, heatExchanger.trnsysId, inputPort, outputPort
287
            )
288

289
            heatExchangerModel = _model.HeatExchanger(
1✔
290
                portPair,
291
                heatExchanger.displayName,
292
                heatExchanger.w,
293
                heatExchanger.id,
294
            )
295

296
            heatExchangerModels.append(heatExchangerModel)
1✔
297

298
        return heatExchangerModels
1✔
299

300
    def decode(self, i: _dcj.JsonDict, resBlockList: list) -> None:
1✔
301
        offsetX = 0
1✔
302
        offsetY = 0
1✔
303

304
        self.logger.debug("Loading a Storage in Decoder")
1✔
305

306
        model = _model.StorageTank.from_dict(i)
1✔
307
        self.flippedH = model.isHorizontallyFlipped
1✔
308
        self.displayName = model.BlockDisplayName
1✔
309

310
        self.changeSize()
1✔
311

312
        self.h = model.height
1✔
313

314
        self.updateImage()
1✔
315

316
        self.setPos(model.position[0] + offsetX, model.position[1] + offsetY)
1✔
317
        self.trnsysId = model.trnsysId
1✔
318

319
        for heatExchangerModel in model.heatExchangers:
1✔
320
            self._decodeHeatExchanger(heatExchangerModel, True)
1✔
321

322
        for portPairModel in model.directPortPairs:
1✔
323
            self._decodeDirectPortPair(portPairModel)
1✔
324

325
        resBlockList.append(self)
1✔
326

327
    def _decodeDirectPortPair(
1✔
328
        self,
329
        portPairModel: _model.DirectPortPair,
330
    ) -> None:
331
        portPair = portPairModel.portPair
1✔
332

333
        portIds = PortIds(portPair.inputPort.id, portPair.outputPort.id)
1✔
334

335
        self.addDirectPortPair(
1✔
336
            portPair.trnsysId,
337
            portPair.side,
338
            portPair.inputPort.relativeHeight,
339
            portPair.outputPort.relativeHeight,
340
            storageTankHeight=self.h,
341
            portIds=portIds,
342
        )
343

344
    def _decodeHeatExchanger(
1✔
345
        self,
346
        heatExchangerModel: _model.HeatExchanger,
347
        shallSetNamesAndIDs: bool,
348
    ):
349
        portPair = heatExchangerModel.portPair
1✔
350

351
        nameSuffix = "" if shallSetNamesAndIDs else "New"
1✔
352
        name = heatExchangerModel.name + nameSuffix
1✔
353

354
        heatExchanger = self.addHeatExchanger(
1✔
355
            name,
356
            portPair.trnsysId,
357
            portPair.side,
358
            portPair.inputPort.relativeHeight,
359
            portPair.outputPort.relativeHeight,
360
        )
361

362
        if shallSetNamesAndIDs:
1✔
363
            heatExchanger.setId(heatExchangerModel.id)
1✔
364

365
        heatExchanger.port1.id = portPair.inputPort.id
1✔
366
        heatExchanger.port2.id = portPair.outputPort.id
1✔
367

368
    def assignIDsToUninitializedValuesAfterJsonFormatMigration(
1✔
369
        self, generator: _id.IdGenerator
370
    ) -> None:  # type: ignore[attr-defined]
371
        for heatExchanger in self.heatExchangers:
1✔
372
            if heatExchanger.trnsysId == generator.UNINITIALIZED_ID:
1✔
373
                heatExchanger.trnsysId = generator.getTrnsysID()
×
374

375
        for directPortPair in self.directPortPairs:
1✔
376
            if directPortPair.trnsysId == generator.UNINITIALIZED_ID:
1✔
377
                directPortPair.trnsysId = generator.getTrnsysID()
×
378

379
    def _getHeatExchangerForPortItem(
1✔
380
        self, portItem: SinglePipePortItem
381
    ) -> _tp.Optional[HeatExchanger]:
NEW
382
        heatExchanger = self._getSingleOrNone(
×
383
            hx
384
            for hx in self.heatExchangers
385
            if portItem in [hx.port1, hx.port2]
386
        )
387

388
        return heatExchanger
×
389

390
    def _getDirectPortPairForPortItemOrNone(
1✔
391
        self, portItem: SinglePipePortItem
392
    ) -> _tp.Optional[DirectPortPair]:
UNCOV
393
        directPortPair = self._getSingleOrNone(
×
394
            dpp
395
            for dpp in self.directPortPairs
396
            if portItem in [dpp.fromPort, dpp.toPort]
397
        )
398

399
        return directPortPair
×
400

401
    @staticmethod
1✔
402
    def _getSingleOrNone(iterable: _tp.Iterable[_T_co]) -> _tp.Optional[_T_co]:
1✔
403
        sequence = list(iterable)
×
404

405
        if not sequence:
×
406
            return None
×
407

408
        if len(sequence) > 1:
×
409
            raise ValueError("More than one value in iterable.")
×
410

411
        return sequence[0]
×
412

413
    # Misc
414
    def _addChildContextMenuActions(self, contextMenu: _qtw.QMenu) -> None:
1✔
415
        super()._addChildContextMenuActions(contextMenu)
×
416

417
        exportDdckAction = contextMenu.addAction("Export ddck")
×
418
        exportDdckAction.triggered.connect(self.exportDck)
×
419

420
    @_tp.no_type_check
1✔
421
    # pylint: disable=inconsistent-return-statements
422
    def mouseDoubleClickEvent(
1✔
423
        self, event: _qtw.QGraphicsSceneMouseEvent, isTest=False
424
    ) -> (_tp.Optional)[ConfigureStorageDialog]:
425
        renameHelper = _rename.RenameHelper(self.editor.namesManager)
1✔
426
        dialog = ConfigureStorageDialog(
1✔
427
            self, self.editor, renameHelper, self.editor.projectFolder
428
        )
429
        if isTest:
1✔
430
            return dialog
1✔
431
        dialog.exec()
×
432

433
    def getInternalPiping(self) -> _ip.InternalPiping:
1✔
434
        heatExchangerNodes = [hx.modelPipe for hx in self.heatExchangers]
1✔
435
        heatExchangerPortItems = {
1✔
436
            mpi: gpi
437
            for hx in self.heatExchangers
438
            for mpi, gpi in [
439
                (hx.modelPipe.fromPort, hx.port1),
440
                (hx.modelPipe.toPort, hx.port2),
441
            ]
442
        }
443

444
        portPairNodes = [pp.modelPipe for pp in self.directPortPairs]
1✔
445
        portPairsPortItems = {
1✔
446
            mpi: gpi
447
            for pp in self.directPortPairs
448
            for mpi, gpi in [
449
                (pp.modelPipe.fromPort, pp.fromPort),
450
                (pp.modelPipe.toPort, pp.toPort),
451
            ]
452
        }
453

454
        nodes = [*heatExchangerNodes, *portPairNodes]
1✔
455
        modelPortItemsToGraphicalPortItem = (
1✔
456
            heatExchangerPortItems | portPairsPortItems
457
        )
458

459
        return _ip.InternalPiping(nodes, modelPortItemsToGraphicalPortItem)
1✔
460

461
    def exportDck(
1✔
462
        self,
463
    ) -> None:  # pylint: disable=too-many-locals,too-many-statements
464
        if not self._areAllPortsConnected():
1✔
465
            msgb = _qtw.QMessageBox()
×
466
            msgb.setText("Please connect all ports before exporting!")
×
467
            msgb.exec_()
×
468
            return
×
469
        success = self._debugConn()
1✔
470

471
        if not success:
1✔
472
            qmb = _qtw.QMessageBox()
×
473
            qmb.setText("Ignore connection errors and continue with export?")
×
NEW
474
            qmb.setStandardButtons(
×
475
                _qtw.QMessageBox.Save | _qtw.QMessageBox.Cancel
476
            )
477
            qmb.setDefaultButton(_qtw.QMessageBox.Cancel)
×
478
            ret = qmb.exec()
×
479
            if ret == _qtw.QMessageBox.Save:
×
480
                self.logger.debug("Overwriting")
×
481
            else:
482
                self.logger.debug("Canceling")
×
483
                return
×
484

485
        nPorts = len(self.directPortPairs)
1✔
486
        nHx = len(self.heatExchangers)
1✔
487

488
        tool = Type1924_TesPlugFlow()
1✔
489

490
        inputs = {
1✔
491
            "nUnit": 50,
492
            "nType": self.storageType,
493
            "nTes": self.nTes,
494
            "nPorts": nPorts,
495
            "nHx": nHx,
496
            "nHeatSources": 1,
497
        }
498

499
        directPairsPorts = self._getDirectPairPortsForExport()
1✔
500

501
        heatExchangerPorts = self._getHeatExchangerPortsForExport()
1✔
502

503
        auxiliaryPorts = self._getAuxiliaryPortForExport(inputs)
1✔
504

505
        tool.setInputs(
1✔
506
            inputs, directPairsPorts, heatExchangerPorts, auxiliaryPorts
507
        )
508

509
        projectDirPath = _pl.Path(self.editor.projectFolder)
1✔
510
        ddckDirPath = _dfh.getComponentDdckDirPath(
1✔
511
            self.displayName, projectDirPath
512
        )
513

514
        if not ddckDirPath.is_dir():
1✔
515
            _qtw.QMessageBox.information(
×
516
                None,
517
                "Component ddck directory doesn't exist",
518
                f"The component ddck directory `{ddckDirPath}` does not exist. The ddck file will not be exported. "
519
                f"Please create the directory and try again.",
520
            )
521
            return
×
522

523
        tool.createDDck(str(ddckDirPath), self.displayName, typeFile="ddck")
1✔
524

525
    def _getDirectPairPortsForExport(self):
1✔
526
        directPairsPorts = []
1✔
527
        for directPortPair in self.directPortPairs:
1✔
528
            incomingConnection = directPortPair.fromPort.getConnection()
1✔
529
            inputTemperatureName = _cnames.getTemperatureVariableName(
1✔
530
                incomingConnection, _mfn.PortItemType.STANDARD
531
            )
532

533
            modelPipe = directPortPair.modelPipe
1✔
534
            massFlowRateName = _mnames.getMassFlowVariableName(
1✔
535
                self.displayName, modelPipe, modelPipe.fromPort
536
            )
537

538
            outgoingConnection = directPortPair.toPort.getConnection()
1✔
539
            reverseInputTemperatureName = _cnames.getTemperatureVariableName(
1✔
540
                outgoingConnection, _mfn.PortItemType.STANDARD
541
            )
542

543
            inputPos = directPortPair.relativeInputHeight
1✔
544
            outputPos = directPortPair.relativeOutputHeight
1✔
545

546
            outputTemperatureName = _temps.getInternalTemperatureVariableName(
1✔
547
                componentDisplayName=self.displayName, nodeName=modelPipe.name
548
            )
549

550
            directPairsPort = {
1✔
551
                "T": inputTemperatureName,
552
                "side": directPortPair.side.formatDdck(),
553
                "Mfr": massFlowRateName,
554
                "Trev": reverseInputTemperatureName,
555
                "zIn": inputPos,
556
                "zOut": outputPos,
557
                "Tout": outputTemperatureName,
558
            }
559
            directPairsPorts.append(directPairsPort)
1✔
560
        return directPairsPorts
1✔
561

562
    def _getHeatExchangerPortsForExport(self):
1✔
563
        heatExchangerPorts = []
1✔
564
        for heatExchanger in self.heatExchangers:
1✔
565
            heatExchangerPort = self._getHeatExchangerPortForExport(
1✔
566
                heatExchanger
567
            )
568

569
            heatExchangerPorts.append(heatExchangerPort)
1✔
570
        return heatExchangerPorts
1✔
571

572
    def _getHeatExchangerPortForExport(
1✔
573
        self, heatExchanger
574
    ):  # pylint: disable=too-many-locals
575
        heatExchangerName = heatExchanger.displayName
1✔
576

577
        incomingConnection = heatExchanger.port1.getConnection()
1✔
578
        inputTemperatureName = _cnames.getTemperatureVariableName(
1✔
579
            incomingConnection, _mfn.PortItemType.STANDARD
580
        )
581
        modelPipe = heatExchanger.modelPipe
1✔
582
        massFlowRateName = _mnames.getMassFlowVariableName(
1✔
583
            self.displayName, modelPipe, modelPipe.fromPort
584
        )
585

586
        outgoingConnection = heatExchanger.port2.getConnection()
1✔
587
        reverseInputTemperatureName = _cnames.getTemperatureVariableName(
1✔
588
            outgoingConnection, _mfn.PortItemType.STANDARD
589
        )
590

591
        inputPos = heatExchanger.relativeInputHeight
1✔
592
        outputPos = heatExchanger.relativeOutputHeight
1✔
593

594
        outputTemperatureName = _temps.getInternalTemperatureVariableName(
1✔
595
            componentDisplayName=self.displayName, nodeName=modelPipe.name
596
        )
597

598
        loop = self._hydraulicLoops.getLoopForExistingConnection(
1✔
599
            incomingConnection
600
        )
601
        loopName = loop.name.value
1✔
602

603
        heatExchangerPort = {
1✔
604
            "Name": heatExchangerName,
605
            "T": inputTemperatureName,
606
            "Mfr": massFlowRateName,
607
            "Trev": reverseInputTemperatureName,
608
            "zIn": inputPos,
609
            "zOut": outputPos,
610
            "Tout": outputTemperatureName,
611
            "cp": _lnames.getHeatCapacityName(loopName),
612
            "rho": _lnames.getDensityName(loopName),
613
        }
614

615
        return heatExchangerPort
1✔
616

617
    @staticmethod
1✔
618
    def _getAuxiliaryPortForExport(inputs):
1✔
619
        auxiliaryPorts = []
1✔
620
        for _ in range(inputs["nHeatSources"]):
1✔
621
            dictInputAux = {"zAux": 0.0, "qAux": 0.0}
1✔
622
            auxiliaryPorts.append(dictInputAux)
1✔
623
        return auxiliaryPorts
1✔
624

625
    def _debugConn(self):
1✔
626
        self.logger.debug("Debugging conn")
1✔
627
        errorConnList = ""
1✔
628
        for directPort in self.directPortPairs:
1✔
629
            stFromPort = directPort.fromPort
1✔
630
            stToPort = directPort.toPort
1✔
631
            toPort1 = stFromPort.connectionList[0].toPort
1✔
632
            fromPort2 = stToPort.connectionList[0].fromPort
1✔
633
            connName1 = stFromPort.connectionList[0].displayName
1✔
634
            connName2 = stToPort.connectionList[0].displayName
1✔
635

636
            if stFromPort != toPort1:
1✔
637
                errorConnList = errorConnList + connName1 + "\n"
×
638
            if stToPort != fromPort2:
1✔
639
                errorConnList = errorConnList + connName2 + "\n"
×
640
        if errorConnList != "":
1✔
641
            msgBox = _qtw.QMessageBox()
×
NEW
642
            msgBox.setText(
×
643
                f"{errorConnList} is connected wrongly, right click StorageTank to invert connection."
644
            )
645
            msgBox.exec()
×
646
            noError = False
×
647
        else:
648
            noError = True
1✔
649

650
        return noError
1✔
651

652
    def _areAllPortsConnected(self):
1✔
653
        for heatExchanger in self.heatExchangers:
1✔
654
            if not heatExchanger.port1.connectionList:
1✔
655
                return False
×
656
            if not heatExchanger.port2.connectionList:
1✔
657
                return False
×
658

659
        for ports in self.leftDirectPortPairsPortItems:
1✔
660
            if not ports.connectionList:
1✔
661
                return False
×
662

663
        for ports in self.rightDirectPortPairsPortItems:
1✔
664
            if not ports.connectionList:
1✔
665
                return False
×
666

667
        return True
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc