Spaces:
Running
Running
| from tabulate import tabulate | |
| from Modules.HeatPumpIntegration.HPIPlot import HPIPlot | |
| from Modules.Utility.TemperaturePocketDeletion import TemperaturePocketDeletion as TPD | |
| class HeatPumpIntegration(): | |
| def __init__(self,streamsDataFile, Tsinkout, pyPinch): | |
| self.Integrationtype = None | |
| if Tsinkout == None: | |
| self.Integrationtype = 'Itterativ' | |
| self.processdesignation = streamsDataFile[:-4] | |
| self.streamsDataFile = streamsDataFile | |
| self.options = {'draw', 'debug'} | |
| self.KoWP = [] | |
| self.EvWP = [] | |
| self.COPwerte = [] | |
| self.COPT = [] | |
| self.SchrittweiteTemp = 0.05 | |
| self.Tsinkout = Tsinkout | |
| self.pyPinch = pyPinch | |
| def COP(self,T): | |
| COPList = [] | |
| StringList = [] | |
| if 144 <= self.Tsinkout <= 212 and 25 <= self.Tsinkout-T <= 190: #Prototypical Stirling | |
| COPList.append(1.28792 * ((self.Tsinkout-(T)) + 2 * 0.54103)**(-0.37606) * (self.Tsinkout+273 + 0.54103)**0.35992) | |
| StringList.append('Prototypical Stirling') | |
| if 80 <= self.Tsinkout <= 160 and 25 <= self.Tsinkout-T <= 95: #VHTHP (HFC/HFO) | |
| COPList.append(1.9118 * ((self.Tsinkout-(T)) + 2 * 0.04419)**(-0.89094) * (self.Tsinkout+273 + 0.04419)**0.67895) | |
| StringList.append('VHTHP (HFC/HFO)') | |
| if 25 <= self.Tsinkout <= 100 and 10 <= self.Tsinkout-T <= 78: #SHP and HTHPs (HFC/HFO) | |
| COPList.append(1.4480*(10**12) * ((self.Tsinkout-(T)) + 2 * 88.73)**(-4.9469)) | |
| StringList.append('SHP and HTHPs (HFC/HFO)') | |
| if 70 <= self.Tsinkout <= 85 and 30 <= self.Tsinkout-T <= 75: #SHP and HTHPs (R717) | |
| COPList.append(40.789 * ((self.Tsinkout-(T)) + 2 * 1.0305)**(-1.0489) * (self.Tsinkout+273 + 1.0305)**0.29998) | |
| StringList.append('SHP and HTHPs (R717)') | |
| if len(COPList) == 0: | |
| COPList.append((self.Tsinkout+273.15)/(self.Tsinkout-T)*0.5) # Carnot | |
| StringList.append('Carnot') | |
| return max(COPList),StringList[COPList.index(max(COPList))] | |
| def get_available_heat_pumps(self, T): | |
| """Returns list of all heat pump types with their COPs and availability status""" | |
| hp_list = [] | |
| delta_T = self.Tsinkout - T | |
| # Prototypical Stirling | |
| if 144 <= self.Tsinkout <= 212 and 25 <= delta_T <= 190: | |
| cop = 1.28792 * ((self.Tsinkout-(T)) + 2 * 0.54103)**(-0.37606) * (self.Tsinkout+273 + 0.54103)**0.35992 | |
| hp_list.append({'name': 'Prototypical Stirling', 'cop': cop, 'available': True, 'reason': ''}) | |
| else: | |
| hp_list.append({'name': 'Prototypical Stirling', 'cop': None, 'available': False, | |
| 'reason': f'Requires: 144°C≤T_sink≤212°C, 25°C≤ΔT≤190°C (Current: T_sink={self.Tsinkout:.1f}°C, ΔT={delta_T:.1f}°C)'}) | |
| # VHTHP (HFC/HFO) | |
| if 80 <= self.Tsinkout <= 160 and 25 <= delta_T <= 95: | |
| cop = 1.9118 * ((self.Tsinkout-(T)) + 2 * 0.04419)**(-0.89094) * (self.Tsinkout+273 + 0.04419)**0.67895 | |
| hp_list.append({'name': 'VHTHP (HFC/HFO)', 'cop': cop, 'available': True, 'reason': ''}) | |
| else: | |
| hp_list.append({'name': 'VHTHP (HFC/HFO)', 'cop': None, 'available': False, | |
| 'reason': f'Requires: 80°C≤T_sink≤160°C, 25°C≤ΔT≤95°C (Current: T_sink={self.Tsinkout:.1f}°C, ΔT={delta_T:.1f}°C)'}) | |
| # SHP and HTHPs (HFC/HFO) | |
| if 25 <= self.Tsinkout <= 100 and 10 <= delta_T <= 78: | |
| cop = 1.4480*(10**12) * ((self.Tsinkout-(T)) + 2 * 88.73)**(-4.9469) | |
| hp_list.append({'name': 'SHP and HTHPs (HFC/HFO)', 'cop': cop, 'available': True, 'reason': ''}) | |
| else: | |
| hp_list.append({'name': 'SHP and HTHPs (HFC/HFO)', 'cop': None, 'available': False, | |
| 'reason': f'Requires: 25°C≤T_sink≤100°C, 10°C≤ΔT≤78°C (Current: T_sink={self.Tsinkout:.1f}°C, ΔT={delta_T:.1f}°C)'}) | |
| # SHP and HTHPs (R717) | |
| if 70 <= self.Tsinkout <= 85 and 30 <= delta_T <= 75: | |
| cop = 40.789 * ((self.Tsinkout-(T)) + 2 * 1.0305)**(-1.0489) * (self.Tsinkout+273 + 1.0305)**0.29998 | |
| hp_list.append({'name': 'SHP and HTHPs (R717)', 'cop': cop, 'available': True, 'reason': ''}) | |
| else: | |
| hp_list.append({'name': 'SHP and HTHPs (R717)', 'cop': None, 'available': False, | |
| 'reason': f'Requires: 70°C≤T_sink≤85°C, 30°C≤ΔT≤75°C (Current: T_sink={self.Tsinkout:.1f}°C, ΔT={delta_T:.1f}°C)'}) | |
| # Carnot (always available) | |
| cop_carnot = (self.Tsinkout+273.15)/(self.Tsinkout-T)*0.5 | |
| hp_list.append({'name': 'Carnot', 'cop': cop_carnot, 'available': True, 'reason': ''}) | |
| return hp_list | |
| def COP_specific(self, T, hp_type): | |
| """Calculate COP for a specific heat pump type""" | |
| if hp_type == 'Prototypical Stirling': | |
| if 144 <= self.Tsinkout <= 212 and 25 <= self.Tsinkout-T <= 190: | |
| return 1.28792 * ((self.Tsinkout-(T)) + 2 * 0.54103)**(-0.37606) * (self.Tsinkout+273 + 0.54103)**0.35992 | |
| elif hp_type == 'VHTHP (HFC/HFO)': | |
| if 80 <= self.Tsinkout <= 160 and 25 <= self.Tsinkout-T <= 95: | |
| return 1.9118 * ((self.Tsinkout-(T)) + 2 * 0.04419)**(-0.89094) * (self.Tsinkout+273 + 0.04419)**0.67895 | |
| elif hp_type == 'SHP and HTHPs (HFC/HFO)': | |
| if 25 <= self.Tsinkout <= 100 and 10 <= self.Tsinkout-T <= 78: | |
| return 1.4480*(10**12) * ((self.Tsinkout-(T)) + 2 * 88.73)**(-4.9469) | |
| elif hp_type == 'SHP and HTHPs (R717)': | |
| if 70 <= self.Tsinkout <= 85 and 30 <= self.Tsinkout-T <= 75: | |
| return 40.789 * ((self.Tsinkout-(T)) + 2 * 1.0305)**(-1.0489) * (self.Tsinkout+273 + 1.0305)**0.29998 | |
| # Fallback to Carnot | |
| return (self.Tsinkout+273.15)/(self.Tsinkout-T)*0.5 | |
| def deleteTemperaturePockets(self): | |
| self.pyPinch = self.pyPinch.PinchAnalyse | |
| self.hotUtility = self.pyPinch.hotUtility | |
| self.heatCascade = self.pyPinch.heatCascade | |
| self._temperatures = self.pyPinch._temperatures | |
| self.deletedPocketdict = TPD(self.hotUtility, self.heatCascade, self._temperatures).deleteTemperaturePockets() | |
| def splitHotandCold(self): | |
| self.splitHotTemperatures = [] | |
| self.splitColdTemperatures = [] | |
| self.splitHotH = [] | |
| self.splitColdH = [] | |
| testHot = 0 | |
| testCold = 0 | |
| for i in range(len(self.deletedPocketdict['T'][0])): | |
| if i >= len(self.deletedPocketdict['deltaH'][0]): | |
| continue | |
| if self.deletedPocketdict['deltaH'][0][i] > 0 and testHot == 0: | |
| self.splitHotTemperatures.append(self.deletedPocketdict['T'][0][i]) | |
| self.splitHotH.append(self.deletedPocketdict['H'][0][i]) | |
| self.splitHotTemperatures.append(self.deletedPocketdict['T'][0][i+1]) | |
| self.splitHotH.append(self.deletedPocketdict['H'][0][i+1]) | |
| testHot = 1 | |
| elif self.deletedPocketdict['deltaH'][0][i] > 0 and testHot == 1: | |
| self.splitHotTemperatures.append(self.deletedPocketdict['T'][0][i+1]) | |
| self.splitHotH.append(self.deletedPocketdict['H'][0][i+1]) | |
| elif self.deletedPocketdict['deltaH'][0][i] < 0 and testCold == 0: | |
| self.splitColdTemperatures.append(self.deletedPocketdict['T'][0][i]) | |
| self.splitColdH.append(self.deletedPocketdict['H'][0][i]) | |
| self.splitColdTemperatures.append(self.deletedPocketdict['T'][0][i+1]) | |
| self.splitColdH.append(self.deletedPocketdict['H'][0][i+1]) | |
| testCold = 1 | |
| elif self.deletedPocketdict['deltaH'][0][i] < 0 and testCold == 1: | |
| self.splitColdTemperatures.append(self.deletedPocketdict['T'][0][i+1]) | |
| self.splitColdH.append(self.deletedPocketdict['H'][0][i+1]) | |
| elif self.deletedPocketdict['deltaH'][0][i] == 0: | |
| if self.deletedPocketdict['deltaH'][0][i-1] < 0: | |
| self.splitColdTemperatures.append(self.deletedPocketdict['T'][0][i+1]) | |
| self.splitColdH.append(self.deletedPocketdict['H'][0][i+1]) | |
| elif self.deletedPocketdict['deltaH'][0][i-1] > 0: | |
| self.splitHotTemperatures.append(self.deletedPocketdict['T'][0][i+1]) | |
| self.splitHotH.append(self.deletedPocketdict['H'][0][i+1]) | |
| else: | |
| pass | |
| else: | |
| pass | |
| self.splitColddeltaH = [] | |
| self.splitHotdeltaH = [] | |
| for i in range(len(self.splitColdH)-1): | |
| self.splitColddeltaH.append(self.splitColdH[i+1]-self.splitColdH[i]) | |
| for i in range(len(self.splitHotH)-1): | |
| self.splitHotdeltaH.append(self.splitHotH[i+1]-self.splitHotH[i]) | |
| return {'H':self.splitHotH, 'T':self.splitHotTemperatures, 'deltaH':self.splitHotdeltaH},{'H':self.splitColdH, 'T':self.splitColdTemperatures, 'deltaH':self.splitColddeltaH} | |
| def QpunktEv(self,T,Quelle): # FEHLER | |
| return self.GCCSource['H'][Quelle] + ((self.GCCSource['H'][Quelle+1]-self.GCCSource['H'][Quelle])/(self.GCCSource['T'][Quelle+1]-self.GCCSource['T'][Quelle])) * (T-self.GCCSource['T'][Quelle]) | |
| def QpunktKo(self,T,Quelle): | |
| return self.GCCSink['H'][Quelle-1] + ((self.GCCSink['H'][Quelle-1]-self.GCCSink['H'][Quelle])/(self.GCCSink['T'][Quelle-1]-self.GCCSink['T'][Quelle])) * (T-self.GCCSink['T'][Quelle-1]) | |
| def TKo(self,H,Quelle): | |
| return self.GCCSink['T'][Quelle] - ((self.GCCSink['T'][Quelle]-self.GCCSink['T'][Quelle+1])/(self.GCCSink['H'][Quelle]-self.GCCSink['H'][Quelle+1])) * (self.GCCSink['H'][Quelle]-H) | |
| def IntegrateHeatPump(self): | |
| Test = 0 | |
| TSTest = 0 | |
| #Starttemperatur | |
| if self.Integrationtype == 'Itterativ': | |
| self.Tsinkout = self.GCCSink['T'][0] | |
| else: | |
| pass | |
| Quelle = 0 | |
| self.SchrittweiteTemp = (self.GCCSource['T'][Quelle] - self.GCCSource['T'][Quelle+1])/10 | |
| T = self.GCCSource['T'][Quelle]-self.SchrittweiteTemp | |
| while T > self.GCCSource['T'][-1]: | |
| if T <= self.GCCSource['T'][Quelle+1]: | |
| Quelle +=1 | |
| self.SchrittweiteTemp = (self.GCCSource['T'][Quelle] - self.GCCSource['T'][Quelle+1])/10 | |
| T = self.GCCSource['T'][Quelle]-self.SchrittweiteTemp | |
| if self.GCCSource['deltaH'][Quelle] == 0.0: | |
| Quelle +=1 | |
| self.SchrittweiteTemp = (self.GCCSource['T'][Quelle] - self.GCCSource['T'][Quelle+1])/10 | |
| T = self.GCCSource['T'][Quelle]-self.SchrittweiteTemp | |
| if T < self.GCCSource['T'][Quelle+1]: | |
| T = self.GCCSource['T'][Quelle+1] | |
| COP = self.COP(T) | |
| QpunktEv = self.QpunktEv(T,Quelle) | |
| QpunktKo = QpunktEv * ((1-(1/COP[0]))**(-1)) | |
| self.COPwerte.append(round(COP[0],3)) | |
| self.EvWP.append(round(QpunktEv)) | |
| self.KoWP.append(round(QpunktKo)) | |
| self.COPT.append(T) | |
| for i in range(len(self.GCCSink['T'])): | |
| if self.GCCSink['T'][i] <= self.Tsinkout: | |
| KoQuelle = i | |
| break | |
| if QpunktKo >= self.QpunktKo(self.Tsinkout, KoQuelle) and self.Integrationtype == None and TSTest == 1 and self.Tsinkout < self.GCCSink['T'][0]: | |
| break | |
| if QpunktKo >= self.QpunktKo(self.Tsinkout, KoQuelle) and self.Integrationtype == None and TSTest == 0: | |
| if self.Tsinkout <= self.GCCSink['T'][0]: | |
| T+=self.SchrittweiteTemp | |
| self.SchrittweiteTemp = self.SchrittweiteTemp/200 | |
| TSTest = 1 | |
| else: | |
| break | |
| if QpunktKo >= self.GCCSink['H'][0] and Test == 0: | |
| T+=self.SchrittweiteTemp | |
| self.SchrittweiteTemp = self.SchrittweiteTemp/200 | |
| Test = 1 | |
| elif QpunktKo >= self.GCCSink['H'][0] and Test == 1: | |
| break | |
| T-=self.SchrittweiteTemp | |
| if T < self.GCCSource['T'][Quelle+1]: | |
| T = self.GCCSource['T'][Quelle+1] | |
| if T <= self.GCCSource['T'][-1]: | |
| T = self.GCCSource['T'][-1] | |
| COP = self.COP(T) | |
| QpunktEv = self.GCCSource['H'][-1] | |
| QpunktKo = QpunktEv * (1-(1/COP[0]))**(-1) | |
| if self.Integrationtype == 'Itterativ': | |
| for i in range(len(self.GCCSink['H'])): | |
| if QpunktKo >= self.GCCSink['H'][i]: | |
| QuelleSenke = i-1 | |
| break | |
| self.Tsinkout = self.TKo(QpunktKo,QuelleSenke) | |
| COP = self.COP(T) | |
| QpunktKo = QpunktEv * (1-(1/COP[0]))**(-1) | |
| TSinktest = self.TKo(QpunktKo, QuelleSenke) | |
| while abs(self.Tsinkout - TSinktest) >= 1: | |
| for i in range(len(self.GCCSink['H'])): | |
| if QpunktKo >= self.GCCSink['H'][i]: | |
| QuelleSenke = i-1 | |
| break | |
| self.Tsinkout = self.TKo(QpunktKo,QuelleSenke) | |
| COP = self.COP(T) | |
| QpunktKo = QpunktEv * (1-(1/COP[0]))**(-1) | |
| TSinktest = self.TKo(QpunktKo, QuelleSenke) | |
| self.COPwerte.append(COP[0]) | |
| self.EvWP.append(round(QpunktEv)) | |
| self.KoWP.append(round(QpunktKo)) | |
| self.COPT.append(T) | |
| self.COPRegression = COP[1] | |
| table = {'COP':self.COPwerte[::30],'QQuelle':self.EvWP[::30],'QSenke':self.KoWP[::30]} | |
| self.tableISSP = {'Temp': self.COPT, 'COP':self.COPwerte,'QQuelle':self.EvWP,'QSenke':self.KoWP} | |
| print(tabulate(table,headers='keys')) | |
| print({'COP':self.COPwerte[-1],'QQuelle':self.EvWP[-1],'QSenke':self.KoWP[-1]}) | |
| def findIntegration(self):#Genaue Integration implementieren! | |
| self.IntegrationPoint = {'Temp': [], 'COP':[],'QQuelle':[],'QSenke':[]} | |
| for i in range(len(self.tableISSP['QSenke'])): | |
| if self.tableISSP['QSenke'][i] >= self.GCCdraw['H'][0]: | |
| self.IntegrationPoint['Temp'].append(self.tableISSP['Temp'][0]+self.SchrittweiteTemp) | |
| self.IntegrationPoint['Temp'].append(self.tableISSP['Temp'][i]) | |
| self.IntegrationPoint['COP'].append(self.tableISSP['COP'][i]) | |
| self.IntegrationPoint['QQuelle'].append(self.tableISSP['QQuelle'][i]) | |
| #self.IntegrationPoint['QQuelle'].append(self.tableISSP['QQuelle'][self.tableISSP['Temp'].index(self.IntegrationPoint['Temp'][-1])]) | |
| self.IntegrationPoint['QSenke'].append(self.tableISSP['QSenke'][i]) | |
| break | |
| else: | |
| self.IntegrationPoint['Temp'].append(self.tableISSP['Temp'][0]+self.SchrittweiteTemp) | |
| self.IntegrationPoint['Temp'].append(self.tableISSP['Temp'][-1]) | |
| self.IntegrationPoint['COP'].append(self.tableISSP['COP'][-1]) | |
| self.IntegrationPoint['QQuelle'].append(self.tableISSP['QQuelle'][-1]) | |
| #self.IntegrationPoint['QQuelle'].append(self.tableISSP['QQuelle'][self.tableISSP['Temp'].index(self.IntegrationPoint['Temp'][-1])]) | |
| self.IntegrationPoint['QSenke'].append(self.tableISSP['QSenke'][-1]) | |
| break | |
| def IntegrateHeatPump_specific(self, hp_type): | |
| """Same as IntegrateHeatPump but uses specific heat pump type""" | |
| self.selected_hp_type = hp_type | |
| # Store original COP method | |
| original_COP = self.COP | |
| # Replace COP method temporarily | |
| def COP_wrapper(T): | |
| cop_val = self.COP_specific(T, hp_type) | |
| return (cop_val, hp_type) if cop_val else original_COP(T) | |
| self.COP = COP_wrapper | |
| # Run integration | |
| self.IntegrateHeatPump() | |
| # Restore original method | |
| self.COP = original_COP | |
| def solveforISSP(self): | |
| self.GCCdraw = self.pyPinch.solvePinchforHPI().grandCompositeCurve | |
| self.GCC = self.deleteTemperaturePockets() | |
| self.IntegrateHeatPump() | |
| self.findIntegration() | |
| return self.IntegrationPoint | |
| def HPI(self): | |
| self.GCCdraw = self.pyPinch.solvePinchforHPI().grandCompositeCurve | |
| Temperaturesdraw = [] | |
| for i in self.pyPinch.PinchAnalyse._temperatures: | |
| Temperaturesdraw.append(i) | |
| self.deleteTemperaturePockets() | |
| self.GCCSource, self.GCCSink = self.splitHotandCold() | |
| self.IntegrateHeatPump() | |
| self.findIntegration() | |
| HPIPlot(self.streamsDataFile[:-4],self.Tsinkout,self.pyPinch,self.EvWP,self.KoWP, | |
| self.COPwerte,self.COPT,self.GCCdraw, Temperaturesdraw, self.COPRegression).drawCOPKo() | |
| HPIPlot(self.streamsDataFile[:-4],self.Tsinkout,self.pyPinch,self.EvWP,self.KoWP, | |
| self.COPwerte,self.COPT,self.GCCdraw, Temperaturesdraw, self.COPRegression).drawGrandCompositeCurve() | |