1 |
(* ASCEND modelling environment |
2 |
Copyright (C) 2007, 2008, 2009, 2010 Carnegie Mellon University |
3 |
|
4 |
This program is free software; you can redistribute it and/or modify |
5 |
it under the terms of the GNU General Public License as published by |
6 |
the Free Software Foundation; either version 2, or (at your option) |
7 |
any later version. |
8 |
|
9 |
This program is distributed in the hope that it will be useful, |
10 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 |
GNU General Public License for more details. |
13 |
|
14 |
You should have received a copy of the GNU General Public License |
15 |
along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 |
*)(* |
17 |
A number of Rankine-cycle (steam turbine power cycle) models of increasing |
18 |
complexity, following the general development of Moran & Shapiro, Çengel, |
19 |
and others. |
20 |
|
21 |
Author: John Pye |
22 |
*) |
23 |
|
24 |
REQUIRE "atoms.a4l"; |
25 |
REQUIRE "johnpye/thermo_types.a4c"; |
26 |
|
27 |
IMPORT "johnpye/fprops/fprops"; |
28 |
|
29 |
(*------------------------------------------------------------------------------ |
30 |
BACKGROUND STUFF |
31 |
*) |
32 |
|
33 |
MODEL fluid; |
34 |
component IS_A symbol_constant; |
35 |
type IS_A symbol_constant; |
36 |
END fluid; |
37 |
|
38 |
(* |
39 |
Thermo properties -- IAPWS-IF97 |
40 |
*) |
41 |
MODEL stream_state; |
42 |
cd IS_A fluid; |
43 |
p IS_A pressure; |
44 |
h IS_A specific_enthalpy; |
45 |
|
46 |
T IS_A temperature; |
47 |
v IS_A specific_volume; |
48 |
s IS_A specific_entropy; |
49 |
x IS_A fraction; |
50 |
|
51 |
calc_vT: fprops_phsx_vT( |
52 |
v, T : INPUT; |
53 |
p, h, s, x : OUTPUT; |
54 |
cd : DATA |
55 |
); |
56 |
calc_ph: fprops_Tvsx_ph( |
57 |
p, h : INPUT; |
58 |
T, v, s, x : OUTPUT; |
59 |
cd : DATA |
60 |
); |
61 |
METHODS |
62 |
METHOD default; |
63 |
p := 10{bar}; |
64 |
p.nominal := 42 {bar}; |
65 |
IF cd.component == 'water' THEN |
66 |
h := 2000 {kJ/kg}; |
67 |
ELSE |
68 |
IF cd.component == 'carbondioxide' THEN |
69 |
h := 350 {kJ/kg}; |
70 |
ELSE |
71 |
h := 351 {kJ/kg}; |
72 |
END IF; |
73 |
END IF; |
74 |
|
75 |
T := 400 {K}; |
76 |
v.nominal := 10 {L/kg}; |
77 |
s := 4 {kJ/kg/K}; |
78 |
x := 0.8; |
79 |
|
80 |
RUN enable_ph; |
81 |
END default; |
82 |
METHOD default_self; |
83 |
RUN default; |
84 |
END default_self; |
85 |
METHOD enable_vT; |
86 |
FOR i IN [1..4] DO |
87 |
calc_ph[i].included := FALSE; |
88 |
calc_vT[i].included := TRUE; |
89 |
END FOR; |
90 |
END enable_vT; |
91 |
METHOD enable_ph; |
92 |
FOR i IN [1..4] DO |
93 |
calc_ph[i].included := TRUE; |
94 |
calc_vT[i].included := FALSE; |
95 |
END FOR; |
96 |
END enable_ph; |
97 |
METHOD solve; |
98 |
EXTERNAL do_solve(SELF); |
99 |
END solve; |
100 |
END stream_state; |
101 |
|
102 |
MODEL stream_state_test REFINES stream_state; |
103 |
cd.component :== 'water'; |
104 |
cd.type :== 'helmholtz'; |
105 |
METHODS |
106 |
METHOD on_load; |
107 |
RUN default_all; |
108 |
FIX p, h; |
109 |
p := 10 {bar}; |
110 |
h := 2000 {kJ/kg}; |
111 |
SOLVER QRSlv; |
112 |
OPTION convopt 'RELNOM_SCALE'; |
113 |
SOLVE; |
114 |
ASSERT abs(T - 453.03 {K}) < 0.01 {K}; |
115 |
ASSERT abs(v - 0.119808 {m^3/kg}) < 0.0001 {m^3/kg}; |
116 |
ASSERT abs(x - 0.6142) < 0.0001; |
117 |
ASSERT abs(s - 4.8696 {kJ/kg/K}) < 0.0001 {kJ/kg/K}; |
118 |
END on_load; |
119 |
END stream_state_test; |
120 |
|
121 |
|
122 |
MODEL stream_state_test_co2 REFINES stream_state; |
123 |
cd.component :== 'carbondioxide'; |
124 |
cd.type :== 'helmholtz'; |
125 |
METHODS |
126 |
METHOD on_load; |
127 |
RUN default_all; |
128 |
h := 350 {kJ/kg}; |
129 |
FIX p, x; |
130 |
p := 6 {bar}; |
131 |
x := 1e-6; |
132 |
SOLVER QRSlv; |
133 |
OPTION convopt 'RELNOM_SCALE'; |
134 |
END on_load; |
135 |
END stream_state_test_co2; |
136 |
|
137 |
|
138 |
MODEL stream_state_test_toluene REFINES stream_state; |
139 |
cd.component :== 'toluene'; |
140 |
cd.type :== 'helmholtz'; |
141 |
METHODS |
142 |
METHOD on_load; |
143 |
RUN default_all; |
144 |
FIX p, x; |
145 |
p := 8 {kPa}; |
146 |
x := 1e-6; |
147 |
SOLVER QRSlv; |
148 |
OPTION convopt 'RELNOM_SCALE'; |
149 |
END on_load; |
150 |
END stream_state_test_toluene; |
151 |
|
152 |
|
153 |
(* a simple connector that includes calculation of steam properties *) |
154 |
MODEL stream_node; |
155 |
state IS_A stream_state; |
156 |
cd ALIASES state.cd; |
157 |
p ALIASES state.p; |
158 |
h ALIASES state.h; |
159 |
v ALIASES state.v; |
160 |
T ALIASES state.T; |
161 |
s ALIASES state.s; |
162 |
x ALIASES state.x; |
163 |
mdot "param: mass flowrate" IS_A mass_rate; |
164 |
METHODS |
165 |
|
166 |
METHOD default_self; |
167 |
RUN state.default_self; |
168 |
RUN default; |
169 |
END default_self; |
170 |
|
171 |
METHOD default; |
172 |
mdot.nominal := 2 {kg/s}; |
173 |
END default; |
174 |
METHOD solve; |
175 |
EXTERNAL do_solve(SELF); |
176 |
END solve; |
177 |
METHOD on_load; |
178 |
RUN default_all; RUN reset; RUN values; |
179 |
FIX p,h; |
180 |
END on_load; |
181 |
END stream_node; |
182 |
|
183 |
MODEL stream_equipment; |
184 |
|
185 |
outlet "out: outlet stream" IS_A stream_node; |
186 |
inlet "in: inlet stream" IS_A stream_node; |
187 |
inlet.cd, outlet.cd ARE_THE_SAME; |
188 |
inlet.mdot, outlet.mdot ARE_THE_SAME; |
189 |
cd ALIASES inlet.cd; |
190 |
mdot ALIASES inlet.mdot; |
191 |
END stream_equipment; |
192 |
|
193 |
(*------------------------------------------------------------------------------ |
194 |
PUMP COMPONENT |
195 |
*) |
196 |
|
197 |
MODEL pump_simple REFINES stream_equipment; |
198 |
NOTES |
199 |
'block' SELF {Simple model of a compressor using isentropic efficiency} |
200 |
'icon' SELF {Pump} |
201 |
'graphic' SELF {0,0-0,10-10,6-10,4-0,0 |
202 |
1,0.4-1,9.6 |
203 |
9,3.6-9,6.4 } |
204 |
'port_in' SELF {inlet:0,5} |
205 |
'port_out' SELF {outlet:10,5} |
206 |
END NOTES; |
207 |
|
208 |
dp "param: it is in fixed state = 20{atm}" IS_A delta_pressure; |
209 |
|
210 |
inlet.p + dp = outlet.p; |
211 |
|
212 |
outlet_is IS_A stream_state; |
213 |
outlet_is.p, outlet.p ARE_THE_SAME; |
214 |
outlet_is.cd, outlet.cd ARE_THE_SAME; |
215 |
outlet_is.s, inlet.s ARE_THE_SAME; |
216 |
eta "param: efficiency of the pump/compressor" IS_A fraction; |
217 |
|
218 |
|
219 |
eta_eq:eta * (inlet.h - outlet.h) = (inlet.h - outlet_is.h); |
220 |
|
221 |
(* work done on the environment, will be negative *) |
222 |
Wdot IS_A energy_rate; |
223 |
Wdot_eq:Wdot = mdot * w; |
224 |
|
225 |
w IS_A negative_specific_work; |
226 |
w_eq:w = inlet.h - outlet.h; |
227 |
METHODS |
228 |
METHOD default_self; |
229 |
RUN inlet.default_self; |
230 |
RUN outlet.default_self; |
231 |
RUN outlet_is.default_self; |
232 |
END default_self; |
233 |
END pump_simple; |
234 |
|
235 |
MODEL pump_simple_test REFINES pump_simple; |
236 |
cd.component :== 'water'; |
237 |
METHODS |
238 |
METHOD on_load; |
239 |
RUN default_self; |
240 |
FIX inlet.p; inlet.p := 5 {bar}; |
241 |
FIX inlet.h; inlet.h := 400 {kJ/kg}; |
242 |
FIX outlet.p; outlet.p := 100 {bar}; |
243 |
FIX eta; eta := 0.65; |
244 |
FIX mdot; mdot := 900 {t/d}; |
245 |
|
246 |
inlet.v := 0.97 {L/kg}; |
247 |
inlet.T := 300 {K}; |
248 |
|
249 |
SOLVER QRSlv; |
250 |
OPTION convopt 'RELNOM_SCALE'; |
251 |
OPTION iterationlimit 200; |
252 |
END on_load; |
253 |
END pump_simple_test; |
254 |
|
255 |
(*------------------------------------------------------------------------------ |
256 |
TURBINE COMPONENT |
257 |
*) |
258 |
|
259 |
MODEL turbine_simple REFINES stream_equipment; |
260 |
NOTES |
261 |
'block' SELF {Simple turbine model} |
262 |
'graphic' SELF {10,0-10,10-0,8-0,2-10,0} |
263 |
'port_in' SELF {inlet:3.34,1.332} |
264 |
'port_out' SELF {outlet:6.67,0.667} |
265 |
END NOTES; |
266 |
|
267 |
|
268 |
dp "param: pressure drop, default value = [10{atm}]" IS_A delta_pressure; |
269 |
inlet.p + dp = outlet.p; |
270 |
|
271 |
outlet_is IS_A stream_state; |
272 |
outlet_is.cd, outlet.cd ARE_THE_SAME; |
273 |
outlet_is.p, outlet.p ARE_THE_SAME; |
274 |
outlet_is.s, inlet.s ARE_THE_SAME; |
275 |
|
276 |
eta "param: efficiency of turbine" IS_A fraction; |
277 |
eta_eq:eta * (inlet.h - outlet_is.h) = (inlet.h - outlet.h); |
278 |
|
279 |
(* work done on the environment, will be positive *) |
280 |
Wdot IS_A energy_rate; |
281 |
Wedot_eq:Wdot = mdot * w; |
282 |
|
283 |
w IS_A positive_specific_work; |
284 |
w_eq:w = inlet.h - outlet.h; |
285 |
METHODS |
286 |
METHOD default_self; |
287 |
RUN inlet.default_self; |
288 |
RUN outlet.default_self; |
289 |
RUN outlet_is.default_self; |
290 |
END default_self; |
291 |
END turbine_simple; |
292 |
|
293 |
MODEL turbine_simple_test REFINES turbine_simple; |
294 |
cd.component :== 'water'; |
295 |
METHODS |
296 |
METHOD on_load; |
297 |
RUN default_self; |
298 |
FIX inlet.p; |
299 |
FIX inlet.h; |
300 |
FIX outlet.p; |
301 |
FIX eta; |
302 |
FIX mdot; |
303 |
|
304 |
inlet.p := 100 {bar}; |
305 |
inlet.h := 3000 {kJ/kg}; |
306 |
outlet.p := 5 {bar}; |
307 |
eta := 0.85; |
308 |
mdot := 900 {t/d}; |
309 |
END on_load; |
310 |
END turbine_simple_test; |
311 |
|
312 |
(*------------------------------------------------------------------------------ |
313 |
BOILER COMPONENT |
314 |
*) |
315 |
|
316 |
(* |
317 |
simple model assumes no pressure drop, but heating losses due to |
318 |
flue gas temperature |
319 |
*) |
320 |
MODEL boiler_simple REFINES stream_equipment; |
321 |
NOTES |
322 |
'block' SELF {Simple boiler model} |
323 |
'graphic' SELF {0,0-10,0-10,10-0,10-0,0} |
324 |
END NOTES; |
325 |
|
326 |
inlet.p, outlet.p ARE_THE_SAME; |
327 |
Qdot_fuel IS_A energy_rate; |
328 |
|
329 |
q IS_A specific_energy; |
330 |
q = (outlet.h - inlet.h); |
331 |
|
332 |
Qdot "param: energy rate" IS_A energy_rate; |
333 |
heateqn: Qdot = mdot * q; |
334 |
|
335 |
eta "param: efficiency of boiler" IS_A fraction; |
336 |
Qdot = eta * Qdot_fuel; |
337 |
METHODS |
338 |
METHOD default_self; |
339 |
RUN inlet.default_self; |
340 |
RUN outlet.default_self; |
341 |
END default_self; |
342 |
END boiler_simple; |
343 |
|
344 |
MODEL boiler_simple_test REFINES boiler_simple; |
345 |
cd.component :== 'water'; |
346 |
METHODS |
347 |
METHOD on_load; |
348 |
RUN default_self; |
349 |
FIX inlet.p; |
350 |
FIX inlet.h; |
351 |
FIX eta; |
352 |
FIX mdot; |
353 |
|
354 |
inlet.p := 100 {bar}; |
355 |
inlet.h := 500 {kJ/kg}; |
356 |
|
357 |
eta := 0.8; |
358 |
outlet.h := 3000 {kJ/kg}; |
359 |
mdot := 900 {t/d}; |
360 |
END on_load; |
361 |
END boiler_simple_test; |
362 |
|
363 |
(*------------------------------------------------------------------------------ |
364 |
CONDENSER COMPONENT |
365 |
*) |
366 |
|
367 |
(* |
368 |
this is really simple (fluid props permitting): just work out the heat |
369 |
that must be expelled to get the water down to a certain state |
370 |
*) |
371 |
MODEL condenser_simple REFINES stream_equipment; |
372 |
NOTES |
373 |
'block' SELF {Condenser} |
374 |
'icon' SELF {Condenser} |
375 |
'graphic' SELF {0,0-10,0-10,10-0,10-0,0 |
376 |
0,5-1.5,5-2,6-3,4-4,6-5,4-6,6-7,4-8,6-8.5,5-10,5} |
377 |
END NOTES; |
378 |
|
379 |
inlet.p, outlet.p ARE_THE_SAME; |
380 |
Qdot IS_A energy_rate; |
381 |
|
382 |
cons_en: Qdot = mdot * (outlet.h - inlet.h); |
383 |
METHODS |
384 |
METHOD default_self; |
385 |
RUN inlet.default_self; |
386 |
RUN outlet.default_self; |
387 |
END default_self; |
388 |
END condenser_simple; |
389 |
|
390 |
MODEL condenser_simple_test REFINES condenser_simple; |
391 |
cd.component :== 'water'; |
392 |
METHODS |
393 |
METHOD on_load; |
394 |
RUN default_self; |
395 |
FIX inlet.p, inlet.x; |
396 |
FIX outlet.h; |
397 |
FIX mdot; |
398 |
|
399 |
inlet.p := 5 {bar}; |
400 |
inlet.x := 0.95; |
401 |
outlet.h := 500 {kJ/kg}; |
402 |
mdot := 900 {t/d}; |
403 |
END on_load; |
404 |
END condenser_simple_test; |
405 |
|
406 |
(*------------------------------------------------------------------------------ |
407 |
FEEDWATER HEATER |
408 |
*) |
409 |
|
410 |
(* |
411 |
open heater does not have inlet.mdot==outlet.mdot, so not a refinement |
412 |
of 'stream_equipment'. |
413 |
*) |
414 |
MODEL heater_open; |
415 |
NOTES |
416 |
'block' SELF {Simple open feedwater heater} |
417 |
'port_in' SELF {inlet:0,5-inlet_heat:5,0} |
418 |
'port_out' SELF {outlet:10,5} |
419 |
'graphic' SELF {0,0-10,0-10,10-0,10-0,0} |
420 |
END NOTES; |
421 |
|
422 |
inlet "in:" IS_A stream_node; |
423 |
inlet_heat "in:" IS_A stream_node; |
424 |
outlet "out:" IS_A stream_node; |
425 |
inlet_heat.p, inlet.p, outlet.p ARE_THE_SAME; |
426 |
inlet.cd, outlet.cd, inlet_heat.cd ARE_THE_SAME; |
427 |
cd ALIASES inlet.cd; |
428 |
|
429 |
(* cons. mass *) |
430 |
cons_mass: inlet.mdot + inlet_heat.mdot = outlet.mdot; |
431 |
|
432 |
m_ratio IS_A factor; |
433 |
inlet_heat.mdot = m_ratio * inlet.mdot; |
434 |
(* cons. energy *) |
435 |
cons_en: inlet.h + m_ratio * inlet_heat.h = outlet.h; |
436 |
METHODS |
437 |
METHOD default_self; |
438 |
RUN inlet.default_self; |
439 |
RUN inlet_heat.default_self; |
440 |
RUN outlet.default_self; |
441 |
END default_self; |
442 |
END heater_open; |
443 |
|
444 |
MODEL heater_open_test REFINES heater_open; |
445 |
cd.component :== 'water'; |
446 |
METHODS |
447 |
METHOD on_load; |
448 |
RUN default_self; |
449 |
FIX inlet.p, inlet.h; |
450 |
inlet.p := 40 {bar}; |
451 |
inlet.h := 634 {kJ/kg}; |
452 |
FIX inlet_heat.h; |
453 |
inlet_heat.h := 2960 {kJ/kg}; |
454 |
|
455 |
FIX outlet.mdot; |
456 |
outlet.mdot := 900 {t/d}; |
457 |
|
458 |
FIX inlet.mdot; |
459 |
inlet.mdot := 700 {t/d}; |
460 |
END on_load; |
461 |
END heater_open_test; |
462 |
|
463 |
MODEL heater_open2; |
464 |
NOTES |
465 |
'block' SELF {Two-heat-inlet open feedwater heater} |
466 |
'port_in' SELF {inlet:0,5-inlet_heat1:3.33,0-inlet_heat2:6.66,0} |
467 |
'port_out' SELF {outlet:10,5} |
468 |
'graphic' SELF {0,0-10,0-10,10-0,10-0,0} |
469 |
END NOTES; |
470 |
|
471 |
inlet "in:" IS_A stream_node; |
472 |
inlet_heat1 "in:" IS_A stream_node; |
473 |
inlet_heat2 "in:" IS_A stream_node; |
474 |
outlet "out:" IS_A stream_node; |
475 |
inlet.cd, inlet_heat1.cd, inlet_heat2.cd, outlet.cd ARE_THE_SAME; |
476 |
inlet_heat1.p, inlet_heat2.p, inlet.p, outlet.p ARE_THE_SAME; |
477 |
cd ALIASES inlet.cd; |
478 |
|
479 |
(* cons. mass *) |
480 |
cons_mass: inlet.mdot + inlet_heat1.mdot + inlet_heat2.mdot = outlet.mdot; |
481 |
|
482 |
(* cons. energy *) |
483 |
cons_en: inlet.mdot * inlet.h + inlet_heat1.mdot * inlet_heat1.h |
484 |
+ inlet_heat2.mdot * inlet_heat2.h = outlet.mdot * outlet.h; |
485 |
METHODS |
486 |
METHOD default_self; |
487 |
RUN inlet.default_self; |
488 |
RUN inlet_heat.default_self; |
489 |
RUN inlet_heat2.default_self; |
490 |
RUN outlet.default_self; |
491 |
END default_self; |
492 |
END heater_open2; |
493 |
|
494 |
MODEL heater_closed; |
495 |
NOTES |
496 |
'block' SELF {Closed feedwater heater model (heat exchanger)} |
497 |
'port_in' SELF {inlet:0,5-inlet_heat:5,0} |
498 |
'port_out' SELF {outlet:10,3.33-outlet_heat:10,6.66} |
499 |
'graphic' SELF {0,0-10,0-10,10-0,10-0,0} |
500 |
END NOTES; |
501 |
|
502 |
inlet "in:" IS_A stream_node; |
503 |
inlet_heat "in:" IS_A stream_node; |
504 |
outlet_heat "out:" IS_A stream_node; |
505 |
outlet "out:" IS_A stream_node; |
506 |
|
507 |
inlet.cd, outlet.cd ARE_THE_SAME; |
508 |
inlet_heat.cd, outlet_heat.cd ARE_THE_SAME; |
509 |
cd ALIASES inlet.cd; |
510 |
cd_heat ALIASES inlet_heat.cd; |
511 |
|
512 |
inlet_heat.p, outlet_heat.p ARE_THE_SAME; |
513 |
inlet.p, outlet.p ARE_THE_SAME; |
514 |
|
515 |
Qdot "heat transferred to main flow stream" IS_A energy_rate; |
516 |
|
517 |
q IS_A specific_energy; |
518 |
Qdot = q * inlet.mdot; |
519 |
|
520 |
(* cons. mass *) |
521 |
cons_mass: inlet.mdot = outlet.mdot; |
522 |
cons_mass_heat: inlet_heat.mdot = outlet_heat.mdot; |
523 |
|
524 |
m_ratio IS_A factor; |
525 |
inlet_heat.mdot = inlet.mdot * m_ratio; |
526 |
|
527 |
(* cons. energy *) |
528 |
cons_en: q + inlet.h = outlet.h; |
529 |
cons_en_heat: m_ratio * inlet_heat.h = m_ratio * outlet_heat.h + q; |
530 |
METHODS |
531 |
METHOD default_self; |
532 |
RUN inlet.default_self; |
533 |
RUN inlet_heat.default_self; |
534 |
RUN outlet.default_self; |
535 |
RUN outlet_heat.default_self; |
536 |
END default_self; |
537 |
END heater_closed; |
538 |
|
539 |
MODEL heater_closed_test REFINES heater_closed; |
540 |
cd.component :== 'water'; |
541 |
cd_heat.component :== 'water'; |
542 |
METHODS |
543 |
METHOD on_load; |
544 |
FIX inlet.p, inlet.h, inlet.mdot; |
545 |
inlet.p := 40 {bar}; |
546 |
inlet.h := 634 {kJ/kg}; |
547 |
inlet.mdot := 700 {t/d}; |
548 |
|
549 |
FIX inlet_heat.p, inlet_heat.h, inlet_heat.mdot; |
550 |
inlet_heat.p := 50 {bar}; |
551 |
inlet_heat.h := 2960 {kJ/kg}; |
552 |
inlet_heat.mdot := 500 {t/d}; |
553 |
|
554 |
FIX outlet.h; |
555 |
outlet.h := 900 {kJ/kg}; |
556 |
|
557 |
SOLVER QRSlv; |
558 |
OPTION convopt 'RELNOM_SCALE'; |
559 |
OPTION iterationlimit 200; |
560 |
END on_load; |
561 |
END heater_closed_test; |
562 |
|
563 |
(*------------------------------------------------------------------------------ |
564 |
TEE PIECE |
565 |
*) |
566 |
|
567 |
(* |
568 |
it's not a car :-) |
569 |
*) |
570 |
MODEL tee; |
571 |
NOTES |
572 |
'block' SELF {Tee piece: branching of flow} |
573 |
'graphic' SELF {0,5-10,3.33-10,6.66-0,5} |
574 |
'port_out' SELF {outlet:10,3.33-outlet_branch:10,6.66} |
575 |
END NOTES; |
576 |
|
577 |
inlet "in:" IS_A stream_node; |
578 |
outlet "out:" IS_A stream_node; |
579 |
outlet_branch "out:" IS_A stream_node; |
580 |
|
581 |
inlet.cd, outlet.cd, outlet_branch.cd ARE_THE_SAME; |
582 |
cd ALIASES inlet.cd; |
583 |
|
584 |
inlet.p, outlet.p, outlet_branch.p ARE_THE_SAME; |
585 |
inlet.h, outlet.h, outlet_branch.h ARE_THE_SAME; |
586 |
|
587 |
(* cons. mass *) |
588 |
cons_mass: inlet.mdot = outlet.mdot + outlet_branch.mdot; |
589 |
|
590 |
phi IS_A fraction; |
591 |
phi_eq: phi * inlet.mdot = outlet_branch.mdot; |
592 |
|
593 |
END tee; |
594 |
|
595 |
(*------------------------------------------------------------------------------ |
596 |
OVERALL CYCLE |
597 |
*) |
598 |
|
599 |
(* |
600 |
simplest possible rankine cycle |
601 |
*) |
602 |
MODEL rankine_common; |
603 |
|
604 |
BO IS_A boiler_simple; |
605 |
TU IS_A turbine_simple; |
606 |
CO IS_A condenser_simple; |
607 |
PU IS_A pump_simple; |
608 |
cd ALIASES BO.cd; |
609 |
|
610 |
BO.outlet, TU.inlet ARE_THE_SAME; |
611 |
TU.outlet, CO.inlet ARE_THE_SAME; |
612 |
CO.outlet, PU.inlet ARE_THE_SAME; |
613 |
PU.outlet, BO.inlet ARE_THE_SAME; |
614 |
|
615 |
Qdot_loss ALIASES CO.Qdot; |
616 |
Wdot IS_A energy_rate; |
617 |
Wdot = TU.Wdot + PU.Wdot; |
618 |
|
619 |
T_H ALIASES BO.outlet.T; |
620 |
T_C ALIASES CO.outlet.T; |
621 |
|
622 |
eta IS_A fraction; |
623 |
eta * (BO.Qdot_fuel) = TU.Wdot + PU.Wdot; |
624 |
|
625 |
eta_carnot IS_A fraction; |
626 |
eta_carnot = 1 - T_C / T_H; |
627 |
|
628 |
DE_cycle "cycle energy balance, should be zero" IS_A energy_rate; |
629 |
DE_cycle = BO.Qdot + CO.Qdot - TU.Wdot - PU.Wdot; |
630 |
|
631 |
mdot ALIASES TU.mdot; |
632 |
x_turb_out ALIASES TU.outlet.x; |
633 |
METHODS |
634 |
METHOD default_self; |
635 |
RUN BO.default_self; |
636 |
RUN TU.default_self; |
637 |
RUN CO.default_self; |
638 |
RUN PU.default_self; |
639 |
END default_self; |
640 |
END rankine_common; |
641 |
|
642 |
|
643 |
MODEL rankine_water REFINES rankine_common; |
644 |
cd.component :== 'water'; |
645 |
cd.type :== 'helmholtz'; |
646 |
METHODS |
647 |
(* first test case: just some plausible values *) |
648 |
METHOD on_load; |
649 |
RUN ClearAll; |
650 |
RUN default_self; |
651 |
FIX BO.eta; BO.eta := 1.0; |
652 |
FIX TU.eta; TU.eta := 0.85; |
653 |
FIX PU.eta; PU.eta := 0.8; |
654 |
FIX Wdot; Wdot := 100 {MW}; |
655 |
(* FIX CO.outlet.p; CO.outlet.p := 10 {kPa};*) |
656 |
FIX CO.outlet.T; CO.outlet.T := 40 {K} + 273.15 {K}; |
657 |
FIX CO.outlet.x; CO.outlet.x := 1e-6; |
658 |
FIX PU.outlet.p; PU.outlet.p := 150 {bar}; |
659 |
PU.outlet.p.upper_bound := 150 {bar}; |
660 |
FIX BO.outlet.T; BO.outlet.T := 580 {K} + 273.15 {K}; |
661 |
|
662 |
SOLVER QRSlv; |
663 |
OPTION convopt 'RELNOM_SCALE'; |
664 |
OPTION iterationlimit 200; |
665 |
END on_load; |
666 |
METHOD set_x_limit; |
667 |
FREE PU.outlet.p; |
668 |
PU.outlet.p.upper_bound := 150 {bar}; |
669 |
FIX TU.outlet.x; TU.outlet.x := 0.9; |
670 |
END set_x_limit; |
671 |
(* |
672 |
second test case: numbers from Example 2.1, K Weston, 'Energy Conversion', |
673 |
1992, http://www.personal.utulsa.edu/~kenneth-weston/ |
674 |
*) |
675 |
METHOD specify; |
676 |
RUN ClearAll; |
677 |
FIX PU.outlet.p; |
678 |
FIX BO.outlet.T; |
679 |
FIX PU.inlet.p; |
680 |
FIX CO.outlet.x; |
681 |
FIX TU.eta; |
682 |
FIX PU.eta; |
683 |
FIX BO.eta; |
684 |
FIX mdot; |
685 |
END specify; |
686 |
METHOD values; |
687 |
PU.outlet.p := 2000 {psi}; |
688 |
BO.outlet.T := 1460 {R}; BO.outlet.h := 3400 {kJ/kg}; |
689 |
PU.inlet.p := 1 {psi}; |
690 |
CO.outlet.x := 1e-6; (*PU.inlet.h := 69.73 {btu/lbm};*) |
691 |
TU.eta := 1.0; |
692 |
PU.eta := 1.0; |
693 |
BO.eta := 1.0; |
694 |
mdot := 900 {t/d}; |
695 |
END values; |
696 |
(* |
697 |
METHOD on_load; |
698 |
RUN default_self; |
699 |
RUN specify; |
700 |
RUN values; |
701 |
|
702 |
SOLVER QRSlv; |
703 |
OPTION convopt 'RELNOM_SCALE'; |
704 |
OPTION iterationlimit 200; |
705 |
END on_load; |
706 |
*) |
707 |
METHOD self_test; |
708 |
(* check the results against those from K Weston's book *) |
709 |
(* note that we have NOT neglected pump work in this case! *) |
710 |
ASSERT abs(eta - 0.4294) < 0.0030; |
711 |
ASSERT abs(eta_carnot - 0.6152) < 0.0005; |
712 |
ASSERT abs(TU.outlet.x - 0.7736) < 0.0005; |
713 |
ASSERT abs(TU.w - 603.1 {btu/lbm}) < 0.7 {btu/lbm}; |
714 |
END self_test; |
715 |
METHOD default_self; |
716 |
RUN rankine_common::default_self; |
717 |
BO.outlet.h := 3000 {kJ/kg}; (* guess *) |
718 |
TU.outlet.h := 3000 {kJ/kg}; (* guess *) |
719 |
CO.outlet.h := 300 {kJ/kg}; |
720 |
CO.outlet.p := 10 {kPa}; |
721 |
END default_self; |
722 |
END rankine_water; |
723 |
|
724 |
MODEL rankine_co2 REFINES rankine_common; |
725 |
cd.component :== 'carbondioxide'; |
726 |
cd.type :== 'helmholtz'; |
727 |
METHODS |
728 |
METHOD on_load_1; |
729 |
RUN ClearAll; |
730 |
RUN default_self; |
731 |
FIX BO.eta; BO.eta := 1.0; |
732 |
FIX TU.eta; TU.eta := 0.85; |
733 |
FIX PU.eta; PU.eta := 0.8; |
734 |
FIX Wdot; Wdot := 100 {MW}; |
735 |
FIX CO.outlet.T; CO.outlet.T := 40 {K} + 273.15 {K}; |
736 |
FIX CO.outlet.p; CO.outlet.p := 80 {bar}; |
737 |
FIX PU.outlet.p; PU.outlet.p := 150 {bar}; |
738 |
FIX BO.outlet.T; BO.outlet.T := 580 {K} + 273.15 {K}; |
739 |
|
740 |
SOLVER QRSlv; |
741 |
OPTION convopt 'RELNOM_SCALE'; |
742 |
OPTION iterationlimit 200; |
743 |
END on_load_1; |
744 |
METHOD on_load; |
745 |
RUN ClearAll; |
746 |
RUN default_self; |
747 |
FIX BO.eta; BO.eta := 1.0; |
748 |
FIX TU.eta; TU.eta := 0.85; |
749 |
FIX PU.eta; PU.eta := 0.8; |
750 |
FIX Wdot; Wdot := 100 {MW}; |
751 |
FIX CO.outlet.T; CO.outlet.T := 10 {K} + 273.15 {K}; |
752 |
FIX CO.outlet.x; CO.outlet.x := 1e-6; |
753 |
FIX PU.outlet.p; PU.outlet.p := 150 {bar}; |
754 |
FIX BO.outlet.T; BO.outlet.T := 580 {K} + 273.15 {K}; |
755 |
|
756 |
SOLVER QRSlv; |
757 |
OPTION convopt 'RELNOM_SCALE'; |
758 |
OPTION iterationlimit 200; |
759 |
END on_load; |
760 |
METHOD default_self; |
761 |
RUN rankine_common::default_self; |
762 |
BO.outlet.h := 350 {kJ/kg}; (* guess *) |
763 |
TU.outlet.h := 1000 {kJ/kg}; (* guess *) |
764 |
CO.outlet.h := 350 {kJ/kg}; |
765 |
CO.outlet.p := 60 {bar}; |
766 |
CO.outlet.p.lower_bound := 5.2 {bar}; |
767 |
END default_self; |
768 |
END rankine_co2; |
769 |
|
770 |
MODEL rankine_toluene REFINES rankine_common; |
771 |
cd.component :== 'toluene'; |
772 |
cd.type :== 'helmholtz'; |
773 |
METHODS |
774 |
METHOD on_load; |
775 |
RUN ClearAll; |
776 |
RUN default_self; |
777 |
FIX BO.eta; BO.eta := 1.0; |
778 |
FIX TU.eta; TU.eta := 0.85; |
779 |
FIX PU.eta; PU.eta := 0.8; |
780 |
FIX Wdot; Wdot := 100 {MW}; |
781 |
FIX CO.outlet.T; CO.outlet.T := 40 {K} + 273.15 {K}; |
782 |
FIX CO.outlet.x; CO.outlet.x := 1e-6; |
783 |
FIX PU.outlet.p; PU.outlet.p := 150 {bar}; |
784 |
FIX BO.outlet.T; BO.outlet.T := 375. {K} + 273.15 {K}; |
785 |
|
786 |
SOLVER QRSlv; |
787 |
OPTION convopt 'RELNOM_SCALE'; |
788 |
OPTION iterationlimit 200; |
789 |
|
790 |
FREE CO.outlet.h; |
791 |
FIX CO.outlet.x; CO.outlet.x := 1e-6; |
792 |
|
793 |
END on_load; |
794 |
METHOD default_self; |
795 |
RUN rankine_common::default_self; |
796 |
PU.inlet.h := 400 {kJ/kg}; |
797 |
BO.outlet.h := 400 {kJ/kg}; |
798 |
CO.outlet.h := 400 {kJ/kg}; |
799 |
CO.outlet.p := 10 {kPa}; |
800 |
END default_self; |
801 |
END rankine_toluene; |
802 |
|
803 |
|
804 |
|
805 |
MODEL rankine_ammonia REFINES rankine_common; |
806 |
cd.component :== 'ammonia'; |
807 |
cd.type :== 'helmholtz'; |
808 |
METHODS |
809 |
METHOD on_load; |
810 |
RUN ClearAll; |
811 |
RUN default_self; |
812 |
FIX BO.eta; BO.eta := 1.0; |
813 |
FIX TU.eta; TU.eta := 0.85; |
814 |
FIX PU.eta; PU.eta := 0.8; |
815 |
FIX Wdot; Wdot := 100 {MW}; |
816 |
FIX CO.outlet.T; CO.outlet.T := 40 {K} + 273.15 {K}; |
817 |
FIX CO.outlet.x; CO.outlet.x := 1e-6; |
818 |
FIX PU.outlet.p; PU.outlet.p := 150 {bar}; |
819 |
FIX BO.outlet.T; BO.outlet.T := 580 {K} + 273.15 {K}; |
820 |
|
821 |
SOLVER QRSlv; |
822 |
OPTION convopt 'RELNOM_SCALE'; |
823 |
OPTION iterationlimit 200; |
824 |
|
825 |
FREE CO.outlet.h; |
826 |
FIX CO.outlet.x; CO.outlet.x := 1e-6; |
827 |
|
828 |
END on_load; |
829 |
METHOD default_self; |
830 |
RUN rankine_common::default_self; |
831 |
PU.inlet.h := 400 {kJ/kg}; |
832 |
BO.outlet.h := 400 {kJ/kg}; |
833 |
CO.outlet.h := 400 {kJ/kg}; |
834 |
CO.outlet.p := 10 {kPa}; |
835 |
END default_self; |
836 |
END rankine_ammonia; |
837 |
|
838 |
|
839 |
|
840 |
(*------------------------------------------------------------------------------ |
841 |
REHEAT RANKINE CYCLE |
842 |
*) |
843 |
MODEL rankine_reheat_common; |
844 |
BO1 IS_A boiler_simple; |
845 |
BO2 IS_A boiler_simple; |
846 |
TU1 IS_A turbine_simple; |
847 |
TU2 IS_A turbine_simple; |
848 |
CO IS_A condenser_simple; |
849 |
PU IS_A pump_simple; |
850 |
|
851 |
BO1.outlet, TU1.inlet ARE_THE_SAME; |
852 |
TU1.outlet, BO2.inlet ARE_THE_SAME; |
853 |
BO2.outlet, TU2.inlet ARE_THE_SAME; |
854 |
TU2.outlet, CO.inlet ARE_THE_SAME; |
855 |
CO.outlet, PU.inlet ARE_THE_SAME; |
856 |
PU.outlet, BO1.inlet ARE_THE_SAME; |
857 |
|
858 |
BO1.eta, BO2.eta ARE_THE_SAME; |
859 |
|
860 |
(* boiler peak temperature is reached for both main and reheat... *) |
861 |
BO1.outlet.T, BO2.outlet.T ARE_THE_SAME; |
862 |
|
863 |
mdot ALIASES PU.mdot; |
864 |
|
865 |
T_H ALIASES BO1.outlet.T; |
866 |
T_C ALIASES CO.outlet.T; |
867 |
|
868 |
eta IS_A fraction; |
869 |
eta * (BO1.Qdot_fuel + BO2.Qdot_fuel) = TU1.Wdot + TU2.Wdot + PU.Wdot; |
870 |
|
871 |
DE_cycle IS_A energy_rate; |
872 |
DE_cycle = BO1.Qdot + BO2.Qdot + CO.Qdot - TU1.Wdot - TU2.Wdot - PU.Wdot; |
873 |
|
874 |
eta_carnot IS_A fraction; |
875 |
eta_carnot = 1 - T_C / T_H; |
876 |
METHODS |
877 |
METHOD default_self; |
878 |
RUN BO1.default_self; |
879 |
RUN BO2.default_self; |
880 |
RUN TU1.default_self; |
881 |
RUN TU2.default_self; |
882 |
RUN CO.default_self; |
883 |
RUN PU.default_self; |
884 |
END default_self; |
885 |
END rankine_reheat_common; |
886 |
|
887 |
(* |
888 |
A model for Rankine cycle with water as the working fluid |
889 |
*) |
890 |
MODEL rankine_reheat_water REFINES rankine_reheat_common; |
891 |
BO1.cd.component :== 'water'; |
892 |
METHODS |
893 |
METHOD on_load; |
894 |
RUN default_self; |
895 |
RUN cengel_ex_10_4; |
896 |
END on_load; |
897 |
METHOD cengel_ex_10_4; |
898 |
(* This example 10.4 from Cengel & Boles, 2011, 'Thermodynamics: An |
899 |
Engineering Approach', 7th Ed., McGraw-Hill. *) |
900 |
RUN ClearAll; |
901 |
RUN default_self; |
902 |
FIX BO1.eta; BO1.eta := 1.0; |
903 |
FIX TU1.eta; TU1.eta := 1.0; |
904 |
FIX TU2.eta; TU2.eta := 1.0; |
905 |
FIX PU.eta; PU.eta := 1.0; |
906 |
|
907 |
FIX TU1.inlet.p; TU1.inlet.p := 15 {MPa}; |
908 |
FIX TU1.inlet.T; TU1.inlet.T := (600 {K} + 273.15 {K}); |
909 |
FIX BO2.outlet.T; BO2.outlet.T := TU1.inlet.T; |
910 |
FIX TU2.outlet.x; TU2.outlet.x := 0.896; |
911 |
FIX CO.inlet.p; CO.inlet.p := 10 {kPa}; |
912 |
FIX CO.outlet.x; CO.outlet.x := 1e-6; |
913 |
FIX mdot; mdot := 1 {kg/s}; |
914 |
END cengel_ex_10_4; |
915 |
METHOD self_test_cengel; |
916 |
ASSERT abs(TU2.outlet.s -7.3688 {kJ/kg/K}) < 0.0001 {kJ/kg/K}; |
917 |
ASSERT abs(TU2.outlet.h - 2335.1 {kJ/kg}) < 0.1 {kJ/kg}; |
918 |
ASSERT abs(BO2.outlet.p - 4.0 {MPa}) < 0.05 {MPa}; |
919 |
ASSERT abs(BO2.outlet.h - 3674.9 {kJ/kg}) < 0.2 {kJ/kg}; |
920 |
ASSERT abs(eta - 0.450) < 0.0005; |
921 |
END self_test_cengel; |
922 |
METHOD default_self; |
923 |
RUN rankine_reheat_common::default_self; |
924 |
BO1.outlet.h := 3000 {kJ/kg}; (* guess *) |
925 |
TU1.outlet.h := 3000 {kJ/kg}; (* guess *) |
926 |
TU2.inlet.h := 3000 {kJ/kg}; (* guess *) |
927 |
END default_self; |
928 |
END rankine_reheat_water; |