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