from __future__ import division, print_function, absolute_import
from math import pi,log,exp
from .Correlations import f_h_1phase_Tube,ShahCondensation_Average,LMPressureGradientAvg,TwoPhaseDensity,AccelPressureDrop
from .FinCorrelations import WavyLouveredFins,FinInputs,IsFinsClass, HerringboneFins, PlainFins
from .ACHPTools import ValidateFields
from scipy.optimize import brentq
import CoolProp as CP
class FinVals():
def __init__(self):
pass
[docs]class CondenserClass():
def __init__(self,**kwargs):
#Load the parameters passed in
# using the dictionary
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
"""
return [
('Volumetric flow rate of humid air','m^3/s',self.Fins.Air.Vdot_ha),
('Inlet Dry bulb temp','K',self.Tin_a),
('Inlet Air pressure','Pa',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.OD),
('Tube ID','m',self.ID),
('Tube Long. Pitch','m',self.Fins.Tubes.Pl),
('Tube Transverse Pitch','m',self.Fins.Tubes.Pt),
('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),
('Fins Type','-',self.FinsType),
('Q Total','W',self.Q),
('Q Superheat','W',self.Q_superheat),
('Q Two-Phase','W',self.Q_2phase),
('Q Subcool','W',self.Q_subcool),
('Inlet Temp','K',self.Tin_r),
('Outlet Temp','K',self.Tout_r),
('Pressure Drop Total','Pa',self.DP_r),
('Pressure Drop Superheat','Pa',self.DP_r_superheat),
('Pressure Drop Two-Phase','Pa',self.DP_r_2phase),
('Pressure Drop Subcool','Pa',self.DP_r_subcool),
('Charge Total','kg',self.Charge),
('Charge Superheat','kg',self.Charge_superheat),
('Charge Two-Phase','kg',self.Charge_2phase),
('Charge Subcool','kg',self.Charge_subcool),
('Mean HTC Superheat','W/m^2-K',self.h_r_superheat),
('Mean HTC Two-phase','W/m^2-K',self.h_r_2phase),
('Mean HTC Subcool','W/m^2-K',self.h_r_subcool),
('Wetted Area Fraction Superheat','-',self.w_superheat),
('Wetted Area Fraction Two-phase','-',self.w_2phase),
('Wetted Area Fraction Subcool','-',self.w_subcool),
('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 of Dry Air','kg/s',self.Fins.mdot_da),
('Mass Flow rate of Humid Air','kg/s',self.Fins.mdot_ha),
('Pressure Drop Air-side','Pa',self.Fins.dP_a),
('Subcooling','K',self.DT_sc)
]
[docs] def Update(self,**kwargs):
#Update the parameters passed in
# using the dictionary
self.__dict__.update(kwargs)
[docs] def Calculate(self):
#Only validate the first time
if not hasattr(self,'IsValidated'):
self.Fins.Validate()
reqFields=[
('Ref',str,None,None),
('Fins',IsFinsClass,None,None),
('FinsType',str,None,None),
('mdot_r',float,0.00001,20),
('Tin_r',float,200,500),
('psat_r',float,0.01,20000000)
]
optFields=['Verbosity','Backend']
ValidateFields(self.__dict__,reqFields,optFields)
self.IsValidated=True
#AbstractState
if hasattr(self,'Backend'): #check if backend is given
AS = CP.AbstractState(self.Backend, self.Ref)
else: #otherwise, use the defualt backend
AS = CP.AbstractState('HEOS', self.Ref)
self.AS = AS
# 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
## Bubble and dew temperatures (same for fluids without glide)
AS.update(CP.PQ_INPUTS, self.psat_r, 0.0)
self.Tbubble=AS.T() #[K]
self.h_l = AS.hmass() #[J/kg]
self.cp_satL = AS.cpmass() #[J/kg-K]
AS.update(CP.PQ_INPUTS, self.psat_r, 1.0)
self.Tdew=AS.T() #[K]
self.h_v = AS.hmass() #[J/kg]
# 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
self.V_r = pi * self.ID**2 / 4.0 * self.Lcircuit * self.Ncircuits
self.A_r_wetted = pi * self.ID * self.Ncircuits * self.Lcircuit
self.G_r = self.mdot_r/(self.Ncircuits*pi*self.ID**2/4.0)
#define known parameters
AS.update(CP.PT_INPUTS, self.psat_r, self.Tin_r)
self.hin_r=AS.hmass() #[J/kg]
self.sin_r=AS.smass() #[J/kg-K]
#Definitely have a superheated portion
self._Superheat_Forward()
#Maybe have a full two-phase section
#First try to run with a full two-phase section from quality of 1 to quality of 0
self._TwoPhase_Forward()
#If we have already used too much of the HX (max possible sum of w is 1.0)
if self.w_2phase+self.w_superheat>1:
#There is no subcooled portion, solve for outlet quality
brentq(self._TwoPhase_Forward,0.0000001,0.9999999)
#Zero out all the subcooled parameters
self.Q_subcool=0.0
self.DP_r_subcool=0.0
self.Charge_subcool=0.0
self.w_subcool=0.0
self.h_r_subcool=0.0
self.existsSubcooled=False
else:
#By definition then we have a subcooled portion, solve for it
self.existsSubcooled=True
self._Subcool_Forward()
#Overall calculations
self.Q=self.Q_superheat+self.Q_2phase+self.Q_subcool
self.DP_r=self.DP_r_superheat+self.DP_r_2phase+self.DP_r_subcool
self.Charge=self.Charge_2phase+self.Charge_subcool+self.Charge_superheat
if self.existsSubcooled==True:
AS.update(CP.PT_INPUTS, self.psat_r, self.Tout_r)
self.hout_r=AS.hmass() #[J/kg]
self.sout_r=AS.smass() #[J/kg-K]
else:
self.Tout_r=self.xout_2phase*self.Tdew+(1-self.xout_2phase)*self.Tbubble
AS.update(CP.QT_INPUTS, 0.0, self.Tout_r)
h_l=AS.hmass() #[J/kg]
s_l=AS.smass() #[J/kg-K]
AS.update(CP.QT_INPUTS, 1.0, self.Tout_r)
h_v=AS.hmass() #[J/kg]
s_v=AS.smass() #[J/kg-K]
self.hout_r= h_l + self.xout_2phase * (h_v - h_l)
self.sout_r= s_l + self.xout_2phase * (s_v - s_l)
#Use the effective subcooling
self.DT_sc=self.DT_sc_2phase
#Calculate the mean outlet air temperature [K]
self.Tout_a=self.Tin_a-self.Q/(self.Fins.cp_da*self.Fins.mdot_da)
self.hmean_r=self.w_2phase*self.h_r_2phase+self.w_superheat*self.h_r_superheat+self.w_subcool*self.h_r_subcool
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
def _Superheat_Forward(self):
# **********************************************************************
# SUPERHEATED PART
# **********************************************************************
#AbstractState
AS = self.AS
#Dew temperature for constant pressure cooling to saturation
Tdew=self.Tdew
Tbubble=self.Tbubble
# Average fluid temps are used for the calculation of properties
# Average temp of refrigerant is average of sat. temp and outlet temp
# Secondary fluid is air over the fins
self.f_r_superheat, self.h_r_superheat, self.Re_r_superheat=f_h_1phase_Tube(self.mdot_r / self.Ncircuits, self.ID,
(Tdew+self.Tin_r)/2.0, self.psat_r, self.AS, "Single");
AS.update(CP.PT_INPUTS, self.psat_r, (Tdew+self.Tin_r)/2)
cp_r = AS.cpmass() #[J/kg-K]
rho_superheat= AS.rhomass() #[kg/m^3]
#Compute Fins Efficiency based on FinsType
if self.FinsType == 'WavyLouveredFins':
WavyLouveredFins(self.Fins)
elif self.FinsType == 'HerringboneFins':
HerringboneFins(self.Fins)
elif self.FinsType == 'PlainFins':
PlainFins(self.Fins)
self.mdot_da=self.Fins.mdot_da
# Cross-flow in the superheated region.
# Using effectiveness-Ntu relationships for cross flow with non-zero Cr.
UA_overall = 1 / (1 / (self.Fins.eta_a * self.Fins.h_a * self.Fins.A_a) + 1 / (self.h_r_superheat * self.A_r_wetted) )
epsilon_superheat=(Tdew-self.Tin_r)/(self.Tin_a-self.Tin_r)
Ntu=UA_overall/(self.mdot_da*self.Fins.cp_da)
if epsilon_superheat>1.0:
epsilon_superheat=1.0-1e-12
self.w_superheat=-log(1-epsilon_superheat)*self.mdot_r*cp_r/((1-exp(-Ntu))*self.mdot_da*self.Fins.cp_da)
# Positive Q is heat input to the refrigerant, negative Q is heat output from refrigerant.
# Heat is removed here from the refrigerant since it is being cooled
self.Q_superheat = self.mdot_r * cp_r * (Tdew-self.Tin_r)
#Pressure drop calculations for superheated 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
self.Charge_superheat = self.w_superheat * self.V_r * rho_superheat
#Latent heat needed for pseudo-quality calc
AS.update(CP.QT_INPUTS, 0.0, Tbubble)
h_l = AS.hmass() #[J/kg]
AS.update(CP.QT_INPUTS, 1.0, Tdew)
h_v = AS.hmass() #[J/kg]
h_fg = h_v - h_l #[J/kg]
self.xin_r=1.0+cp_r*(self.Tin_r-Tdew)/h_fg
def _TwoPhase_Forward(self,xout_r_2phase=0.0):
"""
xout_r_2phase: quality of refrigerant at end of two-phase portion
default value is 0.0 (full two phase region)
"""
## Bubble and dew temperatures (same for fluids without glide)
Tbubble=self.Tbubble
Tdew=self.Tdew
## Mean temperature for use in HT relationships
Tsat_r=(Tbubble+Tdew)/2
h_l = self.h_l #[J/kg]
h_v = self.h_v #[J/kg]
h_fg = h_v - h_l #[J/kg]
# This block calculates the average refrigerant heat transfer coefficient by
# integrating the local heat transfer coefficient between
# a quality of 1.0 and the outlet quality
self.h_r_2phase=ShahCondensation_Average(xout_r_2phase,1.0,self.AS,self.G_r,self.ID,self.psat_r,Tbubble,Tdew);
UA_overall = 1 / (1 / (self.Fins.eta_a * self.Fins.h_a * self.Fins.A_a) + 1 / (self.h_r_2phase * self.A_r_wetted));
self.epsilon_2phase=1-exp(-UA_overall/(self.mdot_da*self.Fins.cp_da));
self.w_2phase=-self.mdot_r*h_fg*(1.0-xout_r_2phase)/(self.mdot_da*self.Fins.cp_da*(self.Tin_a-Tsat_r)*self.epsilon_2phase);
#Positive Q is heat input to the refrigerant, negative Q is heat output from refrigerant.
#Heat is removed here from the refrigerant since it is condensing
self.Q_2phase = self.epsilon_2phase * self.Fins.cp_da* self.mdot_da * self.w_2phase * (self.Tin_a-Tsat_r);
self.xout_2phase=xout_r_2phase
# Frictional pressure drop component
DP_frict=LMPressureGradientAvg(self.xout_2phase,1.0,self.AS,self.G_r,self.ID,Tbubble,Tdew)*self.Lcircuit*self.w_2phase
#Accelerational pressure drop component
DP_accel=-AccelPressureDrop(self.xout_2phase,1.0,self.AS,self.G_r,Tbubble,Tdew)*self.Lcircuit*self.w_2phase
# Total pressure drop is the sum of accelerational and frictional components (neglecting gravitational effects)
self.DP_r_2phase=DP_frict+DP_accel
rho_average=TwoPhaseDensity(self.AS,self.xout_2phase,1.0,self.Tdew,self.Tbubble,slipModel='Zivi')
self.Charge_2phase = rho_average * self.w_2phase * self.V_r
if self.Verbosity>7:
print('2phase cond resid', self.w_2phase-(1-self.w_superheat))
print('h_r_2phase',self.h_r_2phase)
#Calculate an effective pseudo-subcooling based on the equality
# cp*DT_sc=-dx*h_fg
cp_satL = self.cp_satL #[J/kg-K]
self.DT_sc_2phase=-self.xout_2phase*h_fg/(cp_satL)
#If the quality is being solved for, the length of the two-phase and subcooled
# sections should add to the length of the HX. Return the residual
return self.w_2phase-(1-self.w_superheat)
def _Subcool_Forward(self):
self.w_subcool=1-self.w_2phase-self.w_superheat
if self.w_subcool<0:
raise ValueError('w_subcool in Condenser cannot be less than zero')
#AbstractState
AS = self.AS
## Bubble and dew temperatures (same for fluids without glide)
Tbubble=self.Tbubble
# Based on the the construction of the cycle model there is guaranteed to be a
# two-phase portion of the heat exchanger
A_a_subcool = self.Fins.A_a * self.w_subcool
mdot_da_subcool = self.mdot_da * self.w_subcool
A_r_subcool = self.A_r_wetted * self.w_subcool
# Friction factor and HTC in the refrigerant portions.
# Average fluid temps are used for the calculation of properties
# Average temp of refrigerant is average of sat. temp and outlet temp
# Secondary fluid is air over the fins
self.f_r_subcool, self.h_r_subcool, self.Re_r_subcool=f_h_1phase_Tube(
self.mdot_r / self.Ncircuits, self.ID, Tbubble-1.0, self.psat_r, self.AS,
"Single")
AS.update(CP.PT_INPUTS, self.psat_r, Tbubble-1)
cp_r = AS.cpmass() #[J/kg-K]
# Cross-flow in the subcooled region.
R_a=1. / (self.Fins.eta_a * self.Fins.h_a * self.Fins.A_a)
R_r=1. / (self.h_r_subcool * self.A_r_wetted)
UA_subcool = self.w_subcool / (R_a + R_r)
Cmin=min([self.mdot_da*self.Fins.cp_da*self.w_subcool,self.mdot_r*cp_r])
Cmax=max([self.mdot_da*self.Fins.cp_da*self.w_subcool,self.mdot_r*cp_r])
Cr=Cmin/Cmax
NTU=UA_subcool/Cmin
if(self.mdot_da*self.Fins.cp_da*self.w_subcool>self.mdot_r*cp_r):
#Minimum capacitance rate on refrigerant side
epsilon_subcool = 1. - exp(-1. / Cr * (1. - exp(-Cr * NTU)))
else:
#Minimum capacitance rate on air side
epsilon_subcool = 1 / Cr * (1 - exp(-Cr * (1 - exp(-NTU))))
# Positive Q is heat input to the refrigerant, negative Q is heat output from refrigerant.
# Heat is removed here from the refrigerant since it is condensing
self.Q_subcool=-epsilon_subcool*Cmin*(Tbubble-self.Tin_a)
self.DT_sc=-self.Q_subcool/(self.mdot_r*cp_r)
self.Tout_r=Tbubble-self.DT_sc
AS.update(CP.PT_INPUTS, self.psat_r, (Tbubble + self.Tout_r) / 2)
rho_subcool=AS.rhomass() #[kg/m^3]
self.Charge_subcool = self.w_subcool * self.V_r * rho_subcool
#Pressure drop calculations for subcooled refrigerant
v_r=1/rho_subcool
#Pressure gradient using Darcy friction factor
dpdz_r=-self.f_r_subcool*v_r*self.G_r**2/(2*self.ID) #Pressure gradient
self.DP_r_subcool=dpdz_r*self.Lcircuit*self.w_subcool
def SampleCondenser(T=41.37):
Fins=FinInputs()
Fins.Tubes.NTubes_per_bank=41 #number of tubes per bank or row
Fins.Tubes.Nbank=1 #number of banks or rows
Fins.Tubes.Ncircuits=5 #number of circuits
Fins.Tubes.Ltube=2.286 #one tube length
Fins.Tubes.OD=0.007
Fins.Tubes.ID=0.0063904
Fins.Tubes.Pl=0.0191 #distance between center of tubes in flow direction
Fins.Tubes.Pt=0.0222 #distance between center of tubes orthogonal to flow direction
Fins.Fins.FPI=25 #Number of fins per inch
Fins.Fins.Pd=0.001 #2* amplitude of wavy fin
Fins.Fins.xf=0.001 #1/2 period of fin
Fins.Fins.t=0.00011 #Thickness of fin material
Fins.Fins.k_fin=237 #Thermal conductivity of fin material
Fins.Air.Vdot_ha=1.7934 #rated volumetric flowrate
Fins.Air.Tmean=308.15
Fins.Air.Tdb=308.15 #Dry Bulb Temperature
Fins.Air.p=101325 #Air pressure in Pa
Fins.Air.RH=0.51 #Relative Humidity
Fins.Air.RHmean=0.51
Fins.Air.FanPower=160
params={
'Ref': 'R410A',
'mdot_r': 0.0708,
'Tin_r': T+20+273.15,
'psat_r': 2500076.19, #PropsSI('P','T',T+273.15,'Q',1.0,'R410A')
'Fins': Fins,
'FinsType': 'HerringboneFins', #Choose fin Type: 'WavyLouveredFins' or 'HerringboneFins'or 'PlainFins'
'Verbosity':0,
'Backend':'HEOS' #choose between: 'HEOS','TTSE&HEOS','BICUBIC&HEOS','REFPROP','SRK','PR'
}
Cond=CondenserClass(**params)
Cond.Calculate()
return Cond
if __name__=='__main__':
#This runs if you run this file directly
Cond=SampleCondenser(43.3)
print(Cond.OutputList())
print('Heat transfer rate in condenser is', Cond.Q,'W')
print('Heat transfer rate in condenser (superheat section) is',Cond.Q_superheat,'W')
print('Heat transfer rate in condenser (twophase section) is',Cond.Q_2phase,'W')
print('Heat transfer rate in condenser (subcooled section) is',Cond.Q_subcool,'W')
print('Fraction of circuit length in superheated section is',Cond.w_superheat)
print('Fraction of circuit length in twophase section is',Cond.w_2phase)
print('Fraction of circuit length in subcooled section is',Cond.w_subcool)