from __future__ import division #Make integer 3/2 give 1.5 in python 2.x
from math import pi,log,exp
from CoolProp.CoolProp import Props,UseSaturationLUT
from Correlations import f_h_1phase_Tube,ShahEvaporation_Average, LockhartMartinelli,LMPressureGradientAvg,AccelPressureDrop,TwoPhaseDensity
from scipy.optimize import brentq #solver to find roots (zero points) of functions
from scipy.interpolate import interp1d
#import numpy as np
from FinCorrelations import WavyLouveredFins,FinInputs,IsFinsClass
from DryWetSegment import DWSVals, DryWetSegment
from ACHPTools import ValidateFields
import numpy as np
# Turn on saturation curve lookup for CoolProp
UseSaturationLUT(1)
[docs]class 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=[]
#append optional parameters, if applicable
if hasattr(self,'TestName'):
Output_List.append(('Name','N/A',self.TestName))
if hasattr(self,'TestDescription'):
Output_List.append(('Description','N/A',self.TestDescription))
if hasattr(self,'TestDetails'):
Output_List.append(('Details','N/A',self.TestDetails))
Output_List_default=[ #default output list
('Volumetric flow rate','m^3/s',self.Fins.Air.Vdot_ha),
('Inlet Dry bulb temp','K',self.Tin_a),
('Inlet Air pressure','kPa',self.Fins.Air.p),
('Inlet Air Relative Humidity','-',self.Fins.Air.RH),
('Tubes per bank','-',self.Fins.Tubes.NTubes_per_bank),
('Number of banks','-',self.Fins.Tubes.Nbank),
('Number circuits','-',self.Fins.Tubes.Ncircuits),
('Length of tube','m',self.Fins.Tubes.Ltube),
('Tube OD','m',self.Fins.Tubes.OD),
('Tube ID','m',self.Fins.Tubes.ID),
('Tube Long. Pitch','m',self.Fins.Tubes.Pl),
('Tube Transverse Pitch','m',self.Fins.Tubes.Pt),
('Outlet superheat','K',self.Tout_r-self.Tdew_r),
('Fins per inch','1/in',self.Fins.Fins.FPI),
('Fin waviness pd','m',self.Fins.Fins.Pd),
('Fin waviness xf','m',self.Fins.Fins.xf),
('Fin thickness','m',self.Fins.Fins.t),
('Fin Conductivity','W/m-K',self.Fins.Fins.k_fin),
('Q Total','W',self.Q),
('Q Superheat','W',self.Q_superheat),
('Q Two-Phase','W',self.Q_2phase),
('Inlet ref. temp','K',self.Tin_r),
('Outlet ref. temp','K',self.Tout_r),
('Outlet air temp','K',self.Tout_a),
('Pressure Drop Total','Pa',self.DP_r),
('Pressure Drop Superheat','Pa',self.DP_r_superheat),
('Pressure Drop Two-Phase','Pa',self.DP_r_2phase),
('Charge Total','kg',self.Charge),
('Charge Superheat','kg',self.Charge_superheat),
('Charge Two-Phase','kg',self.Charge_2phase),
('Mean HTC Superheat','W/m^2-K',self.h_r_superheat),
('Mean HTC Two-phase','W/m^2-K',self.h_r_2phase),
('Wetted Area Fraction Superheat','-',self.w_superheat),
('Wetted Area Fraction Two-phase','-',self.w_2phase),
('Mean Air HTC','W/m^2-K',self.Fins.h_a),
('Surface Effectiveness','-',self.Fins.eta_a),
('Air-side area (fin+tubes)','m^2',self.Fins.A_a),
('Mass Flow rate dry Air','kg/s',self.Fins.mdot_da),
('Mass Flow rate humid Air','kg/s',self.Fins.mdot_ha),
('Pressure Drop Air-side','Pa',self.Fins.dP_a),
('Sensible Heat Ratio','-',self.SHR)
]
for i in range(0,len(Output_List_default)): #append default parameters to output list
Output_List.append(Output_List_default[i])
return Output_List
[docs] def AirSideCalcs(self):
WavyLouveredFins(self.Fins)
[docs] def Initialize(self):
#Input validation the first call of Initialize
if False:#not hasattr(self,'IsValidated'):
self.Fins.Validate()
reqFields=[
('Ref',str,None,None),
('psat_r',float,1e-6,100000),
('Fins',IsFinsClass,None,None),
('hin_r',float,-100000,10000000),
('mdot_r',float,0.000001,10),
]
optFields=['Verbosity']
d=self.__dict__ #Current fields in model
ValidateFields(d,reqFields,optFields)
self.IsValidated=True
# Retrieve some parameters from nested structures
# for code compactness
self.ID=self.Fins.Tubes.ID
self.OD=self.Fins.Tubes.OD
self.Ltube=self.Fins.Tubes.Ltube
self.NTubes_per_bank=self.Fins.Tubes.NTubes_per_bank
self.Nbank=self.Fins.Tubes.Nbank
self.Ncircuits=self.Fins.Tubes.Ncircuits
self.Tin_a=self.Fins.Air.Tdb
# Calculate an effective length of circuit if circuits are
# not all the same length
TotalLength=self.Ltube*self.NTubes_per_bank*self.Nbank
self.Lcircuit=TotalLength/self.Ncircuits
# Wetted area on the refrigerant side
self.A_r_wetted=self.Ncircuits*pi*self.ID*self.Lcircuit
self.V_r=self.Ncircuits*self.Lcircuit*pi*self.ID**2/4.0
#Average mass flux of refrigerant in circuit
self.G_r = self.mdot_r/(self.Ncircuits*pi*self.ID**2/4.0) #[kg/m^2-s]
"""
Tsat() is a relatively slow function since it does a Dekker solve
over the full two-phase region. So store the value in order to cut
down on computational work.
"""
## Bubble and dew temperatures (same for fluids without glide)
self.Tbubble_r=Props('T','P',self.psat_r,'Q',0,self.Ref)
self.Tdew_r=Props('T','P',self.psat_r,'Q',1,self.Ref)
## Mean temperature for use in HT relationships
self.Tsat_r=(self.Tbubble_r+self.Tdew_r)/2
# Latent heat
self.h_fg=(Props('H','T',self.Tdew_r,'Q',1.0,self.Ref)-Props('H','T',self.Tbubble_r,'Q',0.0,self.Ref))*1000. #[J/kg]
self.Fins.Air.RHmean=self.Fins.Air.RH
WavyLouveredFins(self.Fins)
self.mdot_ha=self.Fins.mdot_ha #[kg_ha/s]
self.mdot_da=self.Fins.mdot_da #[kg_da/s]
[docs] def Calculate(self):
self.Initialize()
# Input and output thermodynamic properties
ssatL=Props('S','T',self.Tbubble_r,'Q',0,self.Ref)*1000
ssatV=Props('S','T',self.Tdew_r,'Q',1,self.Ref)*1000
hsatL=Props('H','T',self.Tbubble_r,'Q',0,self.Ref)*1000
hsatV=Props('H','T',self.Tdew_r,'Q',1,self.Ref)*1000
#Must give enthalpy and pressure as inputs
self.xin_r=(self.hin_r-hsatL)/(hsatV-hsatL)
self.sin_r=self.xin_r*ssatV+(1-self.xin_r)*ssatL
self.hin_r=self.xin_r*hsatV+(1-self.xin_r)*hsatL
self.Tin_r=self.xin_r*self.Tdew_r+(1-self.xin_r)*self.Tbubble_r
if self.xin_r>1.0:
raise ValueError
#Begin by assuming that you go all the way to saturated vapor at least
self.xout_2phase=1.0
if self._TwoPhase_Forward(1.0)<0:
# Evaporator outlet is in two-phase region, use all the area and find the outlet quality
existsSuperheat=False
self.w_2phase=1.0
def OBJECTIVE(xout):
self.xout_2phase=xout
Q_target=self.mdot_r*(xout-self.xin_r)*(hsatV-hsatL)
self._TwoPhase_Forward(self.w_2phase)
return self.Q_2phase-Q_target
#Use a solver to find outlet quality
brentq(OBJECTIVE,self.xin_r,1.0)
self.w_superheat=0.0
self.Q_superheat=0.0
self.h_r_superheat=0.0
self.Re_r_superheat=0.0
self.Charge_superheat=0.0
self.Q_sensible_superheat=0.0
self.Tout_a_superheat=0.0
self.DP_r_superheat=0.0
self.fdry_superheat=0.0
else:
existsSuperheat=True
# Evaporator outlet is in superheated region, everything is ok
self.w_2phase=brentq(self._TwoPhase_Forward,0.00000000001,0.9999999999)
self._Superheat_Forward(1-self.w_2phase)
self.Q=self.Q_superheat+self.Q_2phase
self.Charge=self.Charge_superheat+self.Charge_2phase
if self.Verbosity>4:
print self.Q,"Evaporator.Q"
self.Capacity=self.Q-self.Fins.Air.FanPower
#Sensible heat ratio [-]
self.SHR=(self.Q_sensible_2phase+self.Q_sensible_superheat)/self.Q
#Average air outlet temperature (area fraction weighted average) [K]
self.Tout_a=self.w_superheat*self.Tout_a_superheat+self.w_2phase*self.Tout_a_2phase
self.DP_r=self.DP_r_superheat+self.DP_r_2phase
#Outlet enthalpy obtained from energy balance
self.hout_r=self.hin_r+self.Q/self.mdot_r
#Outlet entropy
if existsSuperheat==True:
self.sout_r=Props('S','T',self.Tout_r,'P',self.psat_r,self.Ref)*1000
else:
xout_r=(self.hout_r-hsatL)/(hsatV-hsatL)
self.sout_r=ssatV*xout_r+(1-xout_r)*ssatL
#Outlet superheat an temperature (in case of two phase)
if existsSuperheat:
self.DT_sh_calc=self.Tout_r-self.Tdew_r
else:
self.DT_sh_calc=(self.hout_r-hsatV)/(Props('C','T',self.Tdew_r,'Q',1,self.Ref)*1000)
self.Tout_r=Props('T','P',self.psat_r+self.DP_r/1000.0,'Q',xout_r,self.Ref) #saturated temperature at outlet quality
self.hmean_r=self.w_2phase*self.h_r_2phase+self.w_superheat*self.h_r_superheat
self.UA_r=self.hmean_r*self.A_r_wetted
self.UA_a=self.Fins.h_a*self.Fins.A_a*self.Fins.eta_a
#Build a vector of temperatures at each point where there is a phase transition along the averaged circuit
if existsSuperheat:
#Insert the shoulder point
Tv=[self.Tin_r,self.Tdew_r,self.Tout_r]
x=[0,self.w_2phase,1]
else:
Tv=[self.Tin_r,xout_r*self.Tdew_r+(1-xout_r)*self.Tbubble_r]
x=[0,1]
#Determine each bend temperature by interpolation
#------------------------------------------------
#Number of bends (including inlet and outlet of coil)
Nbends=1+self.Lcircuit/self.Ltube
#x-position of each point
xv=np.linspace(0,1,Nbends)
self.Tbends=interp1d(x,Tv)(xv)
def _TwoPhase_Forward(self,w_2phase):
DWS=DWSVals() #DryWetSegment structure
# Store temporary values to be passed to DryWetSegment
DWS.Fins=self.Fins
DWS.A_a=self.Fins.A_a*w_2phase
DWS.cp_da=self.Fins.cp_da
DWS.eta_a=self.Fins.eta_a
DWS.h_a=self.Fins.h_a #Heat transfer coefficient, not enthalpy
DWS.mdot_da=self.mdot_da*w_2phase
DWS.pin_a=self.Fins.Air.p
DWS.Tdew_r=self.Tdew_r
DWS.Tbubble_r=self.Tbubble_r
DWS.Tin_a=self.Tin_a
DWS.RHin_a=self.Fins.Air.RH
DWS.Tin_r=self.Tsat_r
DWS.A_r=self.A_r_wetted*w_2phase
DWS.cp_r=1.0e15 #In the two-phase region the cp is infinite, use 1e15 as a big number;
DWS.pin_r=self.psat_r
DWS.mdot_r=self.mdot_r
DWS.IsTwoPhase=True
#Target heat transfer to go from inlet quality to saturated vapor
Q_target=self.mdot_r*(self.xout_2phase-self.xin_r)*self.h_fg
if Q_target<0:
raise ValueError('Q_target in Evaporator must be positive')
# Average Refrigerant heat transfer coefficient
DWS.h_r=ShahEvaporation_Average(self.xin_r,self.xout_2phase,self.Ref,self.G_r,self.ID,self.Tsat_r,Q_target/DWS.A_r,self.Tbubble_r,self.Tdew_r)
#Run the DryWetSegment to carry out the heat and mass transfer analysis
DryWetSegment(DWS)
self.Q_2phase=DWS.Q
self.Q_sensible_2phase=DWS.Q_sensible
self.h_r_2phase=DWS.h_r
self.fdry_2phase=DWS.f_dry
self.Tout_a_2phase=DWS.Tout_a
rho_average=TwoPhaseDensity(self.Ref,self.xin_r,self.xout_2phase,self.Tdew_r,self.Tbubble_r,slipModel='Zivi')
self.Charge_2phase = rho_average * w_2phase * self.V_r
#Frictional pressure drop component
DP_frict=LMPressureGradientAvg(self.xin_r,self.xout_2phase,self.Ref,self.G_r,self.ID,self.Tbubble_r,self.Tdew_r)*self.Lcircuit*w_2phase
#Accelerational pressure drop component
DP_accel=AccelPressureDrop(self.xin_r,self.xout_2phase,self.Ref,self.G_r,self.Tbubble_r,self.Tdew_r)
self.DP_r_2phase=DP_frict+DP_accel;
if self.Verbosity>7:
print w_2phase,DWS.Q,Q_target,self.xin_r,"w_2phase,DWS.Q,Q_target,self.xin_r"
return DWS.Q-Q_target
def _Superheat_Forward(self,w_superheat):
self.w_superheat=w_superheat
DWS=DWSVals() #DryWetSegment structure
# Store temporary values to be passed to DryWetSegment
DWS.A_a=self.Fins.A_a*w_superheat
DWS.cp_da=self.Fins.cp_da
DWS.eta_a=self.Fins.eta_a
DWS.h_a=self.Fins.h_a #Heat transfer coefficient
DWS.mdot_da=self.mdot_da*w_superheat
DWS.pin_a=self.Fins.Air.p
DWS.Fins=self.Fins
# Inputs on the air side to two phase region are inlet air again
DWS.Tin_a=self.Tin_a
DWS.RHin_a=self.Fins.Air.RH
DWS.Tin_r=self.Tdew_r
DWS.A_r=self.A_r_wetted*w_superheat
DWS.cp_r=Props('C','T',self.Tdew_r+2.5, 'P', self.psat_r, self.Ref)*1000#Use a guess value of 6K superheat to calculate cp
DWS.pin_r=self.psat_r
DWS.mdot_r=self.mdot_r
DWS.IsTwoPhase=False
#Use a guess value of 6K superheat to calculate the properties
self.f_r_superheat, self.h_r_superheat, self.Re_r_superheat=f_h_1phase_Tube(self.mdot_r / self.Ncircuits, self.ID,
self.Tdew_r+3, self.psat_r, self.Ref, "Single");
# Average Refrigerant heat transfer coefficient
DWS.h_r=self.h_r_superheat
#Run DryWetSegment
DryWetSegment(DWS)
rho_superheat=Props('D','T',(DWS.Tout_r+self.Tdew_r)/2.0, 'P', self.psat_r, self.Ref)
self.Charge_superheat = w_superheat * self.V_r * rho_superheat
#Pressure drop calculations for subcooled refrigerant
v_r=1/rho_superheat
#Pressure gradient using Darcy friction factor
dpdz_r=-self.f_r_superheat*v_r*self.G_r**2/(2*self.ID) #Pressure gradient
self.DP_r_superheat=dpdz_r*self.Lcircuit*self.w_superheat
#Set values
self.Q_superheat=DWS.Q
self.Q_sensible_superheat=DWS.Q_sensible
self.fdry_superheat=DWS.f_dry
self.Tout_a_superheat=DWS.Tout_a
self.Tout_r=DWS.Tout_r
if __name__=='__main__':
#This code runs if this file is run by itself, but otherwise doesn't run
TT=[]
Q=[]
ff=[]
QQ=[]
hh=[]
import numpy as np,pylab
for Tdew in np.linspace(270,299.7,101):
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
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) #update not necessary here, but left for illu
Evap.Calculate()
#print Evap.OutputList()
Q.append(Evap.Q)
QQ.append(Evap.Q_2phase)
TT.append(Tdew)
ff.append(Evap.w_2phase)
hh.append(Evap.h_r_2phase)
pylab.plot(TT,QQ,TT,Q)
pylab.show()
pylab.plot(TT,hh)
pylab.show()