def __init__(self, T_evap=1.5, T_cond=39.9, x1=0.567, x2=0.624, Eff_SHX=0.64, m_pump=0.05): """Args ---- T_evap : float Evaporator saturation temperature (deg C) T_cond : float Condenser saturation temperature (deg C) x1 : float Pump side mass fraction of LiBr in stream (low) [kg/kg] x2 : float Return side mass fraction of LiBr in stream (high/concentrate) Eff_SHX : float Effectiveness of the solution heat exchanger (K/K), 0 to 1 m_pump : float Mass flow rate through the solution pump (kg/s) """ self.T_evap = T_evap self.T_cond = T_cond self.x1 = x1 self.x2 = x2 self.m_pump = m_pump self.Eff_SHX = Eff_SHX self.dx = x1 - x2 self.P_evap = CP.PropsSI('P','T',C2K(T_evap),'Q',1,water) self.P_cond = CP.PropsSI('P','T',C2K(T_cond),'Q',1,water) self.T_gen_inlet = 0 self.T_gen_outlet = 0 self.T_abs_inlet_max = 0 self.T_abs_outlet_max = 0 self.h_gen_inlet = 0 self.h_gen_outlet = 0 self.h_abs_inlet = 0 self.h_abs_outlet = 0 self.m_concentrate = 0 self.m_refrig = 0 self.T_SHX_concentrate_outlet = 0 self.Q_SHX = 0 self.T_abs_pre = np.nan self.h_abs_pre = np.nan self.Q_abs_pre_cool = 0 self.P_abs_pre = np.nan self.Q_abs_main = 0 self.Q_abs_total = 0 self.T_gen_pre = np.nan self.Q_gen_pre_heat = 0 self.Q_gen_main = 0 self.Q_gen_total = 0 self.Q_condenser_reject = 0 self.Q_evap_heat = 0 self.COP = 0 self.W_pump = 0 self.f = np.inf
def _q_helper(self,T): x_local = libr_props.massFraction(C2K(T),self.P * 1e-5) # Could parametrize this by x, but libr_props.temperature also has an # implicit solve. Only P(T,x) is explicit. pwater.update(CP.PT_INPUTS, self.P, C2K(T)) h_vapor_local = pwater.hmass() - h_w_ref h_solution_local = libr_props.massSpecificEnthalpy(C2K(T), x_local) # Mass balance on LiBr m_solution_local = self.m_in * self.x_in / x_local hlv1 = h_vapor_local - h_solution_local q1 = self.m_total * h_vapor_local - m_solution_local * hlv1 return q1
def _q(self,T): # First, determine the mass fraction here. if T > self.T_sat: raise ValueError("This function is for subcooled LiBr...") else: x_local = libr_props.massFraction(C2K(T),self.P*1e-5) return self._qx(x_local)
def makeRejectStream(self, T_in, dT, Q): # Flow rate for reject streams is specified by inlet and outlet temperatures... cp = CP.PropsSI('C', 'T', C2K(T_in), 'Q', 0, 'water') #print "cp is ",cp dh = cp * dT m = Q / dh return HRHX_integral_model.streamExample1(T_in, m, cp)
def makeColdStream(self, Q): # Flow rate for evaporator is specified by inlet and outlet temperature... T_in, T_out = 12, 7 cp = CP.PropsSI('C', 'T', C2K(T_in), 'Q', 0, 'water') #print "cp is ",cp dh = cp * (T_out - T_in) m = -Q / dh return HRHX_integral_model.streamExample1(T_in, m, cp)
def updateSHX_hot_side(self): DeltaT_max = self.T_gen_outlet - self.T_abs_outlet_max DeltaT_SHX_concentrate = self.Eff_SHX * DeltaT_max self.T_SHX_concentrate_outlet = self.T_gen_outlet \ - DeltaT_SHX_concentrate self.h_SHX_concentrate_outlet = libr_props.massSpecificEnthalpy( C2K(self.T_SHX_concentrate_outlet), self.x2) self.Q_SHX = self.m_concentrate \ * (self.h_gen_outlet - self.h_SHX_concentrate_outlet)
def getHeatCurve(self): """Returns (Heat,T), arrays showing progress of the process. Note: absorber heat input is negative. Learn this from (my revision to) example 3.3. """ Q, result = 0, [] # Starting coordinates result.append((0,self.T_abs_pre)) # Heat input to reach a saturated state. Q += self.m_concentrate * (self.h_abs_inlet - self.h_abs_pre) result.append((Q,self.T_abs_inlet_max)) # Heat input to reach outlet. Q += self.m_pump * self.h_abs_outlet \ - self.m_concentrate * self.h_abs_inlet \ - self.m_refrig * self.h_abs_vapor_inlet result.append((Q,self.T_abs_outlet_max)) # Pump -- no heat, just work # Pump outlet to generator through SHX Q += self.m_pump * self.h_gen_pre - self.m_pump * self.h_abs_outlet result.append((Q,self.T_gen_pre)) # Generator preheat Q += self.m_concentrate * self.h_gen_inlet \ - self.m_concentrate * self.h_gen_pre result.append((Q,self.T_gen_inlet)) # Generator proper Q += self.m_concentrate * self.h_gen_outlet \ + self.m_refrig * self.h_gen_vapor_outlet \ - self.m_pump * self.h_gen_inlet result.append((Q,self.T_gen_outlet)) # SHX, concentrate side Q += self.m_concentrate * self.h_SHX_concentrate_outlet \ - self.m_concentrate * self.h_gen_outlet result.append((Q,self.T_SHX_concentrate_outlet)) # Solution expander result.append((Q,self.T_abs_pre)) # Condenser cool to saturated result.append((Q,self.T_gen_inlet)) pwater.update(CP.QT_INPUTS,0,C2K(self.T_cond)) h_condenser_sat = pwater.hmass() - h_w_ref Q += self.m_refrig * h_condenser_sat \ - self.m_refrig * self.h_gen_vapor_outlet result.append((Q,self.T_cond)) # Real condense Q += self.m_refrig * (self.h_condenser_outlet - h_condenser_sat) result.append((Q,self.T_cond)) # What if condenser subcools? Later. # Expander pwater.update(CP.HmassP_INPUTS,self.h_condenser_outlet + h_w_ref, self.P_evap) T_into_evap = pwater.T() result.append((Q,T_into_evap)) # Evaporator Q += self.m_refrig * (self.h_evap_outlet - self.h_evap_inlet) result.append((Q,self.T_evap)) return zip(*result)
def _q(self,T): """Provide process heat canonical curve for generator in various forms. Assumes that * inlet solution state is obtained from self, * generated vapor is flowing in reverse direction and * it is everywhere in local equilibrium with solution. Args ---- T : Temperature (deg C) The local temperature Returns ------- q : Local progress index Measured as cumulative heat flux (W). Q : Total heat flux (W) The total amount of heat transferred into the generator. """ hlv0 = self.h_vapor_out - self.h_sat q0 = self.m_total * self.h_vapor_out - self.m_in * hlv0 if T < self.T_in: raise "Generator outlet must be greater than pre-inlet temperature!" elif T < self.T_sat: # The state is either saturated or subcooled. # Use linear interpolation. q = self.m_in * self.cp_in * (T - self.T_in) else: x_local = libr_props.massFraction(C2K(T),self.P * 1e-5) pwater.update(CP.PT_INPUTS, self.P, C2K(T)) h_vapor_local = pwater.hmass() - h_w_ref h_solution_local = libr_props.massSpecificEnthalpy(C2K(T), x_local) # Mass balance on LiBr m_solution_local = self.m_in * self.x_in / x_local hlv1 = h_vapor_local - h_solution_local q1 = self.m_total * h_vapor_local - m_solution_local * hlv1 q = (q1 - q0) + self.Q_preheat # TODO # If q > Q (iff T > T_solution_outlet) then result is invalid. return q
def update(self, P, m_in, T_in, x_in, x_out): self.P = P self.m_in = m_in self.T_in = T_in self.x_in = x_in self.x_out = x_out # Find inlet enthalpy. # Find saturation point at inlet concentration. # Find ... self.T_sat = K2C(libr_props.temperature(self.P * 1e-5, self.x_in)) self.T_out = K2C(libr_props.temperature(self.P * 1e-5, self.x_out)) self.h_sat = libr_props.massSpecificEnthalpy(C2K(self.T_sat), self.x_in) self.h_out = libr_props.massSpecificEnthalpy(C2K(self.T_out),self.x_out) self.cp_in = libr_props.massSpecificHeat(C2K(self.T_in),self.x_in) # If h_in is an input: if False: preheat = (self.h_sat - self.h_in)/self.cp_in self.T_in = self.T_sat - preheat else: preheat = self.T_sat - self.T_in self.h_in = self.h_sat - preheat * self.cp_in pwater.update(CP.PT_INPUTS, self.P, C2K(self.T_sat)) self.h_vapor_out = pwater.hmass() - h_w_ref # Mass balance on LiBr self.m_out = self.m_in * self.x_in / self.x_out # Mass balance on Water self.m_vapor_out = self.m_in - self.m_out self.m_total = self.m_out self.Q_preheat = self.m_in * (self.h_sat - self.h_in) self.Q_desorb = self.m_out * self.h_out \ + self.m_vapor_out * self.h_vapor_out \ - self.m_in * self.h_sat # Determine a reasonable limit for extending the domain. self.Tmax = K2C(libr_props.temperature(self.P*1e-5,libr_props.xmax))
def _qx(self,x_local): T = K2C(libr_props.temperature(self.P*1e-5,x_local)) dx = self.x_in - x_local # TODO h_local = libr_props.massSpecificEnthalpy(C2K(T),x_local) # And calculate m_vapor = self.m_in * dx / x_local m_out = self.m_in + m_vapor # Heat is inbound. result = -self.m_in * self.h_in - m_vapor * self.h_vapor_inlet \ + m_out * h_local return T,result
def Hsat(x, T): """Applies correction based on concentration, then returns saturation enthalpy from CoolProp's LiBr-H2O solution. You should check if the state is crystalline; if so, the results are not accurate. Args ---- x (float) Concentration of LiBr in liquid, from 0 to 0.75 [kg/kg]. T (float) Equilibrium temperature, from 0 to 227 [C]. """ return CP.PropsSI('H', 'T', C2K(T), 'Q', 0, librname(x))
def _q(self,T): from CoolProp.CoolProp import PropsSI if T < self.Tmin: return 0 elif T > self.Tmax: return self._q(self.Tmax) else: try: # CoolProp raises an exception if this is the saturation temp. #h_out = CP.PropsSI('H','P',self.P,'T',C2K(T),self.fluid) h_out = PropsSI('H','P',self.P,'T',C2K(T),self.fluid) except: h_out = self.h_sat return self.mdot * (h_out - self.h_in)
def main(): from hw2_1 import CelsiusToKelvin as C2K spec = AdsorptionChillerSpec() ctrl = AdsorptionChillerControl(t_evap=C2K(12), t_exhaust=C2K(100)) chiller = AdsorptionChiller(spec, ctrl) t_ads = linspace(0, 240, endpoint=True) t_des = linspace(0, 240, endpoint=True) T_d0 = 300 myt = 0 fig1, (ax1, ax2) = plt.subplots(2, 1) ax1.cla() ax2.cla() print(spec) print(ctrl) headers = 'Delta_T Delta_t q_low q_high'.split() units = 'K s kg/kg kg/kg'.split() fmt1 = "{:>12} " * 4 fmt2 = "{:>12.5} " * 4 print(fmt1.format(*headers)) print(fmt1.format(*units)) print(fmt1.format(*['----------'] * 4)) for k in range(5): cycle = chiller.loopOnce(T_d0, t_des, t_ads, ax1, ax2, [fig1], myt) dT, dt, q_low, q_high = cycle print(fmt2.format(*cycle)) myt += dt T_d0 += dT print(fmt1.format(*['----------'] * 4)) performance = chiller.afterSolve(q_low, q_high, dt) import tabulate headers = 'Q_ref Q_in COP m_dot_ref'.split() units = 'kW kW kW/kW kg/s'.split() print(tabulate.tabulate(zip(headers, units, performance))) plt.show() return chiller, cycle, performance
def main(): T,Qu = C2K(50), 1.0 g_water = PropsSI("G","T",T,"Q",Qu,"water") # mass-specific gibbs energy # TODO: identify bug to report to CoolProp and fix it. # Maybe just need to expose # double CoolProp::AbstractState::gibbsmolar(void) # via # src/wrappers/Python/CoolProp/AbstractState.pxd # eg # cpdef double gibbsmolar(self) except * # Just to check, we could use this different method, but it has the same problem. #water = AbstractState("HEOS","Water") #water.update(QT_INPUTS, Qu, T) #g_water = water.gibbsmolar() / molarmass mu_1 = [] g_liquid = [] xvals = [] for x in linspace(0.01,0.99): g = libr_props.massSpecificGibbs(T,x) #P = 0 try: P = libr_props.pressure(T, x) except: print("Crystallized!") break xvals.append(x) g_liquid.append(g) mu = (1. / x) * (g - (1. - x) * g_water) mu_1.append( mu ) print("T,x = {}, {} -> P = {} bar, g = {} J/kg, mu = {}".format(T,x,P,g,mu)) plt.close('all') plt.xlabel("LiBr mass fraction in liquid phase") plt.ylabel("Potential function in liquid phase") plt.xlim(0,1) plt.plot(xvals, mu_1, label="mu_LiBr") plt.plot(xvals, g_liquid, label="g_liquid") plt.legend(loc='best') plt.title("g_water_vapor = {:g} J/kg".format(g_water)) plt.savefig('../img/{}.figure{}.png'.format(me2,plt.gcf().number))
def updateGenerator(self,Q_gen): genStream = self.getGeneratorStream() self.h_gen_inlet = genStream.h_sat self.T_gen_inlet = genStream.T_sat if Q_gen < genStream.Q_preheat: self.T_gen_outlet = genStream.T(Q_gen) self.x2 = self.x1 # error? else: self.T_gen_outlet = genStream.T(Q_gen) self.x2 = libr_props.massFraction(C2K(self.T_gen_outlet), self.P_cond) genStream.update(self.P_cond, self.m_pump, self.T_gen_pre, self.x1, self.x2) self.h_gen_outlet = genStream.h_out self.h_gen_vapor_outlet = genStream.h_vapor_out self.dx = self.x1 - self.x2 # Mass balance on LiBr self.m_concentrate = self.m_pump * self.x1 / self.x2 # Mass balance on Water self.m_refrig = self.m_pump - self.m_concentrate self.f = self.m_pump / self.m_refrig
def hTx(T,x): return CP.PropsSI('H','T',C2K(T),'Q',0,libr_props2.librname(x))
amm = lambda(x): 'REFPROP::water[{}]&ammonia[{}]'.format(1-x,x) # Units in this file: # temperature [C] # enthalpy [J/kg] # pressure [Pa] # mass fraction [kg/kg total] # effectiveness [K/K] # The LiBr enthalpy is zero at 293.15 K, 1 atm, per # http://www.coolprop.org/fluid_properties/Incompressibles.html#general-introduction # We need to evaluate water enthalpy relative to that, but it is not built-in. # http://www.coolprop.org/coolprop/HighLevelAPI.html#reference-states T_ref = 20 P_ref = 101325 h_w_ref = CP.PropsSI('H','T',C2K(T_ref),'P',P_ref,water) # Specify evaporator outlet and condenser outlet temperatures T_evap = 1.5 T_cond = 39.9 P_evap = CP.PropsSI('P','T',C2K(T_evap),'Q',1,water) P_cond = CP.PropsSI('P','T',C2K(T_cond),'Q',1,water) x2 = 0.624 dx = 0.057 x1 = x2 - dx T_gen_inlet = libr_props2.Tsat(x1, P_cond, 80) T_gen_outlet = libr_props2.Tsat(x2, P_cond, T_gen_inlet) T_abs_inlet_max = libr_props2.Tsat(x2, P_evap, T_gen_outlet)
def Tsat(x, P, T_guess=25): # CP.PropsSI('T','P',P_evap,'Q',0,libr(x1)) # unsupported inputs P_err = lambda T: CP.PropsSI('P', 'T', T, 'Q', 0, librname(x)) - P f = fsolve(P_err, C2K(T_guess)) return K2C(f[0])
def generatorHeatCurveQ(self,T,x_out): """Provide process heat canonical curve for generator in various forms. Assumes that * inlet solution state is obtained from self, * generated vapor is flowing in reverse direction and * it is everywhere in local equilibrium with solution. Args ---- T : Temperature (deg C) The local temperature x_out : Mass fraction (kg/kg) The outlet solution LiBr mass fraction Returns ------- q : Local progress index Measured as cumulative heat flux (W). Q : Total heat flux (W) The total amount of heat transferred into the generator. """ # We may need m_concentrate. It depends on Q -- solve from inlet. h_solution_inlet = self.h_gen_inlet h_vapor_outlet = self.h_gen_vapor_outlet T_solution_outlet = K2C(libr_props.temperature(self.P_cond * 1e-5, x_out)) h_solution_outlet = libr_props.massSpecificEnthalpy( C2K(T_solution_outlet), x_out) # Mass balance on LiBr m_solution_outlet = self.m_pump * self.x1 / x_out # Mass balance on Water m_vapor_outlet = self.m_pump - m_solution_outlet m_total = m_solution_outlet hlv0 = h_vapor_outlet - h_solution_inlet q0 = m_total * h_vapor_outlet - self.m_pump * hlv0 Q = m_solution_outlet * h_solution_outlet \ + m_vapor_outlet * h_vapor_outlet \ - self.m_pump * h_solution_inlet q = 0 T0,T1,T2=self.genpoints[0][1],self.genpoints[1][1],self.genpoints[2][1] Q0,Q1,Q2=self.genpoints[0][0],self.genpoints[1][0],self.genpoints[2][0] if T < T0: raise "Generator outlet must be greater than pre-inlet temperature!" elif T < T1: # The state is either saturated or subcooled. # Use linear interpolation. q = (T - T0) / (T1 - T0) * (Q1 - Q0) else: x_local = libr_props.massFraction(C2K(T),self.P_cond * 1e-5) pwater.update(CP.PT_INPUTS, self.P_cond, C2K(T)) h_vapor_local = pwater.hmass() - h_w_ref h_solution_local = libr_props.massSpecificEnthalpy(C2K(T), x_local) # Mass balance on LiBr m_solution_local = self.m_pump * self.x1 / x_local hlv1 = h_vapor_local - h_solution_local q1 = m_total * h_vapor_local - m_solution_local * hlv1 q = (q1 - q0) + (Q1 - Q0) # TODO # If q > Q (iff T > T_solution_outlet) then result is invalid. return q, Q
def Tsat2(x, H, T_guess=25): # CP.PropsSI('T','P',P_evap,'Q',0,libr(x1)) # unsupported inputs H_err = lambda T: CP.PropsSI('H', 'T', T, 'Q', 0, librname(x)) - H f = fsolve(H_err, C2K(T_guess)) return f[0]
def P_err(x): return CP.PropsSI('P', 'T', C2K(T), 'Q', 0, librname(x)) - P
def setT_cond(self,T_cond): self.T_cond = T_cond pwater.update(CP.QT_INPUTS, 1, C2K(T_cond)) self.P_cond = pwater.p()
def iterate1(self): """Update the internal parameters.""" self.T_gen_inlet = K2C(libr_props.temperature(self.P_cond*1e-5, self.x1)) self.T_gen_outlet = K2C(libr_props.temperature(self.P_cond * 1e-5, self.x2)) self.T_abs_inlet_max = K2C(libr_props.temperature(self.P_evap * 1e-5, self.x2)) self.T_abs_outlet_max = K2C(libr_props.temperature(self.P_evap * 1e-5, self.x1)) self.h_gen_inlet = libr_props.massSpecificEnthalpy( C2K(self.T_gen_inlet), self.x1) self.h_gen_outlet = libr_props.massSpecificEnthalpy( C2K(self.T_gen_outlet), self.x2) self.h_abs_inlet = libr_props.massSpecificEnthalpy( C2K(self.T_abs_inlet_max), self.x2) self.h_abs_outlet = libr_props.massSpecificEnthalpy( C2K(self.T_abs_outlet_max), self.x1) # Mass balance on LiBr self.m_concentrate = self.m_pump * self.x1 / self.x2 # Mass balance on Water self.m_refrig = self.m_pump - self.m_concentrate self.f = self.m_pump / self.m_refrig # Compute SHX outlets, assuming concentrate limits heat flow (C_min) # Neglect pump work for the present. DeltaT_max = self.T_gen_outlet - self.T_abs_outlet_max DeltaT_SHX_concentrate = self.Eff_SHX * DeltaT_max self.T_SHX_concentrate_outlet = self.T_gen_outlet \ - DeltaT_SHX_concentrate self.h_SHX_concentrate_outlet = libr_props.massSpecificEnthalpy( C2K(self.T_SHX_concentrate_outlet), self.x2) self.Q_SHX = self.m_concentrate \ * (self.h_gen_outlet - self.h_SHX_concentrate_outlet) # Expansion valve self.h_abs_pre = self.h_SHX_concentrate_outlet if self.h_abs_pre > self.h_abs_inlet: # Pre-cooling is required to reach saturation temperature self.Q_abs_pre_cool = self.m_concentrate \ * (self.h_abs_pre - self.h_abs_inlet) q,t,xl = libr_props.twoPhaseProps(self.h_abs_pre, self.P_evap*1e-5, self.x2) self.T_abs_pre = K2C(t) self.x_abs_pre = xl # ignore vapor quality, q # Minimum vapor pressure for absorption to occur self.P_abs_pre = np.inf else: self.Q_abs_pre_cool = 0 #self.T_abs_pre = K2C(CP.PropsSI('T', # 'H', self.h_abs_pre, # 'P', self.P_evap, # librname(self.x2))) self.T_abs_pre = np.nan # Minimum vapor pressure for absorption to occur # self.P_abs_pre = CP.PropsSI('P', # 'T', C2K(self.T_abs_pre), # 'Q', 0, # librname(self.x2)) self.P_abs_pre = np.nan # Heat rejection in absorber: energy balance pwater.update(CP.PQ_INPUTS, self.P_evap, 1) self.h_abs_vapor_inlet = pwater.hmass() - h_w_ref self.Q_abs_main = self.m_refrig * self.h_abs_vapor_inlet \ + self.m_concentrate * self.h_abs_inlet \ - self.m_pump * self.h_abs_outlet self.Q_abs_total = self.Q_abs_main + self.Q_abs_pre_cool # Energy balance in SHX, pump side D_in = CP.PropsSI('D', 'T',C2K(self.T_abs_outlet_max), 'Q',0, librname(self.x1)) DeltaH_pump = (self.P_cond - self.P_evap) / D_in self.W_pump = self.m_pump * DeltaH_pump self.h_pump_outlet = self.h_abs_outlet + DeltaH_pump DeltaH_SHX_pumpside = self.Q_SHX / self.m_pump self.h_gen_pre = self.h_pump_outlet + DeltaH_SHX_pumpside if self.h_gen_pre > self.h_gen_inlet: # Flash steam self.T_gen_pre = np.nan else: # The state is either saturated or subcooled. # We need to calculate the temperature from specific heat. cp = libr_props.massSpecificHeat(C2K(self.T_gen_inlet),self.x1) deltaHsub = self.h_gen_inlet - self.h_gen_pre deltaT = deltaHsub / cp self.T_gen_pre = self.T_gen_inlet - deltaT self.Q_gen_pre_heat = self.m_pump * (self.h_gen_inlet - self.h_gen_pre) # Heat input to generator: energy balance pwater.update(CP.PT_INPUTS, self.P_cond, C2K(self.T_gen_inlet)) self.h_gen_vapor_outlet = pwater.hmass() - h_w_ref self.vapor_superheat = self.T_gen_inlet - self.T_cond self.Q_gen_main = self.m_refrig * self.h_gen_vapor_outlet \ + self.m_concentrate * self.h_gen_outlet \ - self.m_pump * self.h_gen_inlet self.Q_gen_total = self.Q_gen_main + self.Q_gen_pre_heat # Condenser pwater.update(CP.PQ_INPUTS, self.P_cond, 0) self.h_condenser_outlet = pwater.hmass() - h_w_ref self.Q_condenser_reject = self.m_refrig * (self.h_gen_vapor_outlet - self.h_condenser_outlet) # Expansion valve self.h_evap_inlet = self.h_condenser_outlet # Evaporator self.h_evap_outlet = self.h_abs_vapor_inlet self.Q_evap_heat = self.m_refrig * (self.h_evap_outlet - self.h_evap_inlet) self.COP = self.Q_evap_heat / self.Q_gen_total
def __init__(self, T_evap=1.5, T_cond=39.9, x1=0.567, x2=0.624, Eff_SHX=0.64, m_pump=0.05): """Args ---- T_evap : float Evaporator saturation temperature (deg C) T_cond : float Condenser saturation temperature (deg C) x1 : float Pump side mass fraction of LiBr in stream (low) [kg/kg] x2 : float Return side mass fraction of LiBr in stream (high/concentrate) Eff_SHX : float Effectiveness of the solution heat exchanger (K/K), 0 to 1 m_pump : float Mass flow rate through the solution pump (kg/s) """ self.T_evap = T_evap self.T_cond = T_cond self.x1 = x1 self.x2 = x2 self.m_pump = m_pump self.Eff_SHX = Eff_SHX self.dx = x1 - x2 pwater.update(CP.QT_INPUTS, 1, C2K(T_evap)) self.P_evap = pwater.p() pwater.update(CP.QT_INPUTS, 1, C2K(T_cond)) self.P_cond = pwater.p() self.stateLabels = """abs_outlet pump_outlet gen_inlet gen_sat_liquid gen_outlet SHX_conc_outlet abs_inlet abs_sat_liquid gen_vapor_outlet cond_sat_vapor cond_outlet evap_inlet evap_sat_liquid evap_sat_vapor evap_outlet""".split('\n') #self.states=dict((k, nullPP('LiBrH2O')) for k in self.stateLabels) self.stateTable,self.states=makePointTable(self.stateLabels) self.T_gen_inlet = 0 self.T_gen_outlet = 0 self.T_abs_inlet_max = 0 self.T_abs_outlet_max = 0 self.h_gen_inlet = 0 self.h_gen_outlet = 0 self.h_abs_inlet = 0 self.h_abs_outlet = 0 self.m_concentrate = 0 self.m_refrig = 0 self.T_SHX_concentrate_outlet = 0 self.Q_SHX = 0 self.T_abs_pre = np.nan self.h_abs_pre = np.nan self.Q_abs_pre_cool = 0 self.P_abs_pre = np.nan self.Q_abs_main = 0 self.Q_abs_total = 0 self.T_gen_pre = np.nan self.Q_gen_pre_heat = 0 self.Q_gen_main = 0 self.Q_gen_total = 0 self.Q_condenser_reject = 0 self.Q_evap_heat = 0 self.COP = 0 self.W_pump = 0 self.f = np.inf self.x_abs_pre = self.x2
def setT_evap(self,T_evap): self.T_evap = T_evap pwater.update(CP.QT_INPUTS, 1, C2K(T_evap)) self.P_evap = pwater.p()
# -*- coding: utf-8 -*- """ Created on Thu Mar 05 17:26:23 2015 @author: nfette """ from __future__ import print_function import ammonia_props from hw2_1 import CelsiusToKelvin as C2K if __name__ == "__main__": myprops = ammonia_props.AmmoniaProps() f1 = myprops.props('TPx') T, P, x = C2K(20.), 10., 0.5 # K, bar, dim state = f1(T, P, x) print(state) dhdT = f1.massSpecificHeat(T=T, P=P, x=x) dhdT_expected = 4.604999985 print("dh/dT = {}, expected {} kJ/kg-K".format(dhdT, dhdT_expected))
# -*- coding: utf-8 -*- """ Created on Wed Feb 18 14:42:55 2015 @author: nfette """ from __future__ import print_function import ammonia_props from hw2_1 import CelsiusToKelvin as C2K if __name__ == "__main__": print("(a) Mixture properties from TPx:") myprops = ammonia_props.AmmoniaProps() f1 = myprops.props('TPx') T, P, x = C2K(50.), 10., 0.0 # K, bar, dim state = f1(T, P, x) print(state) print(f1.getOutputUnits()) print("(b) ... in molar units:") Meff = state.molarMass() hbar = state.h * Meff print("Meff = {} kg/kmol".format(Meff)) print("hbar = {} kJ/kmol".format(hbar)) print("(c) Partial component enthalpies") dhdx = f1.dhdxetc(T=T, P=P, x=x) print("{} kJ/kg".format(dhdx)) print("(d) Enthalpy of mixing") x = state.x
def __init__(self,P,m_in,h_in,x_in,h_vapor_inlet,debug=False): self.P=P self.m_in=m_in self.h_in=h_in self.x_in=x_in self.h_vapor_inlet = h_vapor_inlet self.T_sat = K2C(libr_props.temperature(self.P * 1e-5, self.x_in)) self.h_sat = libr_props.massSpecificEnthalpy(C2K(self.T_sat),self.x_in) if self.h_in > self.h_sat: q,t,xl = libr_props.twoPhaseProps(self.h_in,self.P*1e-5,self.x_in) # Pre-cooling is required to reach saturation temperature self.Q_pre_cool = self.m_in * (self.h_sat - self.h_in) self.T_in = K2C(t) prepoints_x = np.linspace(xl,self.x_in,20,endpoint=False) prepoints_T = np.zeros_like(prepoints_x) prepoints_q = np.zeros_like(prepoints_x) for i,x in enumerate(prepoints_x): #q,t,xl = libr_props.twoPhaseProps(h,self.P*1e-5,self.x_in) t = libr_props.temperature(self.P * 1e-5, x) h = libr_props.massSpecificEnthalpy(t,x) prepoints_T[i] = K2C(t) prepoints_q[i] = self.m_in * (h - self.h_in) prepoints_x[i] = x else: self.Q_pre_cool = 0 self.T_in = K2C(libr_props.temperature(self.P * 1e-5, self.x_in)) prepoints_T = [] prepoints_q = [] prepoints_x = [] # Set up bounds and points for interpolation. # Absorber limit is liquid water. pwater.update(CP.PQ_INPUTS,P,0) self.Tmin = pwater.T() x_points = np.linspace(x_in,0.1,100) T_points = np.zeros_like(x_points) q_points = np.zeros_like(x_points) #q_func = np.vectorize(self._q) #q_points = q_func(T_points) for i,x in enumerate(x_points): T_points[i],q_points[i] = self._qx(x) x_points = np.concatenate([prepoints_x,x_points]) T_points = np.concatenate([prepoints_T,T_points]) q_points = np.concatenate([prepoints_q,q_points]) # Forward function T_points1 = np.resize(T_points,len(T_points)+1) q_points1 = np.resize(q_points,len(T_points)+1) T_points1[-1] = T_points[-1] - 5 q_points1[-1] = q_points[-1] # Inverse function T_points2 = np.resize(T_points,len(T_points)+1) q_points2 = np.resize(q_points,len(T_points)+1) T_points2[-1] = T_points[-1] q_points2[-1] = q_points[-1] * 1.05 if debug: import matplotlib.pyplot as plt import tabulate xmod = np.resize(x_points,len(x_points)+1) print(tabulate.tabulate(zip(xmod,T_points1,q_points1, T_points2,q_points2), headers=['x','T1','q1','T2','q2'])) plt.figure(); plt.plot(T_points1,q_points1); plt.title("q(T)") plt.figure(); plt.plot(q_points2,T_points2); plt.title("T(q)") # Interpolate data must be in increasing order, so we reverse it # compared to reaction direction. self.q = PchipInterpolator(T_points1[::-1], q_points1[::-1]) self.T = PchipInterpolator(q_points2[::-1], T_points2[::-1])
Qu = 1. - x / x_liquid Q_vapor = 1 h_vap = CP.PropsSI('H','T',T,'Q',Q_vapor,'Water') v_vap = CP.PropsSI('D','T',T,'Q',Q_vapor,'Water') cp_vap = CP.PropsSI('C','T',T,'Q',Q_vapor,'Water') h = (1.0 - Qu) * h_liquid + Qu * h_vap v = (1.0 - Qu) * v_liquid + Qu * v_vap hh[i] = h vv[i] = v dhdp_T = (hh[1] - hh[0]) / deltaP dvdT_p = (vv[2] - vv[0]) / deltaT a = dhdp_T - (vv[0] - T * dvdT_p) dhdT_p = (state3.h - state1.h) / deltaT b = dhdT_p - cp print(state1) print(state2) print(state3) print("a = {}. b = {}".format(a,b)) return a,b if __name__ == "__main__": TC, P, x = 100, 10, 0.5 # C, bar, dim # go to 120 C and 11 bar residualsAmmonia(C2K(TC), P, x) # units are kJ/kg-K TC, P, x = 100, 1e3 / 1e5, 0.5 # C, bar, dim residualsLiBr(C2K(TC), P, x) # units are J/kg-K
# Units in this file: # temperature [C] # enthalpy [J/kg] # pressure [Pa] # mass fraction [kg/kg total] # effectiveness [K/K] # The LiBr enthalpy is zero at 293.15 K, 1 atm, per # http://www.coolprop.org/fluid_properties/Incompressibles.html#general-introduction # We need to evaluate water enthalpy relative to that, but it is not built-in. # http://www.coolprop.org/coolprop/HighLevelAPI.html#reference-states T_ref = 20 P_ref = 101325 pwater.update(CP.PT_INPUTS,P_ref,C2K(T_ref)) h_w_ref = pwater.hmass() class GeneratorLiBr(object): """Provide process heat canonical curve for generator in various forms. For purpose of external heat exchange, generator process goes ... P_cond, T_gen_pre, x1 (subcooled) P_cond, T_gen_inlet, x1 (saturated liquid) + backwards flowing vapor P_cond, T_gen_outlet, x2 (saturated liquid) Args: P : Pressure (Pa) The process is assumed to occur at constant pressure level. m_in : Solution inlet mass flow rate (kg/s) The mass flow rate of the stream pumped up from low pressure. T_in : Solution inlet temperature (C)