Spaces:
Running
Running
| #Based on: | |
| #!/usr/bin/env python3 | |
| # -*- coding: utf-8 -*- | |
| # File : PyPinch.py | |
| # License : License: GNU v3.0 | |
| # Author : Andrei Leonard Nicusan <aln705@student.bham.ac.uk> | |
| # Date : 25.05.2019 | |
| import csv | |
| import os | |
| import numpy as np | |
| from Modules.Pinch.Streams import Streams | |
| from Modules.Pinch.PinchPlot import PinchPlot | |
| from Modules.Pinch.PinchExport import PinchExport | |
| class Pinch: | |
| def __init__(self, streamsDataFile, options = {}): | |
| self.tmin = 0 | |
| self.streams = [] | |
| self.temperatureInterval = [] | |
| self.problemTable = [] | |
| self.hotUtility = 0 | |
| self.coldUtility = 0 | |
| self.unfeasibleHeatCascade = [] | |
| self.heatCascade = [] | |
| self.pinchTemperature = 0 | |
| self.shiftedCompositeDiagram = {'hot': {'H': [], 'T': []}, 'cold': {'H': [], 'T': []}} | |
| self.compositeDiagram = {'hot': {'H': [], 'T': []}, 'cold': {'H': [], 'T': []}} | |
| self.grandCompositeCurve = {'H': [], 'T': []} | |
| self._temperatures = [] | |
| self._deltaHHot = [] | |
| self._deltaHCold = [] | |
| self._options = {'debug': False, 'draw': False, 'csv': False} | |
| self._temperaturesHOT= [] | |
| self._temperaturesCOLD = [] | |
| self.emptyintervalstartHOT= [] | |
| self.emptyintervalstartCOLD = [] | |
| self.lastHotStream = 0 | |
| self.lastColdStream = 0 | |
| self.emptyintervalsHot = {'H': [], 'T': []} | |
| self.emptyintervalsCold = {'H': [], 'T': []} | |
| self.processdesignation = streamsDataFile[:-4] | |
| path = r"{} Pinch".format(self.processdesignation) | |
| self.newpath = 'Output'+ '\\' + path | |
| self.streams = Streams(streamsDataFile) | |
| self.tmin = self.streams.tmin | |
| if 'debug' in options: | |
| self._options['debug'] = True | |
| if 'draw' in options: | |
| self._options['draw'] = True | |
| if 'csv' in options: | |
| self._options['csv'] = True | |
| def shiftTemperatures(self): | |
| for stream in self.streams: | |
| if stream['type'] == 'HOT': | |
| stream['ss'] = stream['ts'] - self.tmin / 2 | |
| stream['st'] = stream['tt'] - self.tmin / 2 | |
| else: | |
| stream['ss'] = stream['ts'] + self.tmin / 2 | |
| stream['st'] = stream['tt'] + self.tmin / 2 | |
| if self._options['debug'] == True: | |
| print("\nStreams: ") | |
| for stream in self.streams: | |
| print(stream) | |
| print("Tmin = {}".format(self.tmin)) | |
| def constructTemperatureInterval(self): | |
| # Take all shifted temperatures and reverse sort them, | |
| # removing all duplicates | |
| for stream in self.streams: | |
| self._temperatures.append(stream['ss']) | |
| self._temperatures.append(stream['st']) | |
| if (stream["type"] == "HOT"): | |
| self._temperaturesHOT.append(stream['ss']) | |
| self._temperaturesHOT.append(stream['st']) | |
| else: | |
| self._temperaturesCOLD.append(stream['ss']) | |
| self._temperaturesCOLD.append(stream['st']) | |
| self._temperaturesHOT = list(set(self._temperaturesHOT)) | |
| self._temperaturesHOT.sort() | |
| self._temperaturesCOLD = list(set(self._temperaturesCOLD)) | |
| self._temperaturesCOLD.sort() | |
| self._temperatures = list(set(self._temperatures)) | |
| self._temperatures.sort(reverse = True) | |
| # Save the stream number of all the streams that pass | |
| # through each shifted temperature interval | |
| for i in range(len(self._temperatures) - 1): | |
| t1 = self._temperatures[i] | |
| t2 = self._temperatures[i + 1] | |
| interval = {'t1': t1, 't2': t2, 'streamNumbers': []} | |
| j = 0 | |
| for stream in self.streams: | |
| if (stream['type'] == 'HOT'): | |
| if (stream['ss'] >= t1 and stream['st'] <= t2): | |
| interval['streamNumbers'].append(j) | |
| else: | |
| if (stream['st'] >= t1 and stream['ss'] <= t2): | |
| interval['streamNumbers'].append(j) | |
| j = j + 1 | |
| self.temperatureInterval.append(interval) | |
| if self._options['debug'] == True: | |
| print("\nTemperature Intervals: ") | |
| i = 0 | |
| print(self._temperatures) | |
| for interval in self.temperatureInterval: | |
| print("Interval {} : {}".format(i, interval)) | |
| i = i + 1 | |
| if self._options['draw'] == True: | |
| PinchPlot().drawTemperatureInterval(self._temperatures, self.streams) | |
| def constructProblemTable(self): | |
| for interval in self.temperatureInterval: | |
| row = {} | |
| row['deltaS'] = interval['t1'] - interval['t2'] | |
| row['deltaCP'] = 0 | |
| for i in interval['streamNumbers']: | |
| if interval['streamNumbers'] != []: | |
| if self.streams.streamsData[i]['type'] == 'HOT': | |
| row['deltaCP'] = row['deltaCP'] + self.streams.streamsData[i]['cp'] | |
| else: | |
| row['deltaCP'] = row['deltaCP'] - self.streams.streamsData[i]['cp'] | |
| else: | |
| row['deltaCP'] = 0 | |
| row['deltaH'] = row['deltaS'] * row['deltaCP'] | |
| self.problemTable.append(row) | |
| if self._options['debug'] == True: | |
| print("\nProblem Table: ") | |
| i = 0 | |
| for interval in self.problemTable: | |
| print("Interval {} : {}".format(i, interval)) | |
| i = i + 1 | |
| if self._options['draw'] == True: | |
| PinchPlot().drawProblemTable(self.problemTable, self._temperatures) | |
| if self._options['csv'] == True: | |
| PinchExport().csvProblemTable(self.problemTable, self._temperatures, self.newpath) | |
| def constructHeatCascade(self): | |
| exitH = 0 | |
| lowestExitH = 0 | |
| i = 0 | |
| pinchInterval = 0 | |
| for interval in self.problemTable: | |
| row = {} | |
| row['deltaH'] = interval['deltaH'] | |
| exitH = exitH + row['deltaH'] | |
| row['exitH'] = exitH | |
| if exitH < lowestExitH: | |
| lowestExitH = exitH | |
| pinchInterval = i | |
| self.unfeasibleHeatCascade.append(row) | |
| i = i + 1 | |
| self.hotUtility = -lowestExitH | |
| exitH = self.hotUtility | |
| for interval in self.problemTable: | |
| row = {} | |
| row['deltaH'] = interval['deltaH'] | |
| exitH = exitH + row['deltaH'] | |
| row['exitH'] = exitH | |
| self.heatCascade.append(row) | |
| self.coldUtility = exitH | |
| if pinchInterval == 0: | |
| self.pinchTemperature = self.temperatureInterval[pinchInterval]['t2'] | |
| else: | |
| self.pinchTemperature = self.temperatureInterval[pinchInterval]['t2'] | |
| if self._options['debug'] == True: | |
| print("\nUnfeasible Heat Cascade: ") | |
| i = 0 | |
| for interval in self.unfeasibleHeatCascade: | |
| print("Interval {} : {}".format(i, interval)) | |
| i = i + 1 | |
| print("\nFeasible Heat Cascade: ") | |
| i = 0 | |
| for interval in self.heatCascade: | |
| print("Interval {} : {}".format(i, interval)) | |
| i = i + 1 | |
| print("\nPinch Temperature (degC): {}".format(self.pinchTemperature)) | |
| print("Minimum Hot Utility (kW): {}".format(self.hotUtility)) | |
| print("Minimum Cold Utility (kW): {}".format(self.coldUtility)) | |
| if self._options['draw'] == True: | |
| PinchPlot().drawHeatCascade(self.unfeasibleHeatCascade, self.heatCascade, self.hotUtility) | |
| if self._options['csv'] == True: | |
| PinchExport().csvHeatCascade(self.unfeasibleHeatCascade, self.hotUtility, self.heatCascade, self.pinchTemperature, self.newpath) | |
| def constructShiftedCompositeDiagram(self, localisation): | |
| emptylist = [] | |
| for interval in self.temperatureInterval: | |
| hotH = 0 | |
| coldH = 0 | |
| # Add CP values for the hot and cold streams | |
| # in a given temperature interval | |
| for i in interval['streamNumbers']: | |
| if interval['streamNumbers'] != []: | |
| if self.streams.streamsData[i]['type'] == 'HOT': | |
| hotH = hotH + self.streams.streamsData[i]['cp'] | |
| #self.shiftedCompositeDiagram['hot']['T'].append(self.streamsData[i]['ss']) | |
| #self.shiftedCompositeDiagram['hot']['T'].append(self.streamsData[i]['st']) | |
| else: | |
| coldH = coldH + self.streams.streamsData[i]['cp'] | |
| #self.shiftedCompositeDiagram['cold']['T'].append(self.streamsData[i]['ss']) | |
| #self.shiftedCompositeDiagram['cold']['T'].append(self.streamsData[i]['st']) | |
| else: | |
| hotH = 0 | |
| emptylist.append(i) | |
| # Enthalpy = CP * deltaT | |
| #checken ob geprüftes interval einen heißen strom enthält und erst dann anfangen | |
| #dann immer wieder prüfen, ob danach noch ein heoßer strom kommt | |
| hotH = hotH * (interval['t1'] - interval['t2']) | |
| self._deltaHHot.append(hotH) | |
| coldH = coldH * (interval['t1'] - interval['t2']) | |
| self._deltaHCold.append(coldH) | |
| # rot bei 0/t1 anfangen | |
| # blau bei coldutility/t2 anfangen | |
| self.shiftedCompositeDiagram['hot']['T']= [] | |
| self._deltaHHot.reverse() | |
| self.shiftedCompositeDiagram['hot']['H'].append(0.0) | |
| for i in range(1, len(self._temperatures)): | |
| self.shiftedCompositeDiagram['hot']['H'].append(self.shiftedCompositeDiagram['hot']['H'][-1] + self._deltaHHot[i-1]) | |
| self.shiftedCompositeDiagram['hot']['T'].append(self._temperatures[len(self._temperatures)-i]) | |
| self.shiftedCompositeDiagram['hot']['T'].append(self._temperatures[0]) | |
| #Summe aus allen deltaHCold + coldutility machen und für die Schritte jeweils deltaHCold abziehen | |
| coldgesamt = self.coldUtility | |
| for i in range(len(self._deltaHCold)): | |
| coldgesamt += self._deltaHCold[i] | |
| #Experimentell | |
| self.shiftedCompositeDiagram['cold']['T']= [] | |
| self.shiftedCompositeDiagram['cold']['H'].append(coldgesamt) | |
| #Experimentell | |
| self.shiftedCompositeDiagram['cold']['T'].append(self._temperatures[0]) | |
| for i in range(1, len(self._temperatures)): | |
| self.shiftedCompositeDiagram['cold']['H'].append(self.shiftedCompositeDiagram['cold']['H'][-1] - self._deltaHCold[i-1]) | |
| self.shiftedCompositeDiagram['cold']['T'].append(self._temperatures[i]) | |
| iliste = [] | |
| for i in range(1,(len(self.shiftedCompositeDiagram['cold']['H'])-1)): | |
| if self.shiftedCompositeDiagram['cold']['H'] == 0.0: | |
| iliste.append(i+1) | |
| elif self.shiftedCompositeDiagram['cold']['H'][i] == self.shiftedCompositeDiagram['cold']['H'][0]: | |
| iliste.append(i-1) | |
| elif self.shiftedCompositeDiagram['cold']['H'][i] == self.shiftedCompositeDiagram['cold']['H'][-1]: | |
| iliste.append(i+1) | |
| iliste.reverse() | |
| for i in iliste: | |
| self.shiftedCompositeDiagram['cold']['H'].pop(i) | |
| self.shiftedCompositeDiagram['cold']['T'].pop(i) | |
| iliste = [] | |
| for i in range(1,(len(self.shiftedCompositeDiagram['hot']['H'])-1)): | |
| if self.shiftedCompositeDiagram['hot']['H'][i] == 0.0: | |
| iliste.append(i-1) | |
| elif self.shiftedCompositeDiagram['hot']['H'][i] == self.shiftedCompositeDiagram['hot']['H'][-1]: | |
| iliste.append(i+1) | |
| iliste.reverse() | |
| for i in iliste: | |
| self.shiftedCompositeDiagram['hot']['H'].pop(i) | |
| self.shiftedCompositeDiagram['hot']['T'].pop(i) | |
| if self._options['draw'] == True: | |
| PinchPlot().drawShiftedCompositeDiagram(self.shiftedCompositeDiagram, self.coldUtility, | |
| self._temperatures, self.hotUtility, self.pinchTemperature, | |
| self.processdesignation, localisation) | |
| if self._options['csv'] == True: | |
| PinchExport().csvShiftedCompositeDiagram(self.newpath, self.shiftedCompositeDiagram) | |
| def constructCompositeDiagram(self, localisation): | |
| self.compositeDiagram['hot']['T'] = [x + self.tmin / 2 for x in self.shiftedCompositeDiagram['hot']['T']] | |
| self.compositeDiagram['hot']['H'] = self.shiftedCompositeDiagram['hot']['H'] | |
| self.compositeDiagram['cold']['T'] = [x - self.tmin / 2 for x in self.shiftedCompositeDiagram['cold']['T']] | |
| self.compositeDiagram['cold']['H'] = self.shiftedCompositeDiagram['cold']['H'] | |
| print(self._temperatures) | |
| if self._options['draw'] == True: | |
| PinchPlot().drawCompositeDiagram(self.compositeDiagram, self.shiftedCompositeDiagram, | |
| self.coldUtility, self._temperatures, self.tmin, self.hotUtility, | |
| self.pinchTemperature, self.processdesignation, localisation) | |
| if self._options['csv'] == True: | |
| PinchExport().csvCompositeDiagram(self.newpath, self.compositeDiagram) | |
| def constructGrandCompositeCurve(self,localisation): | |
| self.grandCompositeCurve['H'].append(self.hotUtility) | |
| self.grandCompositeCurve['T'].append(self._temperatures[0]) | |
| for i in range(1, len(self._temperatures)): | |
| self.grandCompositeCurve['H'].append(self.heatCascade[i - 1]['exitH']) | |
| self.grandCompositeCurve['T'].append(self._temperatures[i]) | |
| print(self.grandCompositeCurve) | |
| print(self.heatCascade) | |
| if self._options['debug'] == True: | |
| print("\nGrand Composite Curve: ") | |
| print("Net H (kW): {}".format(self.grandCompositeCurve['H'])) | |
| print("T (degC): {}".format(self.grandCompositeCurve['T'])) | |
| if self._options['draw'] == True: | |
| PinchPlot().drawGrandCompositeCurve(self.processdesignation, self.heatCascade, | |
| self.grandCompositeCurve, self._temperatures, self.pinchTemperature, localisation) | |
| if self._options['csv'] == True: | |
| PinchExport().csvGrandCompositeCurve(self.newpath, self.grandCompositeCurve) | |