Source code for MultiCircuitEvaporator

from __future__ import division #Make integer 3/2 give 1.5 in python 2.x
from math import floor,ceil
from CoolProp.CoolProp import Props
from FinCorrelations import FinInputs
from Evaporator import EvaporatorClass
import numpy as np, pylab
import copy
from CoolProp.Plots import Ph
from scipy.optimize import newton
from ACHPTools import Write2CSV

#MultiCircuitEvaporator inherits things from the Evaporator base class
[docs]class MultiCircuitEvaporatorClass(EvaporatorClass): def __init__(self,**kwargs): self.__dict__.update(kwargs)
[docs] def Update(self,**kwargs): self.__dict__.update(kwargs)
[docs] def OutputList(self): """ Return a list of parameters for this component for further output It is a list of tuples, and each tuple is formed of items: [0] Description of value [1] Units of value [2] The value itself """ Output_list=[] num_evaps= int(self.Fins.Tubes.Ncircuits) Output_list_i=[] for i in range(num_evaps): #Generate output list with all evaporators Output_list_i.append([('Volumetric flow rate'+' '+str(i),'m^3/s',self.Evaps[i].Fins.Air.Vdot_ha), ('Inlet Dry bulb temp'+' '+str(i),'K',self.Evaps[i].Fins.Air.Tdb), ('Inlet Air pressure'+' '+str(i),'kPa',self.Evaps[i].Fins.Air.p), ('Inlet Air Relative Humidity'+' '+str(i),'-',self.Evaps[i].Fins.Air.RH), ('Tubes per bank'+' '+str(i),'-',self.Evaps[i].Fins.Tubes.NTubes_per_bank), ('Number of banks'+' '+str(i),'-',self.Evaps[i].Fins.Tubes.Nbank), ('Number circuits'+' '+str(i),'-',self.Evaps[i].Fins.Tubes.Ncircuits), ('Length of tube'+' '+str(i),'m',self.Evaps[i].Fins.Tubes.Ltube), ('Tube OD'+' '+str(i),'m',self.Evaps[i].Fins.Tubes.OD), ('Tube ID'+' '+str(i),'m',self.Evaps[i].Fins.Tubes.ID), ('Tube Long. Pitch'+' '+str(i),'m',self.Evaps[i].Fins.Tubes.Pl), ('Tube Transverse Pitch'+' '+str(i),'m',self.Evaps[i].Fins.Tubes.Pt), ('Outlet superheat'+' '+str(i),'K',self.Evaps[i].Tout_r-self.Evaps[i].Tdew_r), ('Fins per inch'+' '+str(i),'1/in',self.Evaps[i].Fins.Fins.FPI), ('Fin waviness pd'+' '+str(i),'m',self.Evaps[i].Fins.Fins.Pd), ('Fin waviness xf'+' '+str(i),'m',self.Evaps[i].Fins.Fins.xf), ('Fin thickness'+' '+str(i),'m',self.Evaps[i].Fins.Fins.t), ('Fin Conductivity'+' '+str(i),'W/m-K',self.Evaps[i].Fins.Fins.k_fin), ('Refrigerant flowrate'+' '+str(i),'kg/s',self.Evaps[i].mdot_r), ('Q Total'+' '+str(i),'W',self.Evaps[i].Q), ('Q Superheat'+' '+str(i),'W',self.Evaps[i].Q_superheat), ('Q Two-Phase'+' '+str(i),'W',self.Evaps[i].Q_2phase), ('Inlet ref. temp'+' '+str(i),'K',self.Evaps[i].Tin_r), ('Outlet ref. temp'+' '+str(i),'K',self.Evaps[i].Tout_r), ('Outlet air temp'+' '+str(i),'K',self.Evaps[i].Tout_a), ('Pressure Drop Total'+' '+str(i),'Pa',self.Evaps[i].DP_r), ('Pressure Drop Superheat'+' '+str(i),'Pa',self.Evaps[i].DP_r_superheat), ('Pressure Drop Two-Phase'+' '+str(i),'Pa',self.Evaps[i].DP_r_2phase), ('Charge Total'+' '+str(i),'kg',self.Evaps[i].Charge), ('Charge Superheat'+' '+str(i),'kg',self.Evaps[i].Charge_superheat), ('Charge Two-Phase'+' '+str(i),'kg',self.Evaps[i].Charge_2phase), ('Mean HTC Superheat'+' '+str(i),'W/m^2-K',self.Evaps[i].h_r_superheat), ('Mean HTC Two-phase'+' '+str(i),'W/m^2-K',self.Evaps[i].h_r_2phase), ('Wetted Area Fraction Superheat'+' '+str(i),'-',self.Evaps[i].w_superheat), ('Wetted Area Fraction Two-phase'+' '+str(i),'-',self.Evaps[i].w_2phase), ('Mean Air HTC'+' '+str(i),'W/m^2-K',self.Evaps[i].Fins.h_a), ('Surface Effectiveness'+' '+str(i),'-',self.Evaps[i].Fins.eta_a), ('Air-side area (fin+tubes)'+' '+str(i),'m^2',self.Evaps[i].Fins.A_a), ('Mass Flow rate dry Air'+' '+str(i),'kg/s',self.Evaps[i].Fins.mdot_da), ('Mass Flow rate humid Air'+' '+str(i),'kg/s',self.Evaps[i].Fins.mdot_ha), ('Pressure Drop Air-side'+' '+str(i),'Pa',self.Evaps[i].Fins.dP_a), ('Sensible Heat Ratio'+' '+str(i),'-',self.Evaps[i].SHR)]) for i in range(len(Output_list_i[0])): #sort output list, such that corresponding values are next to each other sumsi=0 #need sums and avgs for n in range(num_evaps): Output_list.append(Output_list_i[n][i]) if type(Output_list_i[n][i][2]) is not type("string"): sumsi+=Output_list_i[n][i][2] #sum up values if n == num_evaps-1: Output_list.append((Output_list_i[n][i][0][:-2]+" sum",Output_list_i[n][i][1],sumsi)) Output_list.append((Output_list_i[n][i][0][:-2]+" avg",Output_list_i[n][i][1],sumsi/num_evaps)) Output_List_tot=[] #append optional parameters, if applicable if hasattr(self,'TestName'): Output_List_tot.append(('Name','N/A',self.TestName)) if hasattr(self,'TestDescription'): Output_List_tot.append(('Description','N/A',self.TestDescription)) if hasattr(self,'TestDetails'): Output_List_tot.append(('Details','N/A',self.TestDetails)) for i in range(0,len(Output_list)): #append default parameters to output list Output_List_tot.append(Output_list[i]) return Output_List_tot
[docs] def Calculate(self): #Check that the length of lists of mdot_r and FinsTubes.Air.Vdot_ha #match the number of circuits or are all equal to 1 (standard evap) Ncircuits=int(self.Fins.Tubes.Ncircuits) # Make Ncircuits copies of evaporator classes defined # by the inputs to the MCE superclass EvapDict=self.__dict__ self.Evaps=[] for i in range(Ncircuits): # Make a deep copy to break all the links between the Fins structs # of each of the evaporator instances ED=copy.deepcopy(EvapDict) #Create new evaporator instanciated with new deep copied dictionary E=EvaporatorClass(**ED) #Add to list of evaporators self.Evaps.append(E) #Upcast single values to lists, and convert numpy arrays to lists self.Fins.Air.Vdot_ha=np.atleast_1d(self.Fins.Air.Vdot_ha).tolist() self.mdot_r=np.atleast_1d(self.mdot_r).tolist() if Ncircuits != len(self.mdot_r) and len(self.mdot_r)>1: print "Problem with length of vector for mdot_r for MCE" else: if len(self.mdot_r)==1: #Single value passed in for mdot_r if hasattr(self,'mdot_r_coeffs'): if len(self.mdot_r_coeffs)!=Ncircuits: raise AttributeError("Size of array mdot_r_coeffs: "+str(len(self.mdot_r_coeffs))+" does not equal Ncircuits: "+str(Ncircuits)) elif abs(np.sum(self.mdot_r_coeffs)-1)>=100*np.finfo(float).eps: raise AttributeError("mdot_r_coeffs must sum to 1.0. Sum *100000is: "+str(100000*np.sum(self.mdot_r_coeffs))) else: # A vector of weighting factors multiplying the total mass flow rate is provided with the right length for i in range(Ncircuits): self.Evaps[i].mdot_r=self.mdot_r[-1]*self.mdot_r_coeffs[i] else: # Refrigerant flow is evenly distributed between circuits, # give each evaporator an equal portion of the refrigerant for i in range(Ncircuits): self.Evaps[i].mdot_r=self.mdot_r[-1]/Ncircuits else: for i in range(Ncircuits): self.Evaps[i].mdot_r=self.mdot_r[i] # Deal with the possibility that the quality might be varied among circuits if hasattr(self,'mdot_v_coeffs'): if len(self.mdot_v_coeffs)!=Ncircuits: raise AttributeError("Size of array mdot_v_coeffs: "+str(len(self.mdot_v_coeffs))+" does not equal Ncircuits: "+str(Ncircuits)) elif abs(np.sum(self.mdot_v_coeffs)-1)>=10*np.finfo(float).eps: raise AttributeError("mdot_v_coeffs must sum to 1.0. Sum is: "+str(np.sum(self.mdot_v_coeffs))) else: hsatL=Props('H','P',self.psat_r,'Q',0.0,self.Ref)*1000 hsatV=Props('H','P',self.psat_r,'Q',1.0,self.Ref)*1000 x_inlet=(self.hin_r-hsatL)/(hsatV-hsatL) mdot_v=x_inlet*sum(self.mdot_r) for i in range(Ncircuits): mdot_v_i=self.mdot_v_coeffs[i]*mdot_v x_i=mdot_v_i/self.Evaps[i].mdot_r self.Evaps[i].hin_r=Props('H','P',self.psat_r,'Q',x_i,self.Ref)*1000 #For backwards compatibility, if the coefficients are provided in the FinInputs class, copy them to the base class if hasattr(self.Fins.Air,'Vdot_ha_coeffs'): self.Vdot_ha_coeffs=self.Fins.Air.Vdot_ha_coeffs print "Warning: please put the vector Vdot_ha_coeffs in the base MCE class, accesssed as MCE.Vdot_ha_coeffs" if Ncircuits !=len(self.Fins.Air.Vdot_ha) and len(self.Fins.Air.Vdot_ha)>1: print "Problem with length of vector for Vdot_ha for MCE" else: if len(self.Fins.Air.Vdot_ha)==1: if hasattr(self,'Vdot_ha_coeffs'): if len(self.Vdot_ha_coeffs)!=Ncircuits: raise AttributeError("Size of array Vdot_ha_coeffs: "+str(len(self.Vdot_ha_coeffs))+" does not equal Ncircuits: "+str(Ncircuits)) elif abs(np.sum(self.Vdot_ha_coeffs)-1)>=10*np.finfo(float).eps: raise AttributeError("Vdot_ha_coeffs does not sum to 1.0!") else: # A vector of factors multiplying the total volume flow rate is provided for i in range(Ncircuits): self.Evaps[i].Fins.Air.Vdot_ha=self.Fins.Air.Vdot_ha[-1]*self.Vdot_ha_coeffs[i] else: # Air flow is evenly distributed between circuits, # give each circuit an equal portion of the air flow for i in range(Ncircuits): self.Evaps[i].Fins.Air.Vdot_ha=self.Fins.Air.Vdot_ha[-1]/Ncircuits else: for i in range(Ncircuits): self.Evaps[i].Fins.Air.Vdot_ha=self.Fins.Air.Vdot_ha[i] # Distribute the tubes of the bank among the different circuits # If Tubes per bank is divisible by the number of circuits, all the # circuits have the same number of tubes per bank # The circuits are ordered from fewer to more if they are not evenly distributed NTubes_min=int(floor(self.Fins.Tubes.NTubes_per_bank/Ncircuits)) NTubes_max=int(ceil(self.Fins.Tubes.NTubes_per_bank/Ncircuits)) if NTubes_min==NTubes_max: #If evenly divisible, use the tubes per circuit from the division A=Ncircuits else: # Total number of tubes per bank is given by # NTubesPerBank=A*NTube_min+(Ncircuits-A)*NTube_max # A=(NTubesPerBank-Ncircuits*NTube_max)/(NTube_min-Ntube_max) A=(self.Fins.Tubes.NTubes_per_bank-Ncircuits*NTubes_max)/(NTubes_min-NTubes_max) for i in range(Ncircuits): if i+1<=A: self.Evaps[i].Fins.Tubes.NTubes_per_bank=NTubes_min else: self.Evaps[i].Fins.Tubes.NTubes_per_bank=NTubes_max for i in range(Ncircuits): self.Evaps[i].Fins.Tubes.Ncircuits=1 #Actually run each Evaporator self.Evaps[i].Calculate() #Collect the outputs from each of the evaporators individually #Try to mirror the outputs of each of the evaporators self.Q=np.sum([self.Evaps[i].Q for i in range(Ncircuits)]) self.Charge=np.sum([self.Evaps[i].Charge for i in range(Ncircuits)]) self.Charge_superheat=np.sum([self.Evaps[i].Charge_superheat for i in range(Ncircuits)]) self.Charge_2phase=np.sum([self.Evaps[i].Charge_2phase for i in range(Ncircuits)]) self.DP_r=np.mean([self.Evaps[i].DP_r for i in range(Ncircuits)]) #simplified self.DP_r_superheat=np.mean([self.Evaps[i].DP_r_superheat for i in range(Ncircuits)]) #simplified self.DP_r_2phase=np.mean([self.Evaps[i].DP_r_2phase for i in range(Ncircuits)]) #simplified self.Tin_r=np.mean([self.Evaps[i].Tin_r for i in range(Ncircuits)]) #simplified self.h_r_superheat=np.mean([self.Evaps[i].h_r_superheat for i in range(Ncircuits)]) #simplified, really should consider flowrate self.h_r_2phase=np.mean([self.Evaps[i].h_r_2phase for i in range(Ncircuits)]) #simplified, really should consider flowrate self.w_superheat=np.sum([self.Evaps[i].w_superheat for i in range(Ncircuits)])/float(Ncircuits) self.w_2phase=np.sum([self.Evaps[i].w_2phase for i in range(Ncircuits)])/float(Ncircuits) self.hout_r=0.0 for i in range(Ncircuits): self.hout_r+=self.Evaps[i].hout_r*self.Evaps[i].mdot_r self.hout_r=(self.hout_r/self.mdot_r[0]) self.Tin_a=self.Evaps[0].Fins.Air.Tdb #assuming equal temperature for all circuits self.Tout_a=0.0 for i in range(Ncircuits): self.Tout_a+=self.Evaps[i].Tout_a*self.Evaps[i].Fins.Air.Vdot_ha self.Tout_a=(self.Tout_a/self.Fins.Air.Vdot_ha[0]) Pout_r=self.psat_r+self.DP_r/1000.0 hsatV_out=Props('H','P',Pout_r,'Q',1.0,self.Ref)*1000 hsatL_out=Props('H','P',Pout_r,'Q',0.0,self.Ref)*1000 if self.hout_r>hsatV_out: self.Tout_r=newton(lambda T: Props('H','T',T,'P',Pout_r,self.Ref)-self.hout_r/1000,Props('T','P',Pout_r,'Q',1.0,self.Ref)) #saturated temperature at outlet quality else: xout_r=((self.hout_r-hsatL_out)/(hsatV_out-hsatL_out)) self.Tout_r=Props('T','P',Pout_r,'Q',xout_r,self.Ref) #saturated temperature at outlet quality self.Capacity=np.sum([self.Evaps[i].Q for i in range(Ncircuits)])-self.Fins.Air.FanPower self.SHR=np.mean([self.Evaps[i].SHR for i in range(Ncircuits)]) self.UA_a=np.sum([self.Evaps[i].UA_a for i in range(Ncircuits)]) self.UA_r=np.sum([self.Evaps[i].UA_r for i in range(Ncircuits)]) self.Q_superheat=np.sum([self.Evaps[i].Q_superheat for i in range(Ncircuits)]) self.Q_2phase=np.sum([self.Evaps[i].Q_2phase for i in range(Ncircuits)]) #Convert back to a single value for the overall evaporator self.Fins.Air.Vdot_ha=float(self.Fins.Air.Vdot_ha[-1]) if self.Verbosity>0: print chr(127), #progress bar
if __name__=='__main__': #This code runs if this file is run by itself, but otherwise doesn't run FinsTubes=FinInputs() FinsTubes.Tubes.NTubes_per_bank=32 FinsTubes.Tubes.Ncircuits=5 FinsTubes.Tubes.Nbank=3 FinsTubes.Tubes.Ltube=0.452 FinsTubes.Tubes.OD=0.009525 FinsTubes.Tubes.ID=0.0089154 FinsTubes.Tubes.Pl=0.0254 FinsTubes.Tubes.Pt=0.0219964 FinsTubes.Fins.FPI=14.5 FinsTubes.Fins.Pd=0.001 FinsTubes.Fins.xf=0.001 FinsTubes.Fins.t=0.00011 FinsTubes.Fins.k_fin=237 FinsTubes.Air.Vdot_ha=0.5663 FinsTubes.Air.Tmean=299.8 FinsTubes.Air.Tdb=299.8 FinsTubes.Air.p=101.325 FinsTubes.Air.RH=0.51 FinsTubes.Air.RHmean=0.51 FinsTubes.Air.FanPower=438 Tdew=282.0 kwargs={'Ref': 'R410A', 'mdot_r': 0.0708, 'psat_r': Props('P','T',Tdew,'Q',1.0,'R410A'), 'Fins': FinsTubes, 'hin_r':Props('H','T',Tdew,'Q',0.15,'R410A')*1000, 'Verbosity':0 } Evap=EvaporatorClass(**kwargs) Evap.Update(**kwargs) Evap.Calculate() print 'Q=' + str(Evap.Q) + ' W' Tdew=282.0 kwargs={'Ref': 'R410A', 'mdot_r': 0.0708, 'mdot_r_coeffs':[0.1,0.1,0.3,0.3,0.2], #Mass flow distribution at distributor 'mdot_v_coeffs':[0.2,0.2,0.2,0.2,0.2], #Quality distribution at distributor 'Vdot_ha_coeffs':[0.2,0.2,0.2,0.2,0.2], #airside flow distribution 'psat_r': Props('P','T',Tdew,'Q',1.0,'R410A'), 'Fins': FinsTubes, 'hin_r':Props('H','T',Tdew,'Q',0.15,'R410A')*1000, 'Verbosity':0, 'TestName':'MCE-0014', #this and the two next lines can be used to specify exact test conditions 'TestDescription':'shows application of MCE', 'TestDetails':'This is the sample multi circuited evaporator' } MCE=MultiCircuitEvaporatorClass(**kwargs) MCE.Update(**kwargs) MCE.Calculate() print MCE.OutputList() Write2CSV(MCE,open('Evaporator_MCE.csv','w'),append=False) """ print 'Q='+str(MCE.Q)+' W' print MCE.hin_r*MCE.mdot_r[-1] print np.sum([MCE.Evaps[i].hin_r*MCE.Evaps[i].mdot_r for i in range(MCE.Fins.Tubes.Ncircuits)]) h=np.array([MCE.Evaps[i].hout_r for i in range(len(MCE.Evaps))]) p=MCE.psat_r*(1+0*h) # plott maldistribution Ph('R410A') pylab.plot(h/1000,p,'o') pylab.plot(MCE.hout_r/1000,MCE.psat_r,'o') pylab.show() print [MCE.Evaps[i].hout_r for i in range(len(MCE.Evaps))], MCE.hout_r, Props('H','T',MCE.Evaps[-1].Tdew_r,'Q',1,MCE.Evaps[-1].Ref)*1000 print [MCE.Evaps[i].DT_sh_calc for i in range(len(MCE.Evaps))] """