thermofluids 2.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,167 @@
1
+ from thermofluids import Statepoint, Quantity
2
+ from CoolProp.CoolProp import PropsSI
3
+ import math
4
+ import warnings
5
+
6
+
7
+ class Compressor():
8
+ """
9
+ Models a Compressor or Pump
10
+ :param inlet: [Statepoint] compressor inlet statepoint
11
+ :param eta: [Quantity] or [float] icentropic efficiency of turbo equipment
12
+ :param Pout: [Quantity] or [float] pressure at outlet of compressor or pump
13
+ :return: [Statepoint] compressor outlet statepoint
14
+ """
15
+ def __init__(self, inlet=None, inject=None, eta=None, Pout=None, output_name=None, work=None):
16
+ self.inject = inject
17
+ self.inlet = inlet
18
+ self.eta = eta
19
+ self.Pout = Pout
20
+ self.output_name = output_name
21
+ self._work = work
22
+ self._outlet = None
23
+
24
+ def set_inlet(self, inlet):
25
+ self.inlet = inlet
26
+
27
+ def set_eta(self, eta):
28
+ self.eta = eta
29
+
30
+ def set_Pout(self, Pout):
31
+ self.Pout = Pout
32
+
33
+ def set_output(self, output_name):
34
+ self.output_name = output_name
35
+
36
+ def get_Ns_Ds(self,rpm,D_rotor,n_comps,n_stages):
37
+ omega = rpm*2.0*math.pi/60.0
38
+ self.V_dot_CFS = (self.inlet.m/n_comps/self.inlet.rho).to('ft^3*s^-1')
39
+ gamma = self.inlet.cp / self.inlet.cv
40
+ ZRTMW = self.inlet.Z*Quantity(8.3144598,'J*K^-1*mol^-1')*self.inlet.t.to('K') / self.inlet.MW
41
+ adiabatic_head = (gamma*ZRTMW/(gamma-1.0)*(((self.Pout.to('Pa')/self.inlet.p.to('Pa'))/n_stages)**((gamma-1.0)/gamma)-1.0)).to('ft*lbf*lbm^-1')
42
+
43
+ self.Ns = rpm * self.V_dot_CFS**0.5 / (adiabatic_head**0.75)
44
+ self.Ds = D_rotor.to('ft')*adiabatic_head**0.25/(self.V_dot_CFS**0.5)
45
+ self.omega_tip = omega*D_rotor/2.0
46
+ self.machN = self.omega_tip/self.inlet.ss
47
+
48
+ @property
49
+ def work(self):
50
+ if self._work is None:
51
+ self.get_outlet()
52
+ return self._work
53
+
54
+ def get_outlet(self):
55
+ if self._outlet is not None:
56
+ return self._outlet
57
+
58
+ assert isinstance(self.inlet, Statepoint), '\'inlet\' must be set to a Statepoint'
59
+ self._outlet = Statepoint(name=self.output_name, fluid=self.inlet.fluid)
60
+ self._outlet.set_source(self.inlet)
61
+ self._outlet.set_m(self.inlet.m)
62
+ self._outlet.set_p(self.Pout)
63
+ if "HEOS" in self.inlet.fluid:
64
+ # mixtures don't have H(P,S) or T(P,S) available, so you have to manually solve for the temperature then enthalpy
65
+ res = 1.
66
+ s_target = inlet.s.magnitude
67
+ t_guess = Statepoint(fluid=inlet.fluid, p=self.Pout, x=1.).t
68
+ n = 0
69
+ while res > 0.001:
70
+ s_check = Statepoint(fluid=inlet.fluid, p=self.Pout, t=t_guess).s
71
+ res = abs(s_target - s_check.magnitude) / s_target
72
+ t_guess = (t_guess.to('K') * s_target / s_check.magnitude).to('degC')
73
+ h_out_s = Statepoint(fluid=inlet.fluid, p=self.Pout, t=t_guess).h
74
+ n += 1
75
+ if n > 100:
76
+ ValueError('Mixture solver timed out')
77
+ elif hasattr(self.inlet,'c'):
78
+ self._outlet.set_c(self.inlet.c)
79
+ h_out_s = Statepoint(fluid=self.inlet.fluid, c=self.inlet.c, p=self.Pout, s=self.inlet.s).h
80
+ else:
81
+ h_out_s = Statepoint(fluid=self.inlet.fluid, p=self.Pout.to_base_units(), s=self.inlet.s).h
82
+ h_out = ((h_out_s - self.inlet.h)/self.eta + self.inlet.h)
83
+ self._work = self._outlet.m*(h_out - self.inlet.h)
84
+ self._outlet.set_h(h_out)
85
+ self.m_cool = 0. #this line is not used in this code, but make this code compatible with calls to isocompressor
86
+
87
+ self.CFM = (self.inlet.m/self.inlet.rho).to('ft^3/min')
88
+
89
+ return self._outlet
90
+
91
+ def get_isothermal_outlet(self):
92
+ assert isinstance(self.inlet, Statepoint), '\'inlet\' must be set to a Statepoint'
93
+ assert isinstance(self.inject, Statepoint), '\'inject\' must be set to a Statepoint'
94
+
95
+ #guess inlet flow rate
96
+ self.inject.set_m(self.inlet.m/4.)
97
+ res=1000.
98
+ count = 0
99
+ self._outlet = Statepoint(name=self.output_name, fluid=self.inlet.fluid)
100
+ inject_vap = Statepoint(name='inject_vap', fluid=self.inject.fluid)
101
+ outlet_isen = Statepoint(name='outlet_isen', fluid=self.inlet.fluid)
102
+ outlet_adia = Statepoint(name='outlet_adia', fluid=self.inlet.fluid)
103
+
104
+ while res>0.01:
105
+ c_mix = (self.inlet.c*self.inlet.m + self.inject.c*self.inject.m)/(self.inlet.m+self.inject.m)
106
+
107
+ inject_vap.set_x(1.)
108
+ inject_vap.set_m(self.inject.m)
109
+ inject_vap.set_p(self.inject.p)
110
+ inject_vap.set_c(self.inject.c)
111
+
112
+ h_vap = inject_vap.h - self.inject.h
113
+ outlet_isen.set_m(self.inlet.m + self.inject.m)
114
+ outlet_isen.set_p(self.Pout)
115
+
116
+ outlet_isen.set_c(c_mix)
117
+ outlet_isen.set_s(self.inlet.s)
118
+
119
+ outlet_adia.set_c(c_mix)
120
+ outlet_adia.set_p(self.Pout)
121
+ outlet_adia.set_m(self.inlet.m + self.inject.m)
122
+ outlet_adia.set_h((outlet_isen.h - self.inlet.h)/self.eta + self.inlet.h)
123
+
124
+ W_isen = self.inlet.m*(outlet_adia.h - self.inlet.h) + self.inject.m*(outlet_isen.h - self.inject.h)
125
+ #print self.inlet.m, outlet_isen.h, self.inlet.h, self.inject.m, self.inject.h
126
+
127
+ self._outlet.set_m(self.inlet.m + self.inject.m)
128
+ self._outlet.set_p(self.Pout)
129
+ outlet_isen.set_c(c_mix)
130
+ self._outlet.set_c(c_mix)
131
+ self._outlet.set_x(1.) #assume the outlet is saturated
132
+ W_iso = self.inlet.m*(self._outlet.h - self.inlet.h) + self.inject.m*(self._outlet.h - self.inject.h)
133
+ Q_cooling = W_isen - W_iso
134
+ self.m_cool = Q_cooling/h_vap
135
+ res = abs((self.inject.m - self.m_cool)/self.inject.m)
136
+ self.inject.set_m(self.m_cool)
137
+ if count>500:
138
+ warnings.warn('isothermal compressor injection flow rate did not converge after 500 iterations')
139
+ raise Exception()
140
+
141
+ self._work = W_iso
142
+ self.CFM = (self.inlet.m/self.inlet.rho).to('ft^3/min')
143
+ return self._outlet
144
+
145
+
146
+ if __name__=='__main__':
147
+ FPS = 'REFPROP-MIX:AMMONIA&WATER'
148
+ inlet = Statepoint(name='inlet', fluid=FPS)
149
+ inlet.set_m(Quantity(0.001,'kg*s^-1'))
150
+ inlet.set_x(Quantity(1.,''))
151
+ inlet.set_c(Quantity(1.,''))
152
+ inlet.set_p(Quantity(1,'bar'))
153
+
154
+ eta_comp = .8
155
+ P_comp = Quantity(2.5,'bar')
156
+
157
+ comp = Compressor(inlet=inlet, eta=eta_comp, Pout=P_comp)
158
+ comp.get_outlet()
159
+ W_comp = comp.work
160
+ print(comp.outlet.h, comp.outlet.p, comp.outlet.c, comp.outlet.m, W_comp)
161
+
162
+ # fluid = "HEOS::R32[0.689]&R1234yf[0.311]"
163
+ # inlet = Statepoint(fluid=fluid, p=7., t=20., m=0.4)
164
+ # comp = Compressor(inlet=inlet, eta=0.8, Pout=19.)
165
+ # print(comp.get_outlet())
166
+ # print(comp.work)
167
+
@@ -0,0 +1,145 @@
1
+ """
2
+ Model of jet ejector based on http://ijlct.oxfordjournals.org/content/early/2009/01/01/ijlct.ctn001.full
3
+
4
+ Fundamentally, an ejector converts thermal energy to kinetic energy by expanding a motive gas to high velocity and low pressure.
5
+ The low pressure gas entrains a secondary fluid, transferring kinetic energy from the motive to the secondary gas.
6
+ Then, the kinetic energy is converted back to thermal energy which increases the pressure and reduces the velocity.
7
+
8
+
9
+ """
10
+
11
+ from math import sqrt
12
+ from thermofluids import Statepoint
13
+ from CoolProp.CoolProp import PropsSI
14
+
15
+ # refrigerants = ['R23', 'R32', 'R41', 'R125', 'R134a', 'R143a', 'R152a', 'R161', 'R227ea', 'R236ea', 'R236fa', 'R245ca', 'R245fa', 'R365mfc', 'R1233zd(E)', 'R1234yf', 'R1234ze(E)',
16
+ # 'RE143a', 'RE245cb2', 'RE245fa2', 'RE347mcc',
17
+ # 'R21', 'R22', 'R123', 'R124', 'R141b', 'R142b',
18
+ # 'R11', 'R12', 'R13', 'R113', 'R114', 'R115',
19
+ # 'R14', 'R116', 'R218', 'R1216', 'C4F10', 'C5F12', 'RC318',
20
+ # 'Novec649']
21
+ #
22
+ # for fluid in refrigerants:
23
+ # try:
24
+ # # print fluid, '\t', PropsSI('T', 'Q', 0.5, 'P', 0.4e5, 'REFPROP::'+fluid)-273.15
25
+ # h_vap = PropsSI('H', 'Q', 1., 'T', 60.+273., 'REFPROP::'+fluid) - PropsSI('H', 'Q', 0., 'T', 60.+273., 'REFPROP::'+fluid)
26
+ # P_sat = PropsSI('P', 'Q', 0.5, 'T', 60.+273., 'REFPROP::'+fluid)/1.e5
27
+ # s_ref = PropsSI('S', 'Q', 1., 'P', P_sat*1.e5, 'REFPROP::'+fluid)
28
+ # T_exp = PropsSI('T', 'S', s_ref, 'P', 0.2e5, 'REFPROP::'+fluid) - 273.15
29
+ # print fluid, '\t', P_sat, '\t', h_vap/1000., T_exp
30
+ # except:
31
+ # print fluid, 'failed'
32
+ #
33
+ # print
34
+ # print
35
+ # print
36
+
37
+ mot_fluid = 'REFPROP::Novec649'
38
+ entr_fluid = 'Ammonia'
39
+
40
+ eta_nozzle = 0.9
41
+ entr_ratio = 0.3
42
+
43
+
44
+ "Motive fluid from superheater to expansion nozzle"
45
+ inlet = Statepoint(name='inlet', fluid=mot_fluid)
46
+ inlet.set_p(1.45)
47
+ inlet.set_t(PropsSI('T', 'Q', 0.5, 'P', inlet.p*1.e5, mot_fluid)-273.15 + 3.) # 3C superheat
48
+ inlet.set_m(0.27 / entr_ratio)
49
+ print('Evaporator:', PropsSI('T', 'Q', 0.5, 'P', inlet.p*1.e5, mot_fluid)-273.15)
50
+
51
+ "Motive fluid isentropic expansion"
52
+ nozzle_s = Statepoint(name='nozzle_s')
53
+ nozzle_s.set_source(inlet, ('fluid', 'm', 's')) # isentropic expansion
54
+ nozzle_s.set_p(0.2)
55
+
56
+ "Motive fluid real expansion"
57
+ nozzle = Statepoint(name='nozzle')
58
+ nozzle.set_source(inlet, ('fluid', 'm'))
59
+ nozzle.set_p(nozzle_s.p)
60
+ nozzle.set_h(nozzle.source[0].h - eta_nozzle * (nozzle.source[0].h - nozzle_s.h))
61
+ nozzle.vel = sqrt(2.*(nozzle.source[0].h - nozzle.h)*1000.) # convert thermal energy to kinetic energy
62
+ nozzle.Ma = nozzle.vel / nozzle.ss
63
+ if PropsSI('T', 'Q', 0.5, 'P', nozzle.p*1.e5, mot_fluid)-273.15 >= nozzle.t:
64
+ raise Exception('Motive fluid condensing in primary nozzle')
65
+ print('Motive Ma:', nozzle.vel / nozzle.ss)
66
+
67
+ "Entrained fluid from boiler to entrainment"
68
+ entr_inlet = Statepoint(name='entr_inlet', fluid=entr_fluid)
69
+ entr_inlet.set_p(nozzle.p)
70
+ entr_inlet.set_x(1.) # saturated vapor inlet
71
+ entr_inlet.set_m(inlet.m * entr_ratio)
72
+
73
+ "Motive fluid after mixing"
74
+ mix_mot = Statepoint(name='mix_mot')
75
+ mix_mot.set_source(nozzle, ('fluid', 'm', 'p', 'h'))
76
+ mix_mot.vel = mix_mot.source[0].m / (mix_mot.source[0].m + entr_inlet.m) * mix_mot.source[0].vel
77
+
78
+ "Entrained fluid after mixing"
79
+ mix_entr = Statepoint(name='mix_entr')
80
+ mix_entr.set_source(entr_inlet, ('fluid', 'm', 'p', 'h'))
81
+ mix_entr.vel = mix_mot.vel
82
+
83
+ mix_ss = (1.-entr_ratio)*mix_mot.ss + entr_ratio*mix_entr.ss
84
+ print('Mixture Ma:', mix_mot.vel / mix_ss)
85
+ print('Mixture:', mix_mot.t, mix_entr.t)
86
+
87
+ "Motive fluid through con-di nozzle"
88
+ mot_recomp = Statepoint('mot_recomp')
89
+ mot_recomp.set_source(mix_mot, ('fluid', 'm'))
90
+ mot_recomp.set_h(mot_recomp.source[0].h + 0.5*mot_recomp.source[0].vel**2./1000.)
91
+ mot_recomp.set_s(mot_recomp.source[0].s)
92
+
93
+ "Entrained fluid through con-di nozzle"
94
+ entr_recomp = Statepoint('entr_recomp')
95
+ entr_recomp.set_source(mix_entr, ('fluid', 'm'))
96
+ entr_recomp.set_h(entr_recomp.source[0].h + 0.5*entr_recomp.source[0].vel**2./1000.)
97
+ entr_recomp.set_s(entr_recomp.source[0].s)
98
+ W_comp = entr_recomp.m * (entr_recomp.h - entr_recomp.source[0].h)
99
+ print('Compression work:', W_comp)
100
+
101
+ "Motive fluid condensation"
102
+ mot_cond = Statepoint('mot_cond')
103
+ mot_cond.set_source(mot_recomp, ('fluid', 'm', 'p'))
104
+ mot_cond.set_x(0.)
105
+ print('Condenser:', mot_cond.t, mot_cond.p)
106
+
107
+ "Entrained fluid condensation"
108
+ entr_cond = Statepoint('entr_cond')
109
+ entr_cond.set_source(entr_recomp, ('fluid', 'm', 'p'))
110
+ entr_cond.set_t(mot_cond.t)
111
+
112
+ Q_cond = mot_cond.m * (mot_cond.source[0].h - mot_cond.h) + entr_cond.m * (entr_cond.source[0].h - entr_cond.h)
113
+ print('Condenser load:', Q_cond)
114
+
115
+ "Pump motive fluid"
116
+ mot_pump = Statepoint('mot_pump')
117
+ mot_pump.set_source(mot_cond, ('fluid', 'm', 's'))
118
+ mot_pump.set_p(inlet.p)
119
+
120
+ "Pump entrained fluid"
121
+ entr_pump = Statepoint('entr_pump')
122
+ entr_pump.set_source(entr_cond, ('fluid', 'm', 's'))
123
+ entr_pump.set_p(1.)
124
+
125
+ W_pump = mot_pump.m * (mot_pump.h - mot_pump.source[0].h) + entr_pump.m * (entr_pump.h - entr_pump.source[0].h)
126
+ print('Pump work:', W_pump)
127
+
128
+ "Preheat motive fluid"
129
+ mot_preheat = Statepoint('mot_preheat')
130
+ mot_preheat.set_source(mot_pump, ('fluid', 'm', 'p'))
131
+ mot_preheat.set_x(0.)
132
+ Q_preheat = mot_preheat.m * (mot_preheat.h - mot_preheat.source[0].h)
133
+ print('Preheat load:', Q_preheat)
134
+
135
+ "Boil motive fluid"
136
+ mot_boil = inlet
137
+ mot_boil.set_source(mot_preheat)
138
+ Q_boil = mot_boil.m * (mot_boil.h - mot_boil.source[0].h)
139
+ print('Boiler load:', Q_boil)
140
+
141
+
142
+ eta_carnot = 1. - (mot_cond.t+273.15) / (inlet.t+273.15)
143
+ print('Actual efficiency:', W_comp / (Q_boil+Q_preheat))
144
+ print('Carnot efficiency:', eta_carnot)
145
+ print('Percent carnot:', (W_comp / (Q_boil+Q_preheat)) / eta_carnot)
@@ -0,0 +1,109 @@
1
+ from thermofluids.Base import Statepoint
2
+ from thermofluids.Base import Quantity
3
+ import types
4
+ from CoolProp.CoolProp import PropsSI
5
+
6
+ class HX_Energy():
7
+ def __init__(self, cold_inlet=None, hot_inlet=None, cold_outlet=None, hot_outlet=None, pinch=None,
8
+ cold_inlet_name='cold_inlet', cold_outlet_name='cold_outlet', hot_inlet_name='hot_inlet', hot_outlet_name='hot_outlet'):
9
+ """
10
+ Models a HX using an energy balance only. Any 3 of the following must be supplied:
11
+ hot inlet, hot outlet, cold inlet, cold outlet, or Pinch
12
+ :param cold_inlet: [Statepoint] HX cold inlet
13
+ :param hot_inlet: [Statepoint] HX hot inlet
14
+ :param cold_outlet: [Statepoint] HX cold outlet
15
+ :param hot_outlet: [Statepoint] HX hot outlet
16
+ :param pinch: [Quantity] or [float] Smallest pinch point at outlet of HX
17
+ :param cold_inlet_name: [string] name for cold inlet statepoint
18
+ :param cold_out_name: [string] name for cold outlet statepoint
19
+ :param hot_inlet_name: [string] name for hot inlet statepoint
20
+ :param hot_outlet_name: [string] name for hot outlet statepoint
21
+ """
22
+
23
+ self.cold_inlet = cold_inlet
24
+ self.hot_inlet = hot_inlet
25
+ self.cold_outlet = cold_outlet
26
+ self.hot_outlet = hot_outlet
27
+ self.pinch = pinch
28
+ self.cold_inlet_name = cold_inlet_name
29
+ self.cold_outlet_name = cold_outlet_name
30
+ self.hot_inlet_name = hot_inlet_name
31
+ self.hot_outlet_name = hot_outlet_name
32
+
33
+ def get_states(self):
34
+ flag_co = 0
35
+ flag_ci = 0
36
+ flag_ho = 0
37
+ flag_hi = 0
38
+ flag_p = 0
39
+
40
+ if self.cold_outlet is None:
41
+ flag_co=1
42
+ self.cold_outlet = Statepoint(name=self.cold_outlet_name, fluid=self.cold_inlet.fluid)
43
+ self.cold_outlet.set_t(max(self.cold_inlet.t, self.hot_inlet.t))
44
+ self.cold_outlet.set_m(self.cold_inlet.m)
45
+ self.cold_outlet.set_p(self.cold_inlet.p)
46
+ self.cold_outlet.set_c(self.cold_inlet.c)
47
+ if self.cold_inlet is None:
48
+ flag_ci=1
49
+ self.cold_inlet = Statepoint(name=self.cold_inlet_name, fluid=self.cold_outlet.fluid)
50
+ self.cold_inlet.set_t(min(self.hot_outlet.t, self.cold_outlet.t))
51
+ self.cold_inlet.set_m(self.cold_outlet.m)
52
+ self.cold_inlet.set_p(self.cold_outlet.p)
53
+ self.cold_inlet.set_c(self.cold_outlet.c)
54
+ if self.hot_outlet is None:
55
+ flag_ho=1
56
+ self.hot_outlet = Statepoint(name=self.hot_outlet_name, fluid=self.hot_inlet.fluid)
57
+ self.hot_outlet.set_t(min(self.cold_inlet.t, self.hot_inlet.t))
58
+ self.hot_outlet.set_m(self.hot_inlet.m)
59
+ self.hot_outlet.set_p(self.hot_inlet.p)
60
+ self.hot_outlet.set_c(self.hot_inlet.c)
61
+ if self.hot_inlet is None:
62
+ flag_hi=1
63
+ self.hot_inlet = Statepoint(name=self.hot_inlet_name, fluid=self.hot_outlet.fluid)
64
+ self.hot_inlet.set_t(max(self.cold_outlet.t, self.hot_outlet.t))
65
+ self.hot_inlet.set_m(self.hot_outlet.m)
66
+ self.hot_inlet.set_p(self.hot_outlet.p)
67
+ self.hot_inlet.set_c(self.hot_outlet.c)
68
+ if self.pinch is None:
69
+ flag_p=1
70
+
71
+ C_cold = self.cold_inlet.m * self.cold_inlet.cp
72
+ C_hot = self.hot_inlet.m * self.hot_inlet.cp
73
+
74
+
75
+ if (float(C_cold) > float(C_hot)) and (flag_ho > 0) and (flag_p == 0):
76
+ self.hot_outlet.update_prop(prop_val=self.cold_inlet.t + self.pinch, prop_name='T')
77
+ elif (float(C_cold) > float(C_hot)) and (flag_ci > 0) and (flag_p == 0):
78
+ self.cold_inlet.update_prop(prop_val=self.hot_outlet.t - self.pinch, prop_name='T')
79
+ elif (float(C_cold) <= float(C_hot)) and (flag_hi > 0) and (flag_p == 0):
80
+ self.hot_inlet.update_prop(prop_val=self.cold_outlet.t + self.pinch, prop_name='T')
81
+ elif (float(C_cold) <= float(C_hot)) and (flag_co > 0) and (flag_p == 0):
82
+ self.cold_outlet.update_prop(prop_val=self.hot_inlet.t - self.pinch, prop_name='T')
83
+
84
+ Q_HX_cold = self.cold_outlet.m*(self.cold_outlet.h-self.cold_inlet.h)
85
+ Q_HX_hot = self.hot_outlet.m*(self.hot_inlet.h-self.hot_outlet.h)
86
+ self.Q_HX = max(Q_HX_cold, Q_HX_hot)
87
+
88
+ if (flag_ho > 0) and (float(C_cold) <= float(C_hot)):
89
+ self.hot_outlet.update_prop(prop_val=self.hot_inlet.t - Q_HX_cold/(self.hot_inlet.m * self.hot_inlet.cp), prop_name='T')
90
+ if (flag_hi > 0) and (float(C_cold) > float(C_hot)):
91
+ self.hot_inlet.update_prop(prop_val=self.hot_outlet.t + Q_HX_cold/(self.hot_outlet.m * self.hot_outlet.cp), prop_name='T')
92
+ if (flag_ci > 0) and (float(C_cold) <= float(C_hot)):
93
+ self.cold_inlet.update_prop(prop_val=self.cold_outlet.t - Q_HX_hot/(self.cold_outlet.m * self.cold_outlet.cp), prop_name='T')
94
+ if(flag_co > 0) and (float(C_cold) > float(C_hot)):
95
+ self.cold_outlet.update_prop(prop_val=self.cold_inlet.t + Q_HX_hot/(self.cold_inlet.m * self.cold_inlet.cp), prop_name='T')
96
+
97
+ if (flag_p > 0):
98
+ if (float(C_cold) > float(C_hot)):
99
+ self.pinch = self.hot_outlet.t - self.cold_inlet.t
100
+ else:
101
+ self.pinch = self.hot_inlet.t - self.cold_outlet.t
102
+ if (flag_ho > 0):
103
+ self.hot_outlet.update_prop(prop_val=self.hot_inlet.t - Q_HX_cold/(self.hot_inlet.m * self.hot_inlet.cp), prop_name='T')
104
+ if (flag_hi > 0):
105
+ self.hot_inlet.update_prop(prop_val=self.hot_outlet.t + Q_HX_cold/(self.hot_outlet.m * self.hot_outlet.cp), prop_name='T')
106
+ if (flag_ci > 0):
107
+ self.cold_inlet.update_prop(prop_val=self.cold_outlet.t - Q_HX_hot/(self.cold_outlet.m * self.cold_outlet.cp), prop_name='T')
108
+ if(flag_co > 0):
109
+ self.cold_outlet.update_prop(prop_val=self.cold_inlet.t + Q_HX_hot/(self.cold_inlet.m * self.cold_inlet.cp), prop_name='T')
@@ -0,0 +1,124 @@
1
+ import warnings
2
+
3
+ from thermofluids.Base import Quantity
4
+ from thermofluids.Base import Statepoint
5
+ import math
6
+
7
+
8
+ class IsoCompressor():
9
+ def __init__(self, inlet=None, inject=None, Pout=None, output_name=None, work=None, eta=None):
10
+ """
11
+ Models an Isothermal Compressor or Pump
12
+ :param inlet: [Statepoint] compressor inlet statepoint
13
+ :param injeciton: [Statepoint] cooling injection stream
14
+ :param eta: [Quantity] or [float] icentropic efficiency of turbo equipment
15
+ :param Pout: [Quantity] or [float] pressure at outlet of compressor or pump
16
+ :return: [Statepoint] compressor outlet statepoint
17
+ """
18
+ self.inject = inject
19
+ self.inlet = inlet
20
+ self.Pout = Pout
21
+ self.output_name = output_name
22
+ self.work = work
23
+ self.eta = eta
24
+ print(self.inlet)
25
+
26
+ def set_inlet(self, inlet):
27
+ self.inlet = inlet
28
+
29
+ def set_eta(self, eta):
30
+ self.eta = eta
31
+
32
+ def set_Pout(self, Pout):
33
+ self.Pout = Pout
34
+
35
+ def set_output_name(self, output_name):
36
+ self.output_name = output_name
37
+
38
+ def get_Ns_Ds(self, rpm, D_rotor, n_comps, n_stages):
39
+ omega = rpm * 2.0 * math.pi / 60.0
40
+ self.V_dot_CFS = (self.inlet.m / n_comps / self.inlet.rho).to('ft^3*s^-1')
41
+ gamma = self.inlet.cp / self.inlet.cv
42
+ ZRTMW = self.inlet.Z * Quantity(8.3144598, 'J*K^-1*mol^-1') * self.inlet.t.to('K') / self.inlet.MW
43
+ adiabatic_head = (gamma * ZRTMW / (gamma - 1.0) * (
44
+ ((self.Pout.to('Pa') / self.inlet.p.to('Pa')) / n_stages) ** (
45
+ (gamma - 1.0) / gamma) - 1.0)).to('ft*lbf*lbm^-1')
46
+
47
+ self.Ns = rpm * self.V_dot_CFS ** 0.5 / (adiabatic_head ** 0.75)
48
+ self.Ds = D_rotor.to('ft') * adiabatic_head ** 0.25 / (self.V_dot_CFS ** 0.5)
49
+ self.omega_tip = omega * D_rotor / 2.0
50
+ self.machN = self.omega_tip / self.inlet.ss
51
+
52
+ def get_outlet(self):
53
+
54
+ assert isinstance(self.inlet, Statepoint), '\'inlet\' must be set to a Statepoint'
55
+ assert isinstance(self.inject, Statepoint), '\'inject\' must be set to a Statepoint'
56
+
57
+ #guess inlet flow rate
58
+ self.inject.set_m(self.inlet.m/4.)
59
+ res=1000.
60
+ count = 0
61
+ self.outlet = Statepoint(name=self.output_name, fluid=self.inlet.fluid)
62
+ inject_vap = Statepoint(name='inject_vap', fluid=self.inject.fluid)
63
+ outlet_isen = Statepoint(name='outlet_isen', fluid=self.inlet.fluid)
64
+ outlet_adia = Statepoint(name='outlet_adia', fluid=self.inlet.fluid)
65
+
66
+ while res>0.01:
67
+ c_mix = (self.inlet.c*self.inlet.m + self.inject.c*self.inject.m)/(self.inlet.m+self.inject.m)
68
+
69
+ inject_vap.set_x(1.)
70
+ inject_vap.set_m(self.inject.m)
71
+ inject_vap.set_p(self.inject.p)
72
+ inject_vap.set_c(self.inject.c)
73
+
74
+ h_vap = inject_vap.h - self.inject.h
75
+ outlet_isen.set_m(self.inlet.m + self.inject.m)
76
+ outlet_isen.set_p(self.Pout)
77
+
78
+ outlet_isen.set_c(c_mix)
79
+ outlet_isen.set_s(self.inlet.s)
80
+
81
+ outlet_adia.set_c(c_mix)
82
+ outlet_adia.set_p(self.Pout)
83
+ outlet_adia.set_m(self.inlet.m + self.inject.m)
84
+ print(outlet_isen.h, self.inlet.h, self.eta, self.inlet.h)
85
+ outlet_adia.set_h((outlet_isen.h - self.inlet.h)/self.eta + self.inlet.h)
86
+
87
+ W_isen = self.inlet.m*(outlet_adia.h - self.inlet.h) + self.inject.m*(outlet_isen.h - self.inject.h)
88
+ #print self.inlet.m, outlet_isen.h, self.inlet.h, self.inject.m, self.inject.h
89
+
90
+ self.outlet.set_m(self.inlet.m + self.inject.m)
91
+ self.outlet.set_p(self.Pout)
92
+ outlet_isen.set_c(c_mix)
93
+ self.outlet.set_c(c_mix)
94
+ self.outlet.set_x(1.) #assume the outlet is saturated
95
+ W_iso = self.inlet.m*(self.outlet.h - self.inlet.h) + self.inject.m*(self.outlet.h - self.inject.h)
96
+ Q_cooling = W_isen - W_iso
97
+ self.m_cool = Q_cooling/h_vap
98
+ res = abs((self.inject.m - self.m_cool)/self.inject.m)
99
+ self.inject.set_m(self.m_cool)
100
+ if count>500:
101
+ warnings.warn('isothermal compressor injection flow rate did not converge after 500 iterations')
102
+ raise Exception()
103
+
104
+ self.work = W_iso
105
+ self.CFM = Quantity(float(self.inlet.m/self.inlet.rho)*2118.88,'ft^3/min')
106
+ return self.outlet
107
+
108
+ if __name__=='__main__':
109
+ #inputs
110
+ R_HX = 1.
111
+ FPS = 'REFPROP-MIX:METHANOL&WATER'
112
+ inject = Statepoint(name='inject', fluid=FPS)
113
+ inlet = Statepoint(name='inlet', fluid=FPS)
114
+ inject.set_x(.0)
115
+ inject.set_c(.72)
116
+ inject.set_p(1.0)
117
+
118
+ inlet.set_x(1.)
119
+ inlet.set_c(0.72)
120
+ inlet.set_p(1.0)
121
+ inlet.set_m(0.035)
122
+ comp = IsoCompressor(inlet=inlet, inject=inject, Pout=2., eta=1)
123
+ comp.get_outlet()
124
+ print(comp.work)
@@ -0,0 +1,21 @@
1
+ from thermofluids.Base import Statepoint
2
+
3
+ class Pipe():
4
+ def __init__(self, inlet=None):
5
+ self.inlet = inlet
6
+
7
+ def get_outlet(self):
8
+ outlet = Statepoint()
9
+ outlet.set_source(self.inlet, ('fluid', 'm', 'h', 'p'))
10
+
11
+ return outlet
12
+
13
+ if __name__ == "__main__":
14
+ inlet = Statepoint()
15
+ inlet.set_fluid("water")
16
+ inlet.set_p(1.)
17
+ inlet.set_m(1.)
18
+ inlet.set_t(25.)
19
+
20
+ pipe = Pipe(inlet)
21
+ print(pipe.get_outlet())
@@ -0,0 +1,109 @@
1
+ from thermofluids.Base import Statepoint
2
+ from thermofluids.Base import Quantity
3
+ from CoolProp.CoolProp import PropsSI
4
+ from thermofluids.Properties.BrineProps import get_c_freeze, get_h_f, get_T_liq_sat, get_T_vap_sat, get_h_mix, get_C_vap_sat, get_C_liq_sat, get_c_satliq_at_t, get_c_satvap_at_t
5
+ import warnings
6
+
7
+ # these values are taken from the manufacterers speck. Flow must be in m^3/s and pressure in bara.
8
+ PUMP_CURVE_DIC = {"IWAKI_M251": {"NPSHr": {
9
+ "flow": [0.000145517,0.00024495,0.00037565,0.000571933,0.001,0.0009168,0.001111983,0.0012997,0.001454833,0.001599733,0.001789267,0.001951767,0.00213965,0.002287983,0.0024091,0.00254205],
10
+ "pressure": [0.424, 0.348, 0.295, 0.231, 0.203, 0.205, 0.225, 0.268, 0.306, 0.356, 0.421, 0.481, 0.547, 0.600,0.639, 0.654]},
11
+ "pump_curve": {
12
+ "flow": [0.000166667,0.0005,0.000824567,0.001087717,0.001324567,0.001526317,0.001745617,0.001956133,0.00214035,0.002324567,0.002535083],
13
+ "pressure": [3.052436053,3.032940359,2.994046941,2.942025769,2.883636658,2.825149578,2.747166805,2.662718123,2.57836741,2.487354852,2.376944569]}}
14
+ }
15
+
16
+ class Pump():
17
+
18
+ def __init__(self, inlet=None, outlet_P=None, name=None):
19
+ self.name = name
20
+ self.inlet = inlet
21
+ self.outlet_P = outlet_P
22
+ self.max_flow = 0
23
+ self.max_P = 0
24
+ self.NPSHr=0
25
+
26
+ def set_outlet_P(self,outlet_P):
27
+ self.outlet_P = outlet_P
28
+
29
+ def set_inlet(self,inlet):
30
+ self.inlet = inlet
31
+
32
+ def set_name(self, name):
33
+ self.name = name
34
+
35
+ def flow_at_outlet_P(self):
36
+ x = 0
37
+ if(self.name=="M251" or self.name=="iwaki-M251" or self.name=="IWAKI-M251" or self.name=="Iwaki-M251" or self.name=="m251"):
38
+ pump_key = "IWAKI_M251"
39
+ if PUMP_CURVE_DIC[pump_key]["pump_curve"]["pressure"][0]<self.outlet_P:
40
+ warnings.warn('specified pump can reach max head of '+str(PUMP_CURVE_DIC[pump_key]["pump_curve"]["pressure"][0])+'bar and cannot meet the required head of '+str(self.outlet_P))
41
+ else:
42
+ while x < len(PUMP_CURVE_DIC[pump_key]["pump_curve"]["flow"]):
43
+ print(PUMP_CURVE_DIC[pump_key]["pump_curve"]["pressure"][x], self.outlet_P)
44
+ if(PUMP_CURVE_DIC[pump_key]["pump_curve"]["pressure"][x]<self.outlet_P):
45
+ P_right = PUMP_CURVE_DIC[pump_key]["pump_curve"]["pressure"][x]
46
+ P_left = PUMP_CURVE_DIC[pump_key]["pump_curve"]["pressure"][x-1]
47
+ flow_right = PUMP_CURVE_DIC[pump_key]["pump_curve"]["flow"][x]
48
+ flow_left = PUMP_CURVE_DIC[pump_key]["pump_curve"]["flow"][x-1]
49
+ self.maxFlow = Quantity(flow_left + (self.outlet_P.magnitude - P_left) / (P_right - P_left) * (flow_right - flow_left),'m^3/s')
50
+ x = 100000
51
+ if(x==len(PUMP_CURVE_DIC[pump_key]["pump_curve"]["flow"])):
52
+ self.maxFlow = flow_right = PUMP_CURVE_DIC[pump_key]["pump_curve"]["flow"][x-1]
53
+ x = 100000
54
+ x = x + 1
55
+
56
+ x = 0
57
+ while x < len(PUMP_CURVE_DIC[pump_key]["NPSHr"]["flow"]):
58
+ if (PUMP_CURVE_DIC[pump_key]["NPSHr"]["flow"][x] > self.maxFlow):
59
+ P_right = PUMP_CURVE_DIC[pump_key]["NPSHr"]["pressure"][x]
60
+ P_left = PUMP_CURVE_DIC[pump_key]["NPSHr"]["pressure"][x - 1]
61
+ flow_right = PUMP_CURVE_DIC[pump_key]["NPSHr"]["flow"][x]
62
+ flow_left = PUMP_CURVE_DIC[pump_key]["NPSHr"]["flow"][x - 1]
63
+ self.NPSHr = Quantity(
64
+ 0.0597216 + P_left + (inlet_flow.magnitude - flow_left) / (flow_right - flow_left) * (P_right - P_left), 'bar')
65
+ x = 100000
66
+ x = x + 1
67
+
68
+ def P_at_inlet_flow(self):
69
+ inlet_flow = self.inlet.m/self.inlet.rho
70
+ x=0
71
+ if(self.name=="M251" or self.name=="iwaki-M251" or self.name=="IWAKI-M251" or self.name=="Iwaki-M251" or self.name=="m251"):
72
+ pump_key = "IWAKI_M251"
73
+ if PUMP_CURVE_DIC[pump_key]["pump_curve"]["flow"][len(PUMP_CURVE_DIC[pump_key]["pump_curve"]["flow"])-1]<inlet_flow:
74
+ warnings.warn('specified pump can reach max flow of '+PUMP_CURVE_DIC[pump_key]["pump_curve"]["flow"][len(PUMP_CURVE_DIC[pump_key]["pump_curve"]["flow"])-1]+'m^3/s and cannot meet the required head of '+intlet_flows)
75
+ else:
76
+ while x<len(PUMP_CURVE_DIC[pump_key]["pump_curve"]["flow"]):
77
+ if(PUMP_CURVE_DIC[pump_key]["pump_curve"]["flow"][x]>inlet_flow):
78
+ P_right = PUMP_CURVE_DIC[pump_key]["pump_curve"]["pressure"][x]
79
+ P_left = PUMP_CURVE_DIC[pump_key]["pump_curve"]["pressure"][x-1]
80
+ flow_right = PUMP_CURVE_DIC[pump_key]["pump_curve"]["flow"][x]
81
+ flow_left = PUMP_CURVE_DIC[pump_key]["pump_curve"]["flow"][x-1]
82
+ self.max_P = Quantity(P_left + (inlet_flow.magnitude - flow_left)/(flow_right-flow_left)*(P_right-P_left),'bar')
83
+ #print (self.max_P-1.0)*401.0/12.,P_left, P_right, flow_left, flow_right, inlet_flow.magnitude, x
84
+ x = 100000
85
+ x=x+1
86
+
87
+ x=0
88
+ while x<len(PUMP_CURVE_DIC[pump_key]["NPSHr"]["flow"]):
89
+ if(PUMP_CURVE_DIC[pump_key]["NPSHr"]["flow"][x]>inlet_flow):
90
+ P_right = PUMP_CURVE_DIC[pump_key]["NPSHr"]["pressure"][x]
91
+ P_left = PUMP_CURVE_DIC[pump_key]["NPSHr"]["pressure"][x-1]
92
+ flow_right = PUMP_CURVE_DIC[pump_key]["NPSHr"]["flow"][x]
93
+ flow_left = PUMP_CURVE_DIC[pump_key]["NPSHr"]["flow"][x-1]
94
+ self.NPSHr = Quantity(0.0597216 + P_left + (inlet_flow.magnitude - flow_left)/(flow_right-flow_left)*(P_right-P_left),'bar')
95
+ x = 100000
96
+ x=x+1
97
+
98
+
99
+
100
+
101
+ def get_outlet_SP(self):
102
+ self.outlet = Statepoint()
103
+ self.outlet.set_fluid(self.inlet.fluid)
104
+ self.outlet.set_p(self.inlet.p)
105
+ self.outlet.set_t(self.inlet.t)
106
+ self.outlet.set_m(outlet.set_m)
107
+
108
+ if __name__=='__main__':
109
+ print(test(2.))