class Boiler(BlockItem, MassFlowNetworkContributorMixin): def __init__(self, trnsysType, parent, **kwargs): super(Boiler, self).__init__(trnsysType, parent, **kwargs) self.w = 80 self.h = 120 self.portOffset = 5 self.inputs.append(_cspi.createSinglePipePortItem("i", 2, self)) self.outputs.append(_cspi.createSinglePipePortItem("o", 2, self)) self.loadedFiles = [] self.changeSize() self.addTree() def _getImageAccessor(self) -> _tp.Optional[_img.ImageAccessor]: return _img.BOILER_SVG def changeSize(self): self.logger.debug("passing through c change size") w = self.w h = self.h """ Resize block function """ delta = 20 deltaH = self.h / 10 # Limit the block size: if h < 20: h = 20 if w < 40: w = 40 # center label: rect = self.label.boundingRect() lw, lh = rect.width(), rect.height() lx = (w - lw) / 2 self.label.setPos(lx, h) self.origInputsPos = [[w, delta]] self.origOutputsPos = [[w, h - delta]] self.inputs[0].setPos(self.origInputsPos[0][0], self.origInputsPos[0][1]) self.outputs[0].setPos(self.origOutputsPos[0][0], self.origOutputsPos[0][1]) self.updateFlipStateH(self.flippedH) self.updateFlipStateV(self.flippedV) self.inputs[0].side = (self.rotationN + 2 - 2 * self.flippedH) % 4 self.outputs[0].side = (self.rotationN + 2 - 2 * self.flippedH) % 4 self.logger.debug(self.outputs[0].pos()) return w, h def addTree(self): """ When a blockitem is added to the main window. A file explorer for that item is added to the right of the main window by calling this method """ self.logger.debug(self.parent.parent()) pathName = self.displayName if self.parent.parent().projectPath == "": # self.path = os.path.dirname(__file__) # self.path = os.path.join(self.path, 'default') self.path = self.parent.parent().projectFolder # now = datetime.now() # self.fileName = now.strftime("%Y%m%d%H%M%S") # self.path = os.path.join(self.path, self.fileName) else: self.path = self.parent.parent().projectPath self.path = os.path.join(self.path, "ddck") self.path = os.path.join(self.path, pathName) if not os.path.exists(self.path): os.makedirs(self.path) self.model = MyQFileSystemModel() self.model.setRootPath(self.path) self.model.setName(self.displayName) self.tree = MyQTreeView(self.model, self) self.tree.setModel(self.model) self.tree.setRootIndex(self.model.index(self.path)) self.tree.setObjectName("%sTree" % self.displayName) for i in range(1, self.model.columnCount() - 1): self.tree.hideColumn(i) self.tree.setMinimumHeight(200) self.tree.setSortingEnabled(True) self.parent.parent().splitter.addWidget(self.tree) def deleteBlock(self): """ Overridden method to also delete folder """ self.logger.debug("Block " + str(self) + " is deleting itself (" + self.displayName + ")") self.deleteConns() # self.logger.debug("self.parent.parent" + str(self.parent.parent())) self.parent.parent().trnsysObj.remove(self) self.logger.debug("deleting block " + str(self) + self.displayName) # self.logger.debug("self.scene is" + str(self.parent.scene())) self.parent.scene().removeItem(self) widgetToRemove = self.parent.parent().findChild( QTreeView, self.displayName + "Tree") shutil.rmtree(self.path) self.deleteLoadedFile() try: widgetToRemove.hide() except AttributeError: self.logger.debug("Widget doesnt exist!") else: self.logger.debug("Deleted widget") del self def setName(self, newName): """ Overridden method to also change folder name """ self.displayName = newName self.label.setPlainText(newName) self.model.setName(self.displayName) self.tree.setObjectName("%sTree" % self.displayName) self.logger.debug(os.path.dirname(self.path)) # destPath = str(os.path.dirname(self.path))+'\\Boiler_'+self.displayName destPath = os.path.join(os.path.split(self.path)[0], self.displayName) if os.path.exists(self.path): os.rename(self.path, destPath) self.path = destPath self.logger.debug(self.path)
class HeatPump(BlockItem, MassFlowNetworkContributorMixin): def __init__(self, trnsysType, parent, **kwargs): super().__init__(trnsysType, parent, **kwargs) self.inputs.append(_cspi.createSinglePipePortItem("i", 0, self)) self.inputs.append(_cspi.createSinglePipePortItem("i", 2, self)) self.outputs.append(_cspi.createSinglePipePortItem("o", 0, self)) self.outputs.append(_cspi.createSinglePipePortItem("o", 2, self)) self.loadedFiles = [] # For restoring correct order of trnsysObj list self.childIds = [] self.childIds.append(self.trnsysId) self.childIds.append(self.parent.parent().idGen.getTrnsysID()) self.changeSize() self.addTree() def _getImageAccessor(self) -> _tp.Optional[_img.ImageAccessor]: return _img.HP_SVG def changeSize(self): w = self.w h = self.h """ Resize block function """ delta = 20 # Limit the block size: if h < 20: h = 20 if w < 40: w = 40 # center label: rect = self.label.boundingRect() lw, lh = rect.width(), rect.height() lx = (w - lw) / 2 self.label.setPos(lx, h) # upper left is reference self.origInputsPos = [[0, delta], [w, h - delta]] # inlet of [evap, cond] self.origOutputsPos = [[0, h - delta], [w, delta]] # outlet of [evap, cond] self.inputs[0].setPos(self.origInputsPos[0][0], self.origInputsPos[0][1]) #evaporator self.inputs[1].setPos(self.origInputsPos[1][0], self.origInputsPos[1][1]) #condenser self.outputs[0].setPos(self.origOutputsPos[0][0], self.origOutputsPos[0][1]) self.outputs[1].setPos(self.origOutputsPos[1][0], self.origOutputsPos[1][1]) self.updateFlipStateH(self.flippedH) self.updateFlipStateV(self.flippedV) self.inputs[0].side = (self.rotationN + 2 * self.flippedH) % 4 self.inputs[1].side = (self.rotationN + 2 - 2 * self.flippedH) % 4 self.outputs[0].side = (self.rotationN + 2 * self.flippedH) % 4 self.outputs[1].side = (self.rotationN + 2 - 2 * self.flippedH) % 4 return w, h def encode(self): if self.isVisible(): self.logger.debug("Encoding a HeatPump") portListInputs = [] portListOutputs = [] for p in self.inputs: portListInputs.append(p.id) for p in self.outputs: portListOutputs.append(p.id) dct = {} dct[".__BlockDict__"] = True dct["BlockName"] = self.name dct["BlockDisplayName"] = self.displayName dct["PortsIDIn"] = portListInputs dct["PortsIDOut"] = portListOutputs dct["HeatPumpPosition"] = (float(self.pos().x()), float(self.pos().y())) dct["ID"] = self.id dct["trnsysID"] = self.trnsysId dct["childIds"] = self.childIds dct["FlippedH"] = self.flippedH dct["FlippedV"] = self.flippedH dct["RotationN"] = self.rotationN dictName = "Block-" return dictName, dct def decode(self, i, resBlockList): self.logger.debug("Loading a HeatPump block") self.flippedH = i["FlippedH"] self.flippedV = i["FlippedV"] self.childIds = i["childIds"] self.displayName = i["BlockDisplayName"] self.changeSize() for x in range(len(self.inputs)): self.inputs[x].id = i["PortsIDIn"][x] self.logger.debug("Input at heatExchanger") for x in range(len(self.outputs)): self.outputs[x].id = i["PortsIDOut"][x] self.logger.debug("Output at heatExchanger") self.setPos(float(i["HeatPumpPosition"][0]), float(i["HeatPumpPosition"][1])) self.trnsysId = i["trnsysID"] self.id = i["ID"] resBlockList.append(self) def decodePaste(self, i, offset_x, offset_y, resConnList, resBlockList, **kwargs): self.logger.debug("Loading a HeatPump in Decoder") self.changeSize() for x in range(len(self.inputs)): self.inputs[x].id = i["PortsIDIn"][x] self.logger.debug("Input at heatExchanger") for x in range(len(self.outputs)): self.outputs[x].id = i["PortsIDOut"][x] self.logger.debug("Output at heatExchanger") self.setPos( float(i["HeatPumpPosition"][0]) + offset_x, float(i["HeatPumpPosition"][1] + offset_y)) resBlockList.append(self) def exportBlackBox(self): equation = [] files = glob.glob(os.path.join(self.path, "**/*.ddck"), recursive=True) if not (files): status = "noDdckFile" for i in range(1, 3): equation.append("T" + self.displayName + "X" + str(i) + "=1") else: status = "noDdckEntry" lines = [] for file in files: infile = open(file, "r") lines += infile.readlines() for i in range(len(lines)): if "output" in lines[i].lower() and "to" in lines[i].lower( ) and "hydraulic" in lines[i].lower(): counter = 1 for j in range(i, len(lines) - i): if lines[j][0] == "T": outputT = lines[j].split("=")[0].replace(" ", "") equation.append("T" + self.displayName + "X" + str(counter) + "=1 ! suggestion: " + outputT) counter += 1 if counter == 3: status = "success" break break return status, equation def getInternalPiping(self) -> InternalPiping: condenserInput = _mfn.PortItem("Condenser Input", _mfn.PortItemType.INPUT) condenserOutput = _mfn.PortItem("Condenser Output", _mfn.PortItemType.OUTPUT) condenserPipe = _mfn.Pipe(f"{self.displayName}Cond", self.childIds[0], condenserInput, condenserOutput) evaporatorInput = _mfn.PortItem("Evaporator Input", _mfn.PortItemType.INPUT) evaporatorOutput = _mfn.PortItem("Evaporator Output", _mfn.PortItemType.OUTPUT) evaporatorPipe = _mfn.Pipe(f"{self.displayName}Evap", self.childIds[1], evaporatorInput, evaporatorOutput) modelPortItemsToGraphicalPortItem = { condenserInput: self.inputs[1], condenserOutput: self.outputs[1], evaporatorInput: self.inputs[0], evaporatorOutput: self.outputs[0], } nodes = [condenserPipe, evaporatorPipe] return InternalPiping(nodes, modelPortItemsToGraphicalPortItem) def getSubBlockOffset(self, c): for i in range(2): if (self.inputs[i] == c.toPort or self.inputs[i] == c.fromPort or self.outputs[i] == c.toPort or self.outputs[i] == c.fromPort): return i def addTree(self): """ When a blockitem is added to the main window. A file explorer for that item is added to the right of the main window by calling this method """ self.logger.debug(self.parent.parent()) pathName = self.displayName if self.parent.parent().projectPath == "": self.path = self.parent.parent().projectFolder else: self.path = self.parent.parent().projectPath self.path = os.path.join(self.path, "ddck") self.path = os.path.join(self.path, pathName) if not os.path.exists(self.path): os.makedirs(self.path) self.model = MyQFileSystemModel() self.model.setRootPath(self.path) self.model.setName(self.displayName) self.tree = MyQTreeView(self.model, self) self.tree.setModel(self.model) self.tree.setRootIndex(self.model.index(self.path)) self.tree.setObjectName("%sTree" % self.displayName) for i in range(1, self.model.columnCount() - 1): self.tree.hideColumn(i) self.tree.setMinimumHeight(200) self.tree.setSortingEnabled(True) self.parent.parent().splitter.addWidget(self.tree) def deleteBlock(self): """ Overridden method to also delete folder """ self.logger.debug("Block " + str(self) + " is deleting itself (" + self.displayName + ")") self.deleteConns() self.parent.parent().trnsysObj.remove(self) self.logger.debug("deleting block " + str(self) + self.displayName) self.parent.scene().removeItem(self) widgetToRemove = self.parent.parent().findChild( QTreeView, self.displayName + "Tree") shutil.rmtree(self.path) self.deleteLoadedFile() try: widgetToRemove.hide() except AttributeError: self.logger.debug("Widget doesnt exist!") else: self.logger.debug("Deleted widget") del self def setName(self, newName): """ Overridden method to also change folder name """ self.displayName = newName self.label.setPlainText(newName) self.model.setName(self.displayName) self.tree.setObjectName("%sTree" % self.displayName) self.logger.debug(os.path.dirname(self.path)) destPath = os.path.join(os.path.split(self.path)[0], self.displayName) if os.path.exists(self.path): os.rename(self.path, destPath) self.path = destPath self.logger.debug(self.path)
class HeatPumpTwoHx(BlockItem, MassFlowNetworkContributorMixin): def __init__(self, trnsysType, parent, **kwargs): super(HeatPumpTwoHx, self).__init__(trnsysType, parent, **kwargs) self.inputs.append(_cspi.createSinglePipePortItem("i", 0, self)) self.inputs.append(_cspi.createSinglePipePortItem("i", 2, self)) self.inputs.append(_cspi.createSinglePipePortItem("i", 2, self)) self.outputs.append(_cspi.createSinglePipePortItem("o", 0, self)) self.outputs.append(_cspi.createSinglePipePortItem("o", 2, self)) self.outputs.append(_cspi.createSinglePipePortItem("o", 2, self)) self.loadedFiles = [] # For restoring correct order of trnsysObj list self.childIds = [] self.childIds.append(self.trnsysId) self.childIds.append(self.parent.parent().idGen.getTrnsysID()) self.childIds.append(self.parent.parent().idGen.getTrnsysID()) self.changeSize() self.addTree() def _getImageAccessor(self) -> _tp.Optional[_img.ImageAccessor]: return _img.HP_TWO_HX_SVG def changeSize(self): w = self.w h = self.h """ Resize block function """ delta = 20 # Limit the block size: if h < 20: h = 20 if w < 40: w = 40 # center label: rect = self.label.boundingRect() lw, lh = rect.width(), rect.height() lx = (w - lw) / 2 self.label.setPos(lx, h) self.origInputsPos = [[0, delta], [w, 2 * delta], [w, h - delta]] # inlet of [evap, cond, cond] self.origOutputsPos = [[0, h - delta], [w, delta], [w, h - 2 * delta]] # outlet of [evap, cond, cond] self.inputs[0].setPos(self.origInputsPos[0][0], self.origInputsPos[0][1]) #evaporator self.inputs[1].setPos(self.origInputsPos[1][0], self.origInputsPos[1][1]) # top condenser self.inputs[2].setPos(self.origInputsPos[2][0], self.origInputsPos[2][1]) # bottom condenser self.outputs[0].setPos(self.origOutputsPos[0][0], self.origOutputsPos[0][1]) #evaporator self.outputs[1].setPos(self.origOutputsPos[1][0], self.origOutputsPos[1][1]) # top condenser self.outputs[2].setPos(self.origOutputsPos[2][0], self.origOutputsPos[2][1]) # bottom condenser self.updateFlipStateH(self.flippedH) self.updateFlipStateV(self.flippedV) self.inputs[0].side = (self.rotationN + 2 * self.flippedH) % 4 self.inputs[1].side = (self.rotationN + 2 - 2 * self.flippedH) % 4 self.inputs[2].side = (self.rotationN + 2 - 2 * self.flippedH) % 4 self.outputs[0].side = (self.rotationN + 2 * self.flippedH) % 4 self.outputs[1].side = (self.rotationN + 2 - 2 * self.flippedH) % 4 self.outputs[2].side = (self.rotationN + 2 - 2 * self.flippedH) % 4 return w, h def encode(self): if self.isVisible(): self.logger.debug("Encoding a HeatPump") portListInputs = [] portListOutputs = [] for p in self.inputs: portListInputs.append(p.id) for p in self.outputs: portListOutputs.append(p.id) dct = {} dct[".__BlockDict__"] = True dct["BlockName"] = self.name dct["BlockDisplayName"] = self.displayName dct["PortsIDIn"] = portListInputs dct["PortsIDOut"] = portListOutputs dct["HeatPumpPosition"] = (float(self.pos().x()), float(self.pos().y())) dct["ID"] = self.id dct["trnsysID"] = self.trnsysId dct["childIds"] = self.childIds dct["FlippedH"] = self.flippedH dct["FlippedV"] = self.flippedV dct["RotationN"] = self.rotationN dictName = "Block-" return dictName, dct def decode(self, i, resBlockList): self.flippedH = i["FlippedH"] self.flippedV = i["FlippedV"] self.childIds = i["childIds"] self.displayName = i["BlockDisplayName"] self.changeSize() for x in range(len(self.inputs)): self.inputs[x].id = i["PortsIDIn"][x] self.logger.debug("Input at heatExchanger") for x in range(len(self.outputs)): self.outputs[x].id = i["PortsIDOut"][x] self.logger.debug("Output at heatExchanger") self.setPos(float(i["HeatPumpPosition"][0]), float(i["HeatPumpPosition"][1])) self.trnsysId = i["trnsysID"] self.id = i["ID"] resBlockList.append(self) def decodePaste(self, i, offset_x, offset_y, resConnList, resBlockList, **kwargs): self.flippedH = i["FlippedH"] self.flippedV = i["FlippedV"] self.changeSize() for x in range(len(self.inputs)): self.inputs[x].id = i["PortsIDIn"][x] self.logger.debug("Input at heatExchanger") for x in range(len(self.outputs)): self.outputs[x].id = i["PortsIDOut"][x] self.logger.debug("Output at heatExchanger") self.setPos(float(i["HeatPumpPosition"][0] + offset_x), float(i["HeatPumpPosition"][1] + offset_y)) # self.trnsysId = i["trnsysID"] # self.id = i["ID"] resBlockList.append(self) def exportBlackBox(self): equations = ["T" + self.displayName + "X1" + "=1"] equations.append("T" + self.displayName + "X2" + "=1") equations.append("T" + self.displayName + "X3" + "=1") status = "success" return status, equations def getInternalPiping(self) -> InternalPiping: pipes = [] portItems = {} for i in range(3): inputPort = _mfn.PortItem(f"Input {i+1}", _mfn.PortItemType.INPUT) outputPort = _mfn.PortItem(f"Output {i+1}", _mfn.PortItemType.OUTPUT) pipe = _mfn.Pipe(f"{self.displayName}Side{i+1}", self.childIds[i], inputPort, outputPort) pipes.append(pipe) portItems[inputPort] = self.inputs[i] portItems[outputPort] = self.outputs[i] return InternalPiping(pipes, portItems) def getSubBlockOffset(self, c): for i in range(3): if (self.inputs[i] == c.toPort or self.inputs[i] == c.fromPort or self.outputs[i] == c.toPort or self.outputs[i] == c.fromPort): return i def addTree(self): """ When a blockitem is added to the main window. A file explorer for that item is added to the right of the main window by calling this method """ self.logger.debug(self.parent.parent()) pathName = self.displayName if self.parent.parent().projectPath == "": # self.path = os.path.dirname(__file__) # self.path = os.path.join(self.path, 'default') self.path = self.parent.parent().projectFolder # now = datetime.now() # self.fileName = now.strftime("%Y%m%d%H%M%S") # self.path = os.path.join(self.path, self.fileName) else: self.path = self.parent.parent().projectPath self.path = os.path.join(self.path, "ddck") self.path = os.path.join(self.path, pathName) if not os.path.exists(self.path): os.makedirs(self.path) self.model = MyQFileSystemModel() self.model.setRootPath(self.path) self.model.setName(self.displayName) self.tree = MyQTreeView(self.model, self) self.tree.setModel(self.model) self.tree.setRootIndex(self.model.index(self.path)) self.tree.setObjectName("%sTree" % self.displayName) for i in range(1, self.model.columnCount() - 1): self.tree.hideColumn(i) self.tree.setMinimumHeight(200) self.tree.setSortingEnabled(True) self.parent.parent().splitter.addWidget(self.tree) def deleteBlock(self): """ Overridden method to also delete folder """ self.logger.debug("Block " + str(self) + " is deleting itself (" + self.displayName + ")") self.deleteConns() # self.logger.debug("self.parent.parent" + str(self.parent.parent())) self.parent.parent().trnsysObj.remove(self) self.logger.debug("deleting block " + str(self) + self.displayName) # self.logger.debug("self.scene is" + str(self.parent.scene())) self.parent.scene().removeItem(self) widgetToRemove = self.parent.parent().findChild( QTreeView, self.displayName + "Tree") shutil.rmtree(self.path) self.deleteLoadedFile() try: widgetToRemove.hide() except AttributeError: self.logger.debug("Widget doesnt exist!") else: self.logger.debug("Deleted widget") del self def setName(self, newName): """ Overridden method to also change folder name """ self.displayName = newName self.label.setPlainText(newName) self.model.setName(self.displayName) self.tree.setObjectName("%sTree" % self.displayName) self.logger.debug(os.path.dirname(self.path)) # destPath = str(os.path.dirname(self.path))+'\\HPTwoHx_'+self.displayName destPath = os.path.join(os.path.split(self.path)[0], self.displayName) if os.path.exists(self.path): os.rename(self.path, destPath) self.path = destPath self.logger.debug(self.path)
class GenericBlock(BlockItem, MassFlowNetworkContributorMixin): def __init__(self, trnsysType, parent, **kwargs): super(GenericBlock, self).__init__(trnsysType, parent, **kwargs) self.inputs.append(_cspi.createSinglePipePortItem("i", 2, self)) self.outputs.append(_cspi.createSinglePipePortItem("o", 2, self)) self.loadedFiles = [] self.childIds = [] self.childIds.append(self.trnsysId) self._imageAccessor = _img.GENERIC_BLOCK_PNG # Disallow adding port pairs later, because the trnsysIDs of the generated port pairs have to be # consecutive to be correctly printed out in the export self.isSet = True self.changeSize() self.addTree() def _getImageAccessor(self) -> _tp.Optional[_img.ImageAccessor]: return _img.GENERIC_BLOCK_PNG def changeSize(self): w = self.w h = self.h delta = 4 """ Resize block function """ # Limit the block size: if h < 20: h = 20 if w < 40: w = 40 # center label: rect = self.label.boundingRect() lw, lh = rect.width(), rect.height() lx = (w - lw) / 2 self.label.setPos(lx, h) self.outputs[0].setPos(2 * delta + w, h - 2 * delta) self.inputs[0].setPos(2 * delta + w, 2 * delta) return w, h def getPairNb(self, side): res = 0 for i in self.inputs: if i.side == side: res += 1 self.logger.debug("there are " + str(res) + " pairs on the side " + str(side)) return res def addPortDlg(self): self.parent.parent().showGenericPortPairDlg(self) def addPort(self, io, relH): self.logger.debug(io) self.logger.debug(relH) def setImage(self): pixmap = self._getPixmap() self.setPixmap(pixmap) def changeImage(self): name = str(self.pickImage().resolve()) if name[-3:] == "png" or name[-3:] == "svg": self.setImageSource(name) self.setImage() else: self.logger.debug("No image picked, name is " + name) def setImageSource(self, name): self._imageAccessor = _img.ImageAccessor.createForFile(_pl.Path(name)) def pickImage(self): return _pl.Path( QFileDialog.getOpenFileName(self.parent.parent(), filter="*.png *.svg")[0]) def contextMenuEvent(self, event): menu = QMenu() a1 = menu.addAction("Launch NotePad++") a1.triggered.connect(self.launchNotepadFile) rr = _img.ROTATE_TO_RIGHT_PNG.icon() a2 = menu.addAction(rr, "Rotate Block clockwise") a2.triggered.connect(self.rotateBlockCW) ll = _img.ROTATE_LEFT_PNG.icon() a3 = menu.addAction(ll, "Rotate Block counter-clockwise") a3.triggered.connect(self.rotateBlockCCW) a4 = menu.addAction("Reset Rotation") a4.triggered.connect(self.resetRotation) b1 = menu.addAction("Print Rotation") b1.triggered.connect(self.printRotation) c1 = menu.addAction("Delete this Block") c1.triggered.connect(self.deleteBlock) c3 = menu.addAction("Set image") c3.triggered.connect(self.changeImage) if not self.isSet: c4 = menu.addAction("Add port") c4.triggered.connect(self.addPortDlg) menu.exec_(event.screenPos()) def encode(self): if self.isVisible(): self.logger.debug("Encoding a Generic Block") portListInputs = [] portListOutputs = [] for p in self.inputs: portListInputs.append(p.id) for p in self.outputs: portListOutputs.append(p.id) dct = {} dct[".__BlockDict__"] = True dct["BlockName"] = self.name dct["BlockDisplayName"] = self.displayName dct["BlockPosition"] = (float(self.pos().x()), float(self.pos().y())) dct["ID"] = self.id dct["trnsysID"] = self.trnsysId dct["PortsIDIn"] = portListInputs dct["PortsIDOut"] = portListOutputs dct["FlippedH"] = self.flippedH dct["FlippedV"] = self.flippedV dct["RotationN"] = self.rotationN dct["Imagesource"] = self._imageAccessor.getResourcePath() dct["PortPairsNb"] = [self.getPairNb(i) for i in range(4)] dictName = "Block-" return dictName, dct def decode(self, i, resBlockList): assert len(self.inputs) == len(self.outputs) numberOfPortPairs = len(self.inputs) for portPairIndex in range(numberOfPortPairs): self.removePortPair(portPairIndex) numberOfPortPairsBySide = i["PortPairsNb"] for side in range(3): numberOfPortPairsToAdd = numberOfPortPairsBySide[side] for _ in range(numberOfPortPairsToAdd): self.addPortPair(side) super(GenericBlock, self).decode(i, resBlockList) self._imageAccessor = _img.ImageAccessor.createFromResourcePath( i["Imagesource"]) self.setImage() def decodePaste(self, i, offset_x, offset_y, resConnList, resBlockList, **kwargs): correcter = 0 for j in range(4): if j == 2: correcter = -1 for k in range(i["PortPairsNb"][j] + correcter): self.addPortPair(j) super(GenericBlock, self).decodePaste(i, offset_x, offset_y, resConnList, resBlockList) self._imageAccessor = _img.ImageAccessor.createFromResourcePath( i["Imagesource"]) self.setImage() def addPortPair(self, side): h = self.h w = self.w delta = 4 self.logger.debug("side is " + str(side)) self.inputs.append(_cspi.createSinglePipePortItem("i", side, self)) self.outputs.append(_cspi.createSinglePipePortItem("o", side, self)) # Allocate id self.childIds.append(self.parent.parent().idGen.getTrnsysID()) portNb = [0, 0, 0, 0] for i in self.inputs: if i.side == 0: distBetweenPorts = (self.h - 4 * delta) / (2 * self.getPairNb(0) - 1) self.logger.debug("distance betw ports " + str(distBetweenPorts)) i.setPos(-2 * delta, 2 * delta + distBetweenPorts * portNb[0]) portNb[0] += 1 self.outputs[self.inputs.index(i)].setPos( -2 * delta, 2 * delta + distBetweenPorts * portNb[0]) portNb[0] += 1 elif i.side == 1: distBetweenPorts = (self.w - 4 * delta) / (2 * self.getPairNb(1) - 1) i.setPos(2 * delta + distBetweenPorts * portNb[1], -2 * delta) portNb[1] += 1 self.outputs[self.inputs.index(i)].setPos( 2 * delta + distBetweenPorts * portNb[1], -2 * delta) portNb[1] += 1 elif i.side == 2: self.logger.debug("side == 2") distBetweenPorts = (self.h - 4 * delta) / (2 * self.getPairNb(2) - 1) self.logger.debug("side 2 dist betw ports is " + str(distBetweenPorts)) i.setPos(2 * delta + w, 2 * delta + distBetweenPorts * portNb[2]) self.logger.debug(2 * delta + distBetweenPorts * portNb[2]) portNb[2] += 1 self.outputs[self.inputs.index(i)].setPos( 2 * delta + w, 2 * delta + distBetweenPorts * portNb[2]) self.logger.debug(2 * delta + distBetweenPorts * portNb[2]) portNb[2] += 1 else: distBetweenPorts = (self.w - 4 * delta) / (2 * self.getPairNb(3) - 1) self.logger.debug("distance betw ports " + str(distBetweenPorts)) i.setPos(2 * delta + distBetweenPorts * portNb[3], 2 * delta + h) portNb[3] += 1 self.outputs[self.inputs.index(i)].setPos( 2 * delta + distBetweenPorts * portNb[3], 2 * delta + h) portNb[3] += 1 def removePortPairOnSide(self, side): for i in self.inputs: if i.side == side: self.removePortPair(self.inputs.index(i)) return def removePortPair(self, n): self.inputs.remove(self.inputs[n]) self.outputs.remove(self.outputs[n]) def updateFlipStateH(self, state): self.flippedH = bool(state) pixmap = self._getPixmap() self.setPixmap(pixmap) def updateFlipStateV(self, state): self.flippedV = bool(state) pixmap = self._getPixmap() self.setPixmap(pixmap) def getInternalPiping(self) -> InternalPiping: assert len(self.inputs) == len(self.outputs) pipes = [] portItems = {} for i, (graphicalInputPort, graphicalOutputPort) in enumerate( zip(self.inputs, self.outputs)): inputPort = _mfn.PortItem(f"Input {i+1}", _mfn.PortItemType.INPUT) outputPort = _mfn.PortItem(f"Output {i+1}", _mfn.PortItemType.OUTPUT) pipe = _mfn.Pipe(f"{self.displayName}X{i}", self.childIds[0], inputPort, outputPort) pipes.append(pipe) portItems[inputPort] = graphicalInputPort portItems[outputPort] = graphicalOutputPort return InternalPiping(pipes, portItems) def getSubBlockOffset(self, c): for i in range(len(self.inputs)): if (self.inputs[i] == c.toPort or self.inputs[i] == c.fromPort or self.outputs[i] == c.toPort or self.outputs[i] == c.fromPort): return i def addTree(self): """ When a blockitem is added to the main window. A file explorer for that item is added to the right of the main window by calling this method """ self.logger.debug(self.parent.parent()) pathName = self.displayName if self.parent.parent().projectPath == "": self.path = self.parent.parent().projectFolder else: self.path = self.parent.parent().projectPath self.path = os.path.join(self.path, "ddck") self.path = os.path.join(self.path, pathName) if not os.path.exists(self.path): os.makedirs(self.path) self.model = MyQFileSystemModel() self.model.setRootPath(self.path) self.model.setName(self.displayName) self.tree = MyQTreeView(self.model, self) self.tree.setModel(self.model) self.tree.setRootIndex(self.model.index(self.path)) self.tree.setObjectName("%sTree" % self.displayName) for i in range(1, self.model.columnCount() - 1): self.tree.hideColumn(i) self.tree.setMinimumHeight(200) self.tree.setSortingEnabled(True) self.parent.parent().splitter.addWidget(self.tree) def deleteBlock(self): """ Overridden method to also delete folder """ self.logger.debug("Block " + str(self) + " is deleting itself (" + self.displayName + ")") self.deleteConns() self.parent.parent().trnsysObj.remove(self) self.logger.debug("deleting block " + str(self) + self.displayName) self.parent.scene().removeItem(self) widgetToRemove = self.parent.parent().findChild( QTreeView, self.displayName + "Tree") shutil.rmtree(self.path) self.deleteLoadedFile() try: widgetToRemove.hide() except AttributeError: self.logger.debug("Widget doesnt exist!") else: self.logger.debug("Deleted widget") del self def setName(self, newName): """ Overridden method to also change folder name """ self.displayName = newName self.label.setPlainText(newName) self.model.setName(self.displayName) self.tree.setObjectName("%sTree" % self.displayName) self.logger.debug(os.path.dirname(self.path)) destPath = os.path.join(os.path.split(self.path)[0], self.displayName) if os.path.exists(self.path): os.rename(self.path, destPath) self.path = destPath self.logger.debug(self.path)
class StorageTank(BlockItem, MassFlowNetworkContributorMixin): # pylint: disable=too-many-instance-attributes,too-many-public-methods HEAT_EXCHANGER_WIDTH = 40 def __init__(self, trnsysType, parent, **kwargs): super().__init__(trnsysType, parent, **kwargs) self.parent = parent self._idGenerator: _id.IdGenerator = self.parent.parent().idGen self.dckFilePath = "" self.directPortPairs: _tp.List[DirectPortPair] = [] self.heatExchangers: _tp.List[HeatExchanger] = [] self.blackBoxEquations = [] self.nTes = self.parent.parent().idGen.getStoragenTes() self.storageType = self.parent.parent().idGen.getStorageType() self.changeSize() self.path = None self.addTree() @property def leftDirectPortPairsPortItems(self): return self._getDirectPortPairPortItems(_sd.Side.LEFT) @property def rightDirectPortPairsPortItems(self): return self._getDirectPortPairPortItems(_sd.Side.RIGHT) def _getDirectPortPairPortItems(self, side: _sd.Side): return [ p for dpp in self.directPortPairs if dpp.side == side for p in [dpp.fromPort, dpp.toPort] ] def _getImageAccessor(self) -> _tp.Optional[_img.ImageAccessor]: return _img.STORAGE_TANK_SVG # Setter functions def setParent(self, p): self.logger.debug("Setting parent of Storage Tank (and its hx)") self.parent = p if self not in self.parent.parent().trnsysObj: self.parent.parent().trnsysObj.append(self) for heatExchanger in self.heatExchangers: heatExchanger.parent = self def addDirectPortPair( # pylint: disable=too-many-arguments self, trnsysId: int, side: _sd.Side, relativeInputHeight: float, relativeOutputHeight: float, storageTankHeight: float, portIds: _tp.Optional[PortIds] = None, ): inputPort = self._createPort("i", relativeInputHeight, storageTankHeight, side) outputPort = self._createPort("o", relativeOutputHeight, storageTankHeight, side) randomInt = int(_rnd.uniform(20, 200)) randomColor = QColor(randomInt, randomInt, randomInt) self._setPortColor(inputPort, randomColor) self._setPortColor(outputPort, randomColor) if portIds: inputPort.id = portIds.inputId outputPort.id = portIds.outputId directPortPair = DirectPortPair( trnsysId, inputPort, outputPort, relativeInputHeight, relativeOutputHeight, side ) self.directPortPairs.append(directPortPair) self.inputs.append(directPortPair.fromPort) self.outputs.append(directPortPair.toPort) def _createPort( self, name: str, relativeHeight: float, storageTankHeight: float, side: _sd.Side ) -> SinglePipePortItem: sideNr = side.toSideNr() portItem = _cspi.createSinglePipePortItem(name, sideNr, self) portItem.setZValue(100) xPos = 0 if side == _sd.Side.LEFT else self.w yPos = storageTankHeight - relativeHeight * storageTankHeight portItem.setPos(xPos, yPos) portItem.side = sideNr return portItem @staticmethod def _setPortColor(portItem: SinglePipePortItem, color: QColor) -> None: portItem.innerCircle.setBrush(color) portItem.visibleColor = color def addHeatExchanger(self, name, trnsysId, side, relativeInputHeight, relativeOutputHeight): heatExchanger = HeatExchanger( trnsysId=trnsysId, sideNr=side.toSideNr(), width=self.HEAT_EXCHANGER_WIDTH, relativeInputHeight=relativeInputHeight, relativeOutputHeight=relativeOutputHeight, storageTankWidth=self.w, storageTankHeight=self.h, parent=self, name=name, ) return heatExchanger def updateImage(self): super().updateImage() self.label.setPos(self.label.pos().x(), self.h) def updatePortItemPositions(self, deltaH, deltaW): for portItem in self.inputs + self.outputs: oldRelativeHeight = portItem.pos().y() / self.h if portItem.side == 0: portItem.setPos(portItem.pos().x(), oldRelativeHeight * (self.h + deltaH)) else: portItem.setPos(portItem.pos().x() + deltaW, oldRelativeHeight * (self.h + deltaH)) def updateHeatExchangersAfterTankSizeChange(self): for heatExchanger in self.heatExchangers: heatExchanger.setTankSize(self.w, self.h) def encode(self): if not self.isVisible(): raise RuntimeError("Cannot encode an invisible storage tank.") heatExchangerModels = self._getHeatExchangerModelsForEncode() portPairModels = self._getDirectPortPairModelsForEncode() position = float(self.pos().x()), float(self.pos().y()) storageTankModel = _model.StorageTank( self.flippedH, self.flippedV, self.name, self.displayName, self.id, self.trnsysId, self.h, position, heatExchangerModels, portPairModels, ) dictName = "Block-" return dictName, storageTankModel.to_dict() def _getDirectPortPairModelsForEncode(self): portPairModels = [] for directPort in self.directPortPairs: side = _sd.Side.createFromSideNr(directPort.fromPort.side) inputPortModel = _model.Port(directPort.fromPort.id, directPort.relativeInputHeight) outputPortModel = _model.Port(directPort.toPort.id, directPort.relativeOutputHeight) portPairModel = _model.PortPair(side, directPort.trnsysId, inputPortModel, outputPortModel) directPortPairModel = _model.DirectPortPair(portPairModel) portPairModels.append(directPortPairModel) return portPairModels def _getHeatExchangerModelsForEncode(self): heatExchangerModels = [] for heatExchanger in self.heatExchangers: side = _sd.Side.createFromSideNr(heatExchanger.sSide) inputPort = _model.Port( heatExchanger.port1.id, heatExchanger.relativeInputHeight, ) outputPort = _model.Port( heatExchanger.port2.id, heatExchanger.relativeOutputHeight, ) portPair = _model.PortPair(side, heatExchanger.trnsysId, inputPort, outputPort) heatExchangerModel = _model.HeatExchanger( portPair, heatExchanger.displayName, heatExchanger.w, self.id, heatExchanger.id ) heatExchangerModels.append(heatExchangerModel) return heatExchangerModels def decode(self, i, resBlockList): offsetX = 0 offsetY = 0 self._decodeInternal(i, offsetX, offsetY, resBlockList, shallSetNamesAndIDs=True) def _decodeInternal( # pylint: disable=too-many-arguments self, i, offsetX, offsetY, resBlockList, shallSetNamesAndIDs: bool, ): self.logger.debug("Loading a Storage in Decoder") model = _model.StorageTank.from_dict(i) self.flippedH = model.isHorizontallyFlipped if shallSetNamesAndIDs: self.displayName = model.BlockDisplayName self.changeSize() self.h = model.height self.updateImage() self.setPos(model.position[0] + offsetX, model.position[1] + offsetY) if shallSetNamesAndIDs: self.trnsysId = model.trnsysId self.id = model.id for heatExchangerModel in model.heatExchangers: self._decodeHeatExchanger(heatExchangerModel, shallSetNamesAndIDs) for portPairModel in model.directPortPairs: self._decodeDirectPortPair(portPairModel) resBlockList.append(self) def _decodeDirectPortPair( self, portPairModel: _model.DirectPortPair, ) -> None: portPair = portPairModel.portPair portIds = PortIds(portPair.inputPort.id, portPair.outputPort.id) self.addDirectPortPair( portPair.trnsysId, portPair.side, portPair.inputPort.relativeHeight, portPair.outputPort.relativeHeight, storageTankHeight=self.h, portIds=portIds, ) def _decodeHeatExchanger(self, heatExchangerModel: _model.HeatExchanger, shallSetNamesAndIDs: bool): portPair = heatExchangerModel.portPair nameSuffix = "" if shallSetNamesAndIDs else "New" name = heatExchangerModel.name + nameSuffix heatExchanger = self.addHeatExchanger( name, portPair.trnsysId, portPair.side, portPair.inputPort.relativeHeight, portPair.outputPort.relativeHeight ) if shallSetNamesAndIDs: heatExchanger.setId(heatExchangerModel.id) heatExchanger.port1.id = portPair.inputPort.id heatExchanger.port2.id = portPair.outputPort.id def decodePaste( # pylint: disable=too-many-arguments self, i, offset_x, offset_y, resConnList, resBlockList, **kwargs ): self._decodeInternal(i, offset_x, offset_y, resBlockList, shallSetNamesAndIDs=False) def getTemperatureVariableName(self, portItem: SinglePipePortItem) -> str: directPortPair = self._getDirectPortPairForPortItemOrNone(portItem) if directPortPair: return self._getTemperatureVariableNameForDirectPortPairPortItem(directPortPair, portItem) heatExchanger = self._getHeatExchangerForPortItem(portItem) if heatExchanger: return self._getTemperatureVariableNameForHeatExchangerPortItem(heatExchanger) raise ValueError("Port item doesn't belong to this storage tank.") def getFlowSolverParametersId(self, portItem: SinglePipePortItem) -> int: directPortPair = self._getDirectPortPairForPortItemOrNone(portItem) if directPortPair: return directPortPair.trnsysId heatExchanger = self._getHeatExchangerForPortItem(portItem) if heatExchanger: return heatExchanger.trnsysId raise ValueError("Port item doesn't belong to this storage tank.") def assignIDsToUninitializedValuesAfterJsonFormatMigration( self, generator: _id.IdGenerator ) -> None: # type: ignore[attr-defined] for heatExchanger in self.heatExchangers: if heatExchanger.trnsysId == generator.UNINITIALIZED_ID: heatExchanger.trnsysId = generator.getTrnsysID() for directPortPair in self.directPortPairs: if directPortPair.trnsysId == generator.UNINITIALIZED_ID: directPortPair.trnsysId = generator.getTrnsysID() def _getHeatExchangerForPortItem(self, portItem: SinglePipePortItem) -> _tp.Optional[HeatExchanger]: heatExchanger = self._getSingleOrNone(hx for hx in self.heatExchangers if portItem in [hx.port1, hx.port2]) return heatExchanger def _getDirectPortPairForPortItemOrNone(self, portItem: SinglePipePortItem) -> _tp.Optional[DirectPortPair]: directPortPair = self._getSingleOrNone( dpp for dpp in self.directPortPairs if portItem in [dpp.fromPort, dpp.toPort] ) return directPortPair @staticmethod def _getSingleOrNone(iterable: _tp.Iterable[_T]) -> _tp.Optional[_T]: sequence = list(iterable) if not sequence: return None if len(sequence) > 1: raise ValueError("More than one value in iterable.") return sequence[0] def _getTemperatureVariableNameForDirectPortPairPortItem(self, directPortPair, portItem): isInputPort = directPortPair.fromPort == portItem relativeHeightInPercent = ( directPortPair.relativeInputHeightPercent if isInputPort else directPortPair.relativeOutputHeightPercent ) return f"T{self.displayName}Port{directPortPair.side.formatDdck()}{relativeHeightInPercent}" @staticmethod def _getTemperatureVariableNameForHeatExchangerPortItem(heatExchanger): return f"T{heatExchanger.displayName}" # Misc def contextMenuEvent(self, event): menu = QMenu() launchNotepadAction = menu.addAction("Launch NotePad++") launchNotepadAction.triggered.connect(self.launchNotepadFile) rotateRightIcon = _img.ROTATE_TO_RIGHT_PNG.icon() rotateRightAction = menu.addAction(rotateRightIcon, "Rotate Block clockwise") rotateRightAction.triggered.connect(self.rotateBlockCW) rotateLeftIcon = _img.ROTATE_LEFT_PNG.icon() rotateLeftIcon = menu.addAction(rotateLeftIcon, "Rotate Block counter-clockwise") rotateLeftIcon.triggered.connect(self.rotateBlockCCW) resetRotationAction = menu.addAction("Reset Rotation") resetRotationAction.triggered.connect(self.resetRotation) printRotationAction = menu.addAction("Print Rotation") printRotationAction.triggered.connect(self.printRotation) deleteBlockAction = menu.addAction("Delete this Block") deleteBlockAction.triggered.connect(self.deleteBlockCom) exportDdckAction = menu.addAction("Export ddck") exportDdckAction.triggered.connect(self.exportDck) menu.exec(event.screenPos()) def mouseDoubleClickEvent(self, event): ConfigureStorageDialog(self, self.scene().parent()) # Export related def exportBlackBox(self): equations = [] ddcxPath = _os.path.join(self.path, self.displayName) ddcxPath = ddcxPath + ".ddcx" self.exportDck() if _os.path.isfile(ddcxPath): with open(ddcxPath, "r", encoding="windows-1252") as infile: lines = infile.readlines() for line in lines: if line[0] == "T": equations.append(line.replace("\n", "")) return "success", equations self.logger.warning("No file at " + ddcxPath) return "noDdckFile", equations def getInternalPiping(self) -> InternalPiping: heatExchangerNodes, heatExchangerPortItems = self._createHeatExchangerNodes() portPairNodes, portPairsPortItems = self._createPortPairNodes() nodes = [*heatExchangerNodes, *portPairNodes] modelPortItemsToGraphicalPortItem = heatExchangerPortItems | portPairsPortItems return InternalPiping(nodes, modelPortItemsToGraphicalPortItem) def _createHeatExchangerNodes(self): heatExchangerPortItems = {} heatExchangerNodes = [] for heatExchanger in self.heatExchangers: heatExchangerPortItem1 = _mfn.PortItem("Heat Exchanger Input", _mfn.PortItemType.INPUT) heatExchangerPortItems[heatExchangerPortItem1] = heatExchanger.port1 heatExchangerPortItem2 = _mfn.PortItem("Heat Exchanger Output", _mfn.PortItemType.OUTPUT) heatExchangerPortItems[heatExchangerPortItem2] = heatExchanger.port2 name = self._getMassFlowVariableSuffixForHeatExchanger(heatExchanger) node = _mfn.Pipe(name, heatExchanger.trnsysId, heatExchangerPortItem1, heatExchangerPortItem2) heatExchangerNodes.append(node) return heatExchangerNodes, heatExchangerPortItems def _createPortPairNodes(self): portPairsPortItems = {} portPairNodes = [] for directPortPair in self.directPortPairs: portPairPortItem1 = _mfn.PortItem("Input", _mfn.PortItemType.INPUT) portPairsPortItems[portPairPortItem1] = directPortPair.fromPort portPairPortItem2 = _mfn.PortItem("Output", _mfn.PortItemType.OUTPUT) portPairsPortItems[portPairPortItem2] = directPortPair.toPort portPairName = self._getMassFlowVariableSuffixForDirectPortPair(directPortPair) node = _mfn.Pipe(portPairName, directPortPair.trnsysId, portPairPortItem1, portPairPortItem2) portPairNodes.append(node) return portPairNodes, portPairsPortItems def _getMassFlowVariableSuffixForDirectPortPair(self, directPortPair: DirectPortPair): return ( f"{self.displayName}Dp{'L' if directPortPair.side.isLeft else 'R'}" f"{directPortPair.relativeInputHeightPercent}-{directPortPair.relativeOutputHeightPercent}" ) @staticmethod def _getMassFlowVariableSuffixForHeatExchanger(heatExchanger): return heatExchanger.displayName def exportDck(self): # pylint: disable=too-many-locals,too-many-statements if not self._checkConnExists(): msgb = QMessageBox() msgb.setText("Please connect all ports before exporting!") msgb.exec_() return noError = self._debugConn() if not noError: qmb = QMessageBox() qmb.setText("Ignore connection errors and continue with export?") qmb.setStandardButtons(QMessageBox.Save | QMessageBox.Cancel) qmb.setDefaultButton(QMessageBox.Cancel) ret = qmb.exec() if ret == QMessageBox.Save: self.logger.debug("Overwriting") # continue else: self.logger.debug("Canceling") return nPorts = len(self.directPortPairs) nHx = len(self.heatExchangers) self.logger.debug("Storage Type: " + str(self.storageType)) self.logger.debug("nTes: " + str(self.nTes)) self.logger.debug("nPorts: " + str(nPorts)) self.logger.debug("nHx: " + str(nHx)) tool = Type1924_TesPlugFlow() inputs = { "nUnit": 50, "nType": self.storageType, "nTes": self.nTes, "nPorts": nPorts, "nHx": nHx, "nHeatSources": 1, } directPairsPorts = [] for directPortPair in self.directPortPairs: incomingConnection = directPortPair.fromPort.connectionList[0] temperatureName = "T" + incomingConnection.displayName massFlowRateName = "Mfr" + incomingConnection.displayName outgoingConnection = directPortPair.toPort.connectionList[0] reverseTemperatureName = "T" + outgoingConnection.displayName inputPos = directPortPair.relativeInputHeight outputPos = directPortPair.relativeOutputHeight directPairsPort = { "T": temperatureName, "side": directPortPair.side.formatDdck(), "Mfr": massFlowRateName, "Trev": reverseTemperatureName, "zIn": inputPos, "zOut": outputPos, } directPairsPorts.append(directPairsPort) heatExchangerPorts = [] for heatExchanger in self.heatExchangers: heatExchangerName = heatExchanger.displayName incomingConnection = heatExchanger.port1.connectionList[0] temperatureName = "T" + incomingConnection.displayName massFlowRateName = "Mfr" + incomingConnection.displayName outgoingConnection = heatExchanger.port2.connectionList[0] reverseTemperatureName = "T" + outgoingConnection.displayName inputPos = heatExchanger.relativeInputHeight outputPos = heatExchanger.relativeOutputHeight heatExchangerPort = { "Name": heatExchangerName, "T": temperatureName, "Mfr": massFlowRateName, "Trev": reverseTemperatureName, "zIn": inputPos, "zOut": outputPos, "cp": "cpwat", "rho": "rhowat", } heatExchangerPorts.append(heatExchangerPort) auxiliaryPorts = [] for _ in range(inputs["nHeatSources"]): dictInputAux = {"zAux": 0.0, "qAux": 0.0} auxiliaryPorts.append(dictInputAux) exportPath = _os.path.join(self.path, self.displayName + ".ddck") self.logger.debug(exportPath) tool.setInputs(inputs, directPairsPorts, heatExchangerPorts, auxiliaryPorts) tool.createDDck(self.path, self.displayName, typeFile="ddck") def _debugConn(self): self.logger.debug("Debugging conn") errorConnList = "" for directPort in self.directPortPairs: stFromPort = directPort.fromPort stToPort = directPort.toPort toPort1 = stFromPort.connectionList[0].toPort fromPort2 = stToPort.connectionList[0].fromPort connName1 = stFromPort.connectionList[0].displayName connName2 = stToPort.connectionList[0].displayName if stFromPort != toPort1: errorConnList = errorConnList + connName1 + "\n" if stToPort != fromPort2: errorConnList = errorConnList + connName2 + "\n" if errorConnList != "": msgBox = QMessageBox() msgBox.setText(f"{errorConnList} is connected wrongly, right click StorageTank to invert connection.") msgBox.exec() noError = False else: noError = True return noError def _checkConnExists(self): for heatExchanger in self.heatExchangers: if not heatExchanger.port1.connectionList: return False if not heatExchanger.port2.connectionList: return False for ports in self.leftDirectPortPairsPortItems: if not ports.connectionList: return False for ports in self.rightDirectPortPairsPortItems: if not ports.connectionList: return False return True def addTree(self): """ When a blockitem is added to the main window. A file explorer for that item is added to the right of the main window by calling this method """ pathName = self.displayName if self.parent.parent().projectPath == "": self.path = self.parent.parent().projectFolder else: self.path = self.parent.parent().projectPath self.path = _os.path.join(self.path, "ddck") self.path = _os.path.join(self.path, pathName) if not _os.path.exists(self.path): _os.makedirs(self.path) self.model = MyQFileSystemModel() self.model.setRootPath(self.path) self.model.setName(self.displayName) self.tree = MyQTreeView(self.model, self) self.tree.setModel(self.model) self.tree.setRootIndex(self.model.index(self.path)) self.tree.setObjectName(f"{self.displayName}Tree") self.tree.setMinimumHeight(200) self.tree.setSortingEnabled(True) self.parent.parent().splitter.addWidget(self.tree) def deleteBlock(self): """ Overridden method to also delete folder """ self.logger.debug("Block " + str(self) + " is deleting itself (" + self.displayName + ")") self.deleteConns() # self.logger.debug("self.parent.parent" + str(self.parent.parent())) self.parent.parent().trnsysObj.remove(self) self.logger.debug("deleting block " + str(self) + self.displayName) # self.logger.debug("self.scene is" + str(self.parent.scene())) self.parent.scene().removeItem(self) widgetToRemove = self.parent.parent().findChild(QTreeView, self.displayName + "Tree") _sh.rmtree(self.path) try: widgetToRemove.hide() except AttributeError: self.logger.debug("Widget doesnt exist!") else: self.logger.debug("Deleted widget") del self def setName(self, newName): """ Overridden method to also change folder name """ self.displayName = newName self.label.setPlainText(newName) self.model.setName(self.displayName) self.tree.setObjectName(f"{self.displayName}Tree") self.logger.debug(_os.path.dirname(self.path)) destPath = _os.path.join(_os.path.split(self.path)[0], self.displayName) if _os.path.split(self.path)[-1] == "" or _os.path.split(self.path)[-1] == "ddck": _os.makedirs(destPath) else: if _os.path.exists(self.path): _os.rename(self.path, destPath) self.path = destPath self.logger.debug(self.path)