/[ascend]/trunk/models/column.a4l
ViewVC logotype

Contents of /trunk/models/column.a4l

Parent Directory Parent Directory | Revision Log Revision Log


Revision 576 - (show annotations) (download) (as text)
Tue May 9 03:42:08 2006 UTC (13 years, 7 months ago) by johnpye
File MIME type: text/x-ascend
File size: 30003 byte(s)
Changed all cases of *.fixed := {TRUE,FALSE} to 'FIX' and 'FREE' statements.
1 REQUIRE "flash.a4l";
2 (* => flash.a4l, stream_holdup.a4l, thermodynamics.a4l, components.a4l,
3 * phases.a4l, atoms.a4l, measures.a4l, system.a4l, basemodel.a4l *)
4 PROVIDE "column.a4l";
5
6 (*
7 * column.a4l
8 * by Ben Allan, Art Westerberg, and Jennifer Perry
9 * Part of the ASCEND Library
10 * $Date: 1998/06/17 18:50:36 $
11 * $Revision: 1.5 $
12 * $Author: mthomas $
13 * $Source: /afs/cs.cmu.edu/project/ascend/Repository/models/column.a4l,v $
14 *
15 * This file is part of the ASCEND Modeling Library.
16 * It defines basic tray-by-tray steady-state distillation models.
17 *
18 * Copyright (C) 1997,1998 Carnegie Mellon University
19 *
20 * The ASCEND Modeling Library is free software; you can redistribute
21 * it and/or modify it under the terms of the GNU General Public
22 * License as published by the Free Software Foundation; either
23 * version 2 of the License, or (at your option) any later version.
24 *
25 * The ASCEND Modeling Library is distributed in hope that it
26 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
27 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
28 * See the GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with the program; if not, write to the Free Software
32 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139 USA. Check
33 * the file named COPYING.
34 *)
35
36 MODEL colmodel() REFINES cmumodel();
37 boundwidth IS_A bound_width;
38 END colmodel;
39
40 MODEL tray_stack(
41 n_trays WILL_BE integer_constant;
42 vapout WILL_BE stream;
43 liqin WILL_BE stream;
44 vapin WILL_BE stream;
45 liqout WILL_BE stream;
46 reduce WILL_BE fraction;
47 equilibrated WILL_BE boolean;
48 ) WHERE (
49 n_trays > 1;
50 vapout, liqin, vapin, liqout WILL_NOT_BE_THE_SAME;
51 vapout.cd, vapin.cd, liqout.cd, liqin.cd WILL_BE_THE_SAME;
52 vapout.pd, vapin.pd WILL_BE_THE_SAME;
53 liqout.pd, liqin.pd WILL_BE_THE_SAME;
54 liqout.pd.phase_indicator == 'L';
55 vapin.pd.phase_indicator == 'V';
56 liqin.pd.phase_indicator == 'L';
57 vapout.pd.phase_indicator == 'V';
58 ) REFINES colmodel();
59
60 NOTES 'ascii-picture'
61 SELF {
62 vapout ^ |
63 | v liqin
64 +---+
65 |_1_|
66 |___| n_trays (at least 2)
67 |___|
68 |_n_|
69 vapin ^ |
70 | v liqout
71 }
72 'usage'
73 equilibrated {
74 When TRUE, enforces equilbrium between phases on all the trays.
75 When FALSE, uses constant alpha between phases on all the trays.
76 }
77 reduce {
78 Homotopy parameter used by reduce_Q to move fixed errors in the
79 energy balances (Qin per tray) toward 0.
80 }
81 'contra-indications' SELF {
82 For a n==1 tray stack, use a "tray" MODEL from the flash library.
83 }
84 END NOTES;
85
86 cd ALIASES liqout.cd;
87 pdL ALIASES liqout.pd;
88 pdV ALIASES vapout.pd;
89 vap_option ALIASES pdV.vapor_option;
90 liq_option ALIASES pdL.liquid1_option;
91 pdVL IS_A phases_data('VL', vap_option, liq_option, 'none');
92
93 (*
94 * The ALIASES/IS_A break if the liqout,vapout are on the same tray.
95 *)
96
97 Tray_set IS_A set OF integer_constant;
98 Tray_set :== [1..n_trays];
99
100 components ALIASES cd.components;
101 phases ALIASES pdVL.phases;
102
103 (* there are alternative ways of building repeated structures.
104 * This is the first one I came up with. It may not be the best.
105 * BAA.
106 *)
107
108 (* build the internal phase mixing rules, and interior stream
109 * states, and interior streams.
110 *)
111 internal_liquid_mixture[1..n_trays-1]
112 IS_A select_mixture_type(cd, liq_option);
113 FOR k IN [1..n_trays-1] CREATE
114 internal_liquid_phase[k]['liquid1'] ALIASES
115 internal_liquid_mixture[k].phase;
116 END FOR;
117 FOR k IN [1..n_trays-1] CREATE
118 internal_liquid_state[k] IS_A
119 thermodynamics(cd, pdL, internal_liquid_phase[k], equilibrated);
120 END FOR;
121 FOR k IN [1..n_trays-1] CREATE
122 internal_liquid_stream[k] IS_A
123 detailed_stream(internal_liquid_state[k]);
124 END FOR;
125 internal_vapor_mixture[2..n_trays]
126 IS_A select_mixture_type(cd, vap_option);
127 FOR k IN [2..n_trays] CREATE
128 internal_vapor_phase[k]['vapor'] ALIASES
129 internal_vapor_mixture[k].phase;
130 END FOR;
131 FOR k IN [2..n_trays] CREATE
132 internal_vapor_state[k] IS_A
133 thermodynamics(cd, pdV, internal_vapor_phase[k], equilibrated);
134 END FOR;
135 FOR k IN [2..n_trays] CREATE
136 internal_vapor_stream[k] IS_A
137 detailed_stream(internal_vapor_state[k]);
138 END FOR;
139
140 (* build tray VLE objects *)
141
142 (* assemble into intermediate, easily accessed arrays *)
143 tray_liquid_mixture[tlTrays] ALIASES
144 (internal_liquid_mixture[1..n_trays-1].phase,
145 liqout.smt['liquid1'].phase)
146 WHERE tlTrays IS_A set OF integer_constant
147 WITH_VALUE (1..n_trays);
148 tray_vapor_mixture[tvTrays] ALIASES
149 (vapout.smt['vapor'].phase,
150 internal_vapor_mixture[2..n_trays].phase)
151 WHERE tvTrays IS_A set OF integer_constant
152 WITH_VALUE (1..n_trays);
153 (* assemble into little pairs for building VLE states *)
154 FOR k IN [Tray_set] CREATE
155 trayVL[k][VLphases[k]] ALIASES
156 (tray_vapor_mixture[k],tray_liquid_mixture[k])
157 WHERE VLphases[k] IS_A set OF symbol_constant
158 WITH_VALUE ('vapor','liquid1');
159 END FOR;
160 (* compile vle of each tray *)
161 FOR k IN [1..n_trays] CREATE
162 tray_state[k] IS_A
163 thermodynamics(cd, pdVL, trayVL[k], equilibrated);
164 END FOR;
165 (* setup
166 * tray_liqin[1..n_trays+1], tray_vapin[0..n_trays],
167 * input streams.
168 *)
169 tray_vapin[tV] ALIASES (vapout.Details,
170 internal_vapor_stream[2..n_trays], vapin.Details)
171 WHERE tV IS_A set OF integer_constant
172 WITH_VALUE (0..n_trays);
173
174 tray_liqin[tL] ALIASES (liqin.Details,
175 internal_liquid_stream[1..n_trays-1], liqout.Details)
176 WHERE tL IS_A set OF integer_constant
177 WITH_VALUE (1..n_trays+1);
178
179 Qin[Tray_set] IS_A energy_rate;
180
181 FOR k IN Tray_set CREATE
182 Stack[k] IS_A detailed_tray(
183 Qin[k],
184 equilibrated,
185 tray_liqin[k],
186 tray_vapin[k],
187 tray_liqin[k+1],
188 tray_vapin[k-1],
189 tray_state[k]
190 );
191 END FOR;
192
193 FOR k IN Tray_set CREATE
194 P[k] ALIASES tray_state[k].P;
195 T[k] ALIASES tray_state[k].T;
196 END FOR;
197
198 METHODS
199
200 METHOD default_all;
201 RUN liqin.default_all;
202 RUN liqout.default_all;
203 RUN vapin.default_all;
204 RUN vapout.default_all;
205 RUN default_self;
206 END default_all;
207
208 METHOD default_self;
209 Qin[Tray_set] := 0{watt};
210 boundwidth := 100;
211 RUN pdVL.default_self;
212 RUN internal_liquid_mixture[1..n_trays-1].default_self;
213 RUN internal_vapor_mixture[2..n_trays].default_self;
214 RUN internal_liquid_state[1..n_trays-1].default_self;
215 RUN internal_vapor_state[2..n_trays].default_self;
216 RUN internal_liquid_stream[1..n_trays-1].default_self;
217 RUN internal_vapor_stream[2..n_trays].default_self;
218 RUN tray_state[Tray_set].default_self;
219 Stack[Tray_set].flowscale := 10{mole/second};
220 Stack[Tray_set].H_flowscale := 1000{J/second};
221 END default_self;
222
223 METHOD check_all;
224 RUN liqin.check_all;
225 RUN liqout.check_all;
226 RUN vapin.check_all;
227 RUN vapout.check_all;
228 RUN check_self;
229 END check_all;
230
231 METHOD check_self;
232 RUN pdVL.check_self;
233 RUN internal_liquid_mixture[1..n_trays-1].check_self;
234 RUN internal_vapor_mixture[2..n_trays].check_self;
235 RUN internal_liquid_state[1..n_trays-1].check_self;
236 RUN internal_vapor_state[2..n_trays].check_self;
237 RUN internal_liquid_stream[1..n_trays-1].check_self;
238 RUN internal_vapor_stream[2..n_trays].check_self;
239 RUN tray_state[Tray_set].check_self;
240 END check_self;
241
242 METHOD scale_all;
243 RUN liqin.scale_all;
244 RUN liqout.scale_all;
245 RUN vapin.scale_all;
246 RUN vapout.scale_all;
247 RUN scale_self;
248 END scale_all;
249
250 METHOD scale_self;
251 (* fortunately no local equations to scale *)
252 RUN pdVL.scale_self;
253 RUN internal_liquid_mixture[1..n_trays-1].scale_self;
254 RUN internal_vapor_mixture[2..n_trays].scale_self;
255 RUN internal_liquid_state[1..n_trays-1].scale_self;
256 RUN internal_vapor_state[2..n_trays].scale_self;
257 RUN internal_liquid_stream[1..n_trays-1].scale_self;
258 RUN internal_vapor_stream[2..n_trays].scale_self;
259 RUN tray_state[Tray_set].scale_self;
260 END scale_self;
261
262 METHOD bound_all;
263 RUN liqin.bound_all;
264 RUN liqout.bound_all;
265 RUN vapin.bound_all;
266 RUN vapout.bound_all;
267 RUN bound_self;
268 END bound_all;
269
270 METHOD bound_self;
271 (* fortunately no local variables to scale *)
272 RUN pdVL.bound_self;
273
274 internal_liquid_mixture[1..n_trays-1].boundwidth := boundwidth;
275 internal_vapor_mixture[2..n_trays].boundwidth := boundwidth;
276 internal_liquid_state[1..n_trays-1].boundwidth := boundwidth;
277 internal_vapor_state[2..n_trays].boundwidth := boundwidth;
278 internal_liquid_stream[1..n_trays-1].boundwidth := boundwidth;
279 internal_vapor_stream[2..n_trays].boundwidth := boundwidth;
280 tray_state[Tray_set].boundwidth := boundwidth;
281
282 RUN internal_liquid_mixture[1..n_trays-1].bound_self;
283 RUN internal_vapor_mixture[2..n_trays].bound_self;
284 RUN internal_liquid_state[1..n_trays-1].bound_self;
285 RUN internal_vapor_state[2..n_trays].bound_self;
286 RUN internal_liquid_stream[1..n_trays-1].bound_self;
287 RUN internal_vapor_stream[2..n_trays].bound_self;
288 RUN tray_state[Tray_set].bound_self;
289
290 END bound_self;
291
292 METHOD specify;
293 RUN seqmod;
294 RUN liqin.specify;
295 RUN vapin.specify;
296 END specify;
297
298 METHOD seqmod;
299 RUN Stack[Tray_set].seqmod;
300 END seqmod;
301
302 METHOD scale;
303 RUN Stack[Tray_set].scale;
304 END scale;
305
306 METHOD reset_to_mass_balance;
307 equilibrated := FALSE;
308 RUN reset;
309 END reset_to_mass_balance;
310
311 METHOD reset_to_full_thermo;
312 equilibrated := TRUE;
313 RUN reset;
314 END reset_to_full_thermo;
315
316 METHOD reset_to_adiabatic;
317 RUN reset_to_full_thermo;
318 FREE Stack[Tray_set].cmo_ratio;
319 FIX Stack[Tray_set].Qin;
320 Stack[Tray_set].Qin := 0{W};
321 END reset_to_adiabatic;
322
323 METHOD reduce_Q;
324 FOR j IN [Tray_set] DO
325 Stack[j].Qin := reduce * Stack[j].Qin;
326 END FOR;
327 END reduce_Q;
328
329 END tray_stack;
330
331 MODEL test_tray_stack() REFINES testcmumodel();
332 n_trays_below IS_A integer_constant;
333 n_trays_below :== 2;
334 equilibrated IS_A start_false;
335 reduce IS_A fraction;
336
337 NOTES
338 'usage' equilibrated {
339 This variable and feed.equilibrated may or may not be the same.
340 Do not assume they are when writing methods.
341 }
342 reduce {
343 This is a fraction from 0 to 1. The method reduce_Q uses it
344 to move the Qin on each stack and feed tray toward 0.
345 Essentially this is a physical homotopy parameter.
346 }
347 END NOTES;
348
349
350 cd IS_A components_data(['n_pentane','n_hexane','n_heptane'],
351 'n_heptane');
352 pdV IS_A phases_data('V', 'Pitzer_vapor_mixture', 'none', 'none');
353 pdL IS_A phases_data('L', 'none', 'UNIFAC_liquid_mixture', 'none');
354
355 Vapout IS_A stream(cd, pdV, equilibrated);
356 Liqin IS_A stream(cd, pdL, equilibrated);
357 Vapin IS_A stream(cd, pdV, equilibrated);
358 Liqout IS_A stream(cd, pdL, equilibrated);
359
360 Section IS_A tray_stack(
361 n_trays_below,
362 Vapout,
363 Liqin,
364 Vapin,
365 Liqout,
366 reduce,
367 equilibrated
368 );
369
370 METHODS
371
372 METHOD default_all;
373 RUN default_self;
374 END default_all;
375 METHOD default_self;
376 equilibrated := FALSE;
377 RUN Section.default_self;
378 END default_self;
379
380 METHOD check_all;
381 RUN check_self;
382 END check_all;
383
384 METHOD check_self;
385 RUN Section.check_all;
386 END check_self;
387
388 METHOD bound_all;
389 RUN bound_self;
390 END bound_all;
391
392 METHOD bound_self;
393 RUN Section.bound_self;
394 END bound_self;
395
396 METHOD scale_all;
397 RUN scale_self;
398 END scale_all;
399
400 METHOD scale_self;
401 RUN Section.scale_self;
402 END scale_self;
403
404 METHOD specify;
405 RUN Section.specify;
406 END specify;
407
408 METHOD reset_to_adiabatic;
409 RUN Section.reset_to_adiabatic;
410 END reset_to_adiabatic;
411 END test_tray_stack;
412
413
414 MODEL simple_column(
415 pdVL WILL_BE phases_data;
416 distillate WILL_BE stream;
417 n_trays_above WILL_BE integer_constant;
418 feed WILL_BE stream;
419 n_trays_below WILL_BE integer_constant;
420 bottoms WILL_BE stream;
421 equilibrated WILL_BE boolean;
422 reduce WILL_BE fraction;
423 ) WHERE (
424 n_trays_above > 1;
425 n_trays_below > 1;
426 distillate, bottoms, feed WILL_NOT_BE_THE_SAME;
427 feed.cd, distillate.cd, bottoms.cd WILL_BE_THE_SAME;
428 pdVL.phase_indicator == 'VL';
429 distillate.pd, bottoms.pd WILL_BE_THE_SAME;
430 distillate.pd.phase_indicator == 'L';
431 pdVL.liquid1_option == distillate.pd.liquid1_option;
432 feed.pd.phase_indicator IN ['V','L','VL'] == TRUE;
433 ) REFINES colmodel();
434
435 NOTES
436 'ascii-picture' SELF {
437 ___ total condenser
438 / \________> distillate liquid
439 |___|
440 (condenser_vapin)^ |
441 | |
442 | v(rectifier_liqin)
443 +---+
444 |___|
445 |___| n_trays_above (at least 2)
446 |___|
447 |___|
448 (rectifier_vapin)^ |
449 | |
450 | v(feed_tray_liqin)
451 +---+
452 V/L feed ----->| |
453 +___+
454 (feed_tray_vapin)^ |
455 | |
456 | v(stripper_liqin)
457 +---+
458 |___|
459 |___| n_trays_below (at least 2)
460 |___|
461 |___|
462 (stripper_vapin)^ |
463 | |
464 | v(reboiler_liqin)
465 ___
466 | |________> bottoms liquid
467 \___/ non-adiabatic flash
468 }
469 'usage' equilibrated {
470 This variable and feed.equilibrated may or may not be the same.
471 Do not assume they are when writing methods.
472 }
473 reduce {
474 This is a fraction from 0 to 1. The method reduce_Q uses it
475 to move the Qin on each stack and feed tray toward 0.
476 Essentially this is a physical homotopy parameter.
477 }
478 'changing' SELF {
479 This MODEL is very large, therefore it is very carefully
480 structured following the ascii-picture.
481 It should be relatively easy to modify this MODEL
482 just by carefully following the patterns we use. The pattern is
483 that all streams are given names corresponding to their input
484 roles.
485
486 You can build arbitrarily complicated columns with bypasses,
487 recycles, intercoolers, etc just by copying this MODEL
488 and rerouting section or tray connections after adding or
489 removing sections, exchangers, and so forth.
490 }
491 END NOTES;
492
493 (*
494 * The creation steps:
495 * alias the options from the feed stream. (done above).
496 * inter-section streams (single phase)
497 * column sections
498 * At the end of the steps, everything has been wired up
499 * simply by passing common parts to both places they belong.
500 * For clarity, no arrays are used.
501 *
502 * If you are nuts enough to reimplement this MODEL using
503 * arrays, have a look at tray_stack for techniques to avoid
504 * sending the compiler to hell.
505 *
506 * The thermodynamic options of the given pdVL
507 * column without using ARE_ALIKE or ARE_THE_SAME.
508 *)
509
510 pdL ALIASES bottoms.pd;
511 pdV IS_A phases_data('V', pdVL.vapor_option, 'none', 'none');
512 cd ALIASES feed.cd;
513 components ALIASES feed.components;
514
515 (* inter-section streams *)
516 condenser_vapin "vapor rising to condenser",
517 rectifier_vapin "vapor rising from feed tray",
518 feed_tray_vapin "vapor rising from stripper",
519 stripper_vapin "vapor rising from reboiler"
520 IS_A stream(cd, pdV, equilibrated);
521
522 rectifier_liqin "reflux condensate",
523 feed_tray_liqin "liquid falling from rectifier",
524 stripper_liqin "liquid falling from feed tray",
525 reboiler_liqin "liquid falling to reboiler"
526 IS_A stream(cd, pdL, equilibrated);
527
528 (* typical heat duties *)
529 Qin_condenser "condenser duty",
530 Qin_feed "feed heater duty",
531 Qin_reboiler "reboiler duty" IS_A energy_rate;
532
533 (* column sections *)
534 condenser IS_A total_condenser(
535 Qin_condenser,
536 condenser_vapin,
537 rectifier_liqin,
538 distillate
539 );
540 rectifying_section "the trays above the feed" IS_A tray_stack(
541 n_trays_above,
542 condenser_vapin,
543 rectifier_liqin,
544 rectifier_vapin,
545 feed_tray_liqin,
546 reduce,
547 equilibrated
548 );
549 feed_tray IS_A feed_tray(
550 Qin_feed,
551 equilibrated,
552 feed,
553 feed_tray_liqin,
554 feed_tray_vapin,
555 stripper_liqin,
556 rectifier_vapin
557 );
558 stripping_section "the trays below the feed" IS_A tray_stack(
559 n_trays_below,
560 feed_tray_vapin,
561 stripper_liqin,
562 stripper_vapin,
563 reboiler_liqin,
564 reduce,
565 equilibrated
566 );
567 reboiler IS_A simple_reboiler(
568 Qin_reboiler,
569 equilibrated,
570 reboiler_liqin,
571 stripper_vapin,
572 bottoms
573 );
574
575 (* this array has the common type flash_base,
576 * so it is mainly useful for methods.
577 *)
578 Tray[zTr] ALIASES (
579 condenser,
580 rectifying_section.Stack[1..n_trays_above],
581 feed_tray,
582 stripping_section.Stack[1..n_trays_below],
583 reboiler)
584 WHERE zTr IS_A set OF integer_constant
585 WITH_VALUE (0..N_trays);
586
587 (* useful things to know from an END user perspective *)
588 N_trays IS_A integer_constant;
589 N_trays :== n_trays_above + 1 + n_trays_below + 1;
590 VLE_set IS_A set OF integer_constant;
591 VLE_set :== [1 .. N_trays];
592 Feed_loc IS_A integer_constant;
593 Feed_loc :== n_trays_above +1;
594
595 (* why is this here? total reflux? *)
596 omb_slack[components] IS_A molar_rate;
597 FOR i IN components CREATE
598 overall_mass_balance[i]:
599 feed.f[i] = (distillate.f[i] + bottoms.f[i] + omb_slack[i]);
600 END FOR;
601
602 METHODS
603
604 METHOD default_self;
605 omb_slack[components] := 0 {mol/s};
606 omb_slack[components].lower_bound := -1000{mole/s};
607 RUN condenser.default_self;
608 RUN rectifying_section.default_self;
609 RUN feed_tray.default_self;
610 RUN stripping_section.default_self;
611 RUN reboiler.default_self;
612 END default_self;
613
614 METHOD default_all;
615 RUN pdVL.default_all;
616 RUN distillate.default_all;
617 RUN feed.default_all;
618 RUN bottoms.default_all;
619 RUN default_self;
620 END default_all;
621
622 METHOD check_all;
623 RUN check_self;
624 RUN pdVL.check_all;
625 RUN distillate.check_all;
626 RUN feed.check_all;
627 RUN bottoms.check_all;
628 END check_all;
629
630 METHOD check_self;
631 FOR i IN components DO
632 IF ( omb_slack[i]/feed.flow.nominal > 1.0e-4 ) THEN
633 STOP {Column violates over-all species balance};
634 END IF;
635 END FOR;
636 RUN pdV.check_self;
637 RUN condenser_vapin.check_self;
638 RUN rectifier_vapin.check_self;
639 RUN feed_tray_vapin.check_self;
640 RUN stripper_vapin.check_self;
641 RUN rectifier_liqin.check_self;
642 RUN feed_tray_liqin.check_self;
643 RUN stripper_liqin.check_self;
644 RUN reboiler_liqin.check_self;
645 RUN condenser.check_self;
646 RUN rectifying_section.check_self;
647 RUN feed_tray.check_self;
648 RUN stripping_section.check_self;
649 RUN reboiler.check_self;
650 END check_self;
651
652 METHOD scale_all;
653 RUN pdVL.scale_all;
654 RUN distillate.scale_all;
655 RUN feed.scale_all;
656 RUN bottoms.scale_all;
657 RUN scale_self;
658 END scale_all;
659
660 METHOD scale_self;
661 RUN pdV.scale_self;
662 RUN condenser_vapin.scale_self;
663 RUN rectifier_vapin.scale_self;
664 RUN feed_tray_vapin.scale_self;
665 RUN stripper_vapin.scale_self;
666 RUN rectifier_liqin.scale_self;
667 RUN feed_tray_liqin.scale_self;
668 RUN stripper_liqin.scale_self;
669 RUN reboiler_liqin.scale_self;
670 RUN condenser.scale_self;
671 RUN rectifying_section.scale_self;
672 RUN feed_tray.scale_self;
673 RUN stripping_section.scale_self;
674 RUN reboiler.scale_self;
675 END scale_self;
676
677 METHOD bound_all;
678 RUN pdVL.bound_all;
679 RUN distillate.bound_all;
680 RUN feed.bound_all;
681 RUN bottoms.bound_all;
682 RUN bound_self;
683 END bound_all;
684
685 METHOD bound_self;
686 RUN pdV.bound_self;
687 RUN condenser_vapin.bound_self;
688 RUN rectifier_vapin.bound_self;
689 RUN feed_tray_vapin.bound_self;
690 RUN stripper_vapin.bound_self;
691 RUN rectifier_liqin.bound_self;
692 RUN feed_tray_liqin.bound_self;
693 RUN stripper_liqin.bound_self;
694 RUN reboiler_liqin.bound_self;
695 RUN condenser.bound_self;
696 RUN rectifying_section.bound_self;
697 RUN feed_tray.bound_self;
698 RUN stripping_section.bound_self;
699 RUN reboiler.bound_self;
700 END bound_self;
701
702 METHOD seqmod;
703 RUN condenser.seqmod;
704 RUN rectifying_section.seqmod;
705 RUN feed_tray.seqmod;
706 RUN stripping_section.seqmod;
707 RUN reboiler.seqmod;
708 END seqmod;
709
710 METHOD specify;
711 RUN seqmod;
712 RUN feed.specify;
713 IF (feed.equilibrated AND (feed.pd.phase_indicator == 'VL')) THEN
714 FREE feed.Details.state.phase[feed.pd.reference_phase].T;
715 FIX feed.Details.state.phase_fraction[feed.pd.other_phases];
716 END IF;
717 END specify;
718
719 METHOD reset_to_mass_balance;
720 equilibrated := FALSE;
721 feed.state.equilibrated := FALSE;
722 RUN reset;
723 END reset_to_mass_balance;
724
725 METHOD reset_to_full_thermo;
726 equilibrated := TRUE;
727 feed.state.equilibrated := TRUE;
728 RUN reset;
729 END reset_to_full_thermo;
730
731 METHOD reset_to_adiabatic;
732 RUN reset_to_full_thermo;
733 (* condenser, reboiler Qin left free *)
734 FREE rectifying_section.Stack[1..n_trays_above].cmo_ratio;
735 FREE stripping_section.Stack[1..n_trays_below].cmo_ratio;
736 FIX Tray[1..N_trays-1].Qin;
737 Tray[1..N_trays-1].Qin := 0{W};
738 FREE feed_tray.q;
739 END reset_to_adiabatic;
740
741 METHOD propagate_feed_values;
742 (* propagate feed tray flows and relative volatilities,
743 * after solving the feed tray.
744 *)
745 FOR i IN components DO
746 (* use feed alpha everywhere *)
747 Tray[VLE_set].alpha[i] := feed_tray.alpha[i];
748 (* copy feed flow rates to all internal streams *)
749 (* This copying should factor in the RR and BR *)
750 Tray[0..N_trays-1].liqout.f[i] := feed.f[i];
751 Tray[1..N_trays].vapout.f[i] := feed.f[i];
752 END FOR;
753 END propagate_feed_values;
754
755 END simple_column;
756
757 MODEL simple_column_profiles(
758 sc WILL_BE simple_column;
759 ) REFINES colmodel();
760
761 traynum[sc.VLE_set] IS_A integer_constant;
762 FOR i IN sc.VLE_set CREATE
763 traynum[i] :== i;
764 END FOR;
765
766 cmo_ratio[zc] ALIASES (
767 sc.rectifying_section.Stack[1..sc.n_trays_above].cmo_ratio,
768 sc.stripping_section.Stack[1..sc.n_trays_below].cmo_ratio)
769 WHERE zc IS_A set OF integer_constant
770 WITH_VALUE ( 1 .. sc.n_trays_above,
771 sc.Feed_loc+1 .. sc.Feed_loc+sc.n_trays_below);
772
773 P[zP] ALIASES (
774 sc.rectifying_section.P[1..sc.n_trays_above],
775 sc.feed_tray.P,
776 sc.stripping_section.P[1..sc.n_trays_below],
777 sc.reboiler.P)
778 WHERE zP IS_A set OF integer_constant WITH_VALUE (sc.VLE_set);
779
780 T[zT] ALIASES (
781 sc.rectifying_section.T[1..sc.n_trays_above],
782 sc.feed_tray.T,
783 sc.stripping_section.T[1..sc.n_trays_below],
784 sc.reboiler.T)
785 WHERE zT IS_A set OF integer_constant WITH_VALUE (sc.VLE_set);
786
787 (* next one is simple because flash_base defines Qin *)
788 Qin[zQ] ALIASES (sc.Tray[0..sc.N_trays].Qin)
789 WHERE zQ IS_A set OF integer_constant WITH_VALUE (0..sc.N_trays);
790
791 Lin[zL] ALIASES (
792 sc.rectifying_section.tray_liqin[1..sc.n_trays_above].flow,
793 sc.feed_tray.liqin.flow,
794 sc.stripping_section.tray_liqin[1..sc.n_trays_below].flow,
795 sc.reboiler.liqin.flow)
796 WHERE zL IS_A set OF integer_constant WITH_VALUE (sc.VLE_set);
797
798 Vin[zV] ALIASES (
799 sc.rectifying_section.tray_vapin[0..sc.n_trays_above].flow,
800 sc.feed_tray.vapin.flow,
801 sc.stripping_section.tray_vapin[1..sc.n_trays_below].flow)
802 WHERE zV IS_A set OF integer_constant WITH_VALUE (0..sc.N_trays-1);
803
804 FOR i IN sc.components CREATE
805
806 x[i][zx[i]] ALIASES (
807 sc.rectifying_section.Stack[1..sc.n_trays_above].x[i],
808 sc.feed_tray.x[i],
809 sc.stripping_section.Stack[1..sc.n_trays_below].x[i],
810 sc.reboiler.x[i])
811 WHERE zx[i] IS_A set OF integer_constant WITH_VALUE (sc.VLE_set);
812
813 y[i][zy[i]] ALIASES (
814 sc.rectifying_section.Stack[1..sc.n_trays_above].y[i],
815 sc.feed_tray.y[i],
816 sc.stripping_section.Stack[1..sc.n_trays_below].y[i],
817 sc.reboiler.y[i])
818 WHERE zy[i] IS_A set OF integer_constant WITH_VALUE (sc.VLE_set);
819
820 kvalues_when_full_thermo[i][zk[i]] ALIASES (
821 sc.rectifying_section.Stack[1..sc.n_trays_above].alpha[i],
822 sc.feed_tray.alpha[i],
823 sc.stripping_section.Stack[1..sc.n_trays_below].alpha[i],
824 sc.reboiler.alpha[i])
825 WHERE zk[i] IS_A set OF integer_constant WITH_VALUE (sc.VLE_set);
826
827 END FOR (* components *);
828
829 METHODS
830 (* This MODEL defines no new equations, variables, or submodels *)
831 (* so we put in a bunch of harmless methods so the system defined
832 * ones get replaced.
833 *)
834 METHOD check_self;
835 END check_self;
836 METHOD check_all;
837 END check_all;
838 METHOD default_self;
839 END default_self;
840 METHOD default_all;
841 END default_all;
842 METHOD scale_self;
843 END scale_self;
844 METHOD scale_all;
845 END scale_all;
846 METHOD bound_self;
847 END bound_self;
848 METHOD bound_all;
849 END bound_all;
850 METHOD specify;
851 END specify;
852
853 END simple_column_profiles;
854
855
856 MODEL test_simple_column() REFINES testcmumodel();
857
858 cd IS_A components_data(
859 ['n_pentane','n_hexane','n_heptane'], 'n_heptane'
860 );
861 pdVL IS_A phases_data('VL','Pitzer_vapor_mixture',
862 'UNIFAC_liquid_mixture','none');
863 pdV IS_A phases_data('V','Pitzer_vapor_mixture','none','none');
864 pdL IS_A phases_data('L','none','UNIFAC_liquid_mixture','none');
865
866
867 Feed_equil, Equilibrated IS_A start_false;
868 Feed IS_A stream(cd, pdVL, Feed_equil);
869 Distillate IS_A stream(cd, pdL, Equilibrated);
870 Bottoms IS_A stream(cd, pdL, Equilibrated);
871
872 n_trays_above, n_trays_below IS_A integer_constant;
873 n_trays_above :== 6;
874 n_trays_below :== 5;
875 reduce IS_A fraction;
876 Column IS_A simple_column(
877 pdVL,
878 Distillate,
879 n_trays_above,
880 Feed,
881 n_trays_below,
882 Bottoms,
883 Equilibrated,
884 reduce
885 );
886
887 Profile IS_A simple_column_profiles(Column);
888 boundwidth IS_A bound_width;
889
890 METHODS
891
892 METHOD default_self;
893 boundwidth := 100;
894 RUN Feed.default_self;
895 RUN Distillate.default_self;
896 RUN Bottoms.default_self;
897 RUN Column.default_self;
898 RUN Profile.default_self;
899 END default_self;
900
901 METHOD check_self;
902 RUN Feed.check_self;
903 RUN Distillate.check_self;
904 RUN Bottoms.check_self;
905 RUN Column.check_self;
906 RUN Profile.check_self;
907 END check_self;
908
909 METHOD scale_self;
910 RUN Feed.scale_self;
911 RUN Distillate.scale_self;
912 RUN Bottoms.scale_self;
913 RUN Column.scale_self;
914 RUN Profile.scale_self;
915 END scale_self;
916
917 METHOD bound_self;
918 Column.boundwidth := boundwidth;
919 Profile.boundwidth := boundwidth;
920 Feed.boundwidth := boundwidth;
921 Distillate.boundwidth := boundwidth;
922 Bottoms.boundwidth := boundwidth;
923 RUN Feed.bound_self;
924 RUN Distillate.bound_self;
925 RUN Bottoms.bound_self;
926 RUN Column.bound_self;
927 RUN Profile.bound_self;
928 END bound_self;
929
930 METHOD bound_all;
931 RUN bound_self;
932 END bound_all;
933
934 METHOD scale_all;
935 RUN scale_self;
936 END scale_all;
937
938 METHOD check_all;
939 RUN check_self;
940 END check_all;
941
942 METHOD default_all;
943 RUN default_self;
944 END default_all;
945
946 METHOD values;
947 Column.feed_tray.alpha['n_pentane'] := 3;
948 Column.feed_tray.alpha['n_hexane'] := 2;
949 Column.feed_tray.alpha['n_heptane'] := 1;
950 Column.condenser.reflux_ratio := 1.3;
951 Feed.T := 298 {K};
952 Feed.P := 1{atm};
953 Feed.f['n_pentane'] := 3{mole/s};
954 Feed.f['n_hexane'] := 3{mole/s};
955 Feed.f['n_heptane'] := 3{mole/s};
956 (* here we should SOLVE the feed tray *)
957 RUN Column.propagate_feed_values;
958 END values;
959
960 END test_simple_column;
961
962 MODEL demo_column(
963 components IS_A set OF symbol_constant;
964 reference IS_A symbol_constant;
965 n_trays IS_A integer_constant;
966 feed_location IS_A integer_constant;
967 ) WHERE (
968 reference IN components == TRUE;
969 n_trays > 5;
970 feed_location > 2;
971 feed_location < n_trays - 2;
972 ) REFINES colmodel();
973
974 cd IS_A components_data(components,reference);
975 pdVL IS_A phases_data('VL','Pitzer_vapor_mixture',
976 'UNIFAC_liquid_mixture','none');
977 pdV IS_A phases_data('V','Pitzer_vapor_mixture','none','none');
978 pdL IS_A phases_data('L','none','UNIFAC_liquid_mixture','none');
979
980 Equilibrated IS_A start_false;
981 Feed IS_A stream(cd, pdVL, Equilibrated);
982 Distillate IS_A stream(cd, pdL, Equilibrated);
983 Bottoms IS_A stream(cd, pdL, Equilibrated);
984
985 n_trays_above, n_trays_below IS_A integer_constant;
986 n_trays_above :== feed_location - 1;
987 n_trays_below :== n_trays - feed_location - 1;
988 reduce IS_A fraction;
989 Column IS_A simple_column(
990 pdVL,
991 Distillate,
992 n_trays_above,
993 Feed,
994 n_trays_below,
995 Bottoms,
996 Equilibrated,
997 reduce
998 );
999
1000 (* component names in order of boiling point. useful for methods. *)
1001 z_boiling_comp[1..CARD[components]] IS_A symbol;
1002 z_bc IS_A symbol;
1003 z_bi IS_A integer;
1004
1005 METHODS
1006
1007 METHOD default_self;
1008 boundwidth := 100;
1009 RUN Feed.default_self;
1010 RUN Distillate.default_self;
1011 RUN Bottoms.default_self;
1012 RUN Column.default_self;
1013 END default_self;
1014
1015 METHOD check_self;
1016 RUN Feed.check_self;
1017 RUN Distillate.check_self;
1018 RUN Bottoms.check_self;
1019 RUN Column.check_self;
1020 END check_self;
1021
1022 METHOD scale_self;
1023 RUN Feed.scale_self;
1024 RUN Distillate.scale_self;
1025 RUN Bottoms.scale_self;
1026 RUN Column.scale_self;
1027 END scale_self;
1028
1029 METHOD bound_self;
1030 Column.boundwidth := boundwidth;
1031 Feed.boundwidth := boundwidth;
1032 Distillate.boundwidth := boundwidth;
1033 Bottoms.boundwidth := boundwidth;
1034 RUN Feed.bound_self;
1035 RUN Distillate.bound_self;
1036 RUN Bottoms.bound_self;
1037 RUN Column.bound_self;
1038 END bound_self;
1039
1040 METHOD bound_all;
1041 RUN bound_self;
1042 END bound_all;
1043
1044 METHOD scale_all;
1045 RUN scale_self;
1046 END scale_all;
1047
1048 METHOD check_all;
1049 RUN check_self;
1050 END check_all;
1051
1052 METHOD default_all;
1053 RUN default_self;
1054 END default_all;
1055
1056 METHOD values;
1057 (* The demo user may very well want to rewrite this method
1058 * for their particular mixture.
1059 *)
1060 z_bi := 1;
1061 (* order the components arbitrarily in a list *)
1062 FOR i IN components DO
1063 z_boiling_comp[z_bi] := i;
1064 z_bi := z_bi + 1;
1065 END FOR;
1066 (* use a bubble point sort, pun intended, to order the components. *)
1067 FOR i IN [1..CARD[components]-1] DO
1068 FOR j IN [i+1 .. CARD[components]] DO
1069 IF cd.data[z_boiling_comp[i]].Tb >
1070 cd.data[z_boiling_comp[j]].Tb THEN
1071 z_bc := z_boiling_comp[j];
1072 z_boiling_comp[j] := z_boiling_comp[i];
1073 z_boiling_comp[i] := z_bc;
1074 END IF;
1075 END FOR;
1076 END FOR;
1077 z_bi := 1;
1078 (* assign close alpha's *)
1079 FOR i IN [1.. CARD[components]] DO
1080 Column.feed_tray.alpha[z_boiling_comp[i]] :=
1081 1+ 1.0*(CARD[components]-i+1); (* 1.0 here --> 0.2 *)
1082 IF (Feed.pd.phase_indicator == 'VL') THEN
1083 Feed.state.phase['vapor'].alpha[z_boiling_comp[i]] :=
1084 Column.feed_tray.alpha[z_boiling_comp[i]];
1085 END IF;
1086 END FOR;
1087 Column.condenser.reflux_ratio := 1.3;
1088 Feed.T := 298 {K};
1089 Feed.P := 1{atm};
1090 Feed.f[components] := 3{mole/s};
1091 RUN Column.propagate_feed_values;
1092 END values;
1093
1094 END demo_column;
1095
1096
1097 MODEL test_demo_column() REFINES testcmumodel();
1098
1099 METHODS
1100 METHOD check_self;
1101 RUN demo.check_self;
1102 END check_self;
1103 METHOD check_all;
1104 RUN demo.check_all;
1105 END check_all;
1106 METHOD default_self;
1107 RUN demo.default_self;
1108 END default_self;
1109 METHOD default_all;
1110 RUN demo.scale_all;
1111 END default_all;
1112 METHOD scale_self;
1113 RUN demo.scale_self;
1114 END scale_self;
1115 METHOD scale_all;
1116 RUN demo.scale_all;
1117 END scale_all;
1118 METHOD bound_self;
1119 RUN demo.bound_self;
1120 END bound_self;
1121 METHOD bound_all;
1122 RUN demo.bound_all;
1123 END bound_all;
1124
1125 METHOD specify;
1126 RUN demo.specify;
1127 END specify;
1128
1129 METHOD values;
1130 RUN demo.values;
1131 END values;
1132
1133 METHOD reset_to_mass_balance;
1134 RUN demo.Column.reset_to_mass_balance;
1135 END reset_to_mass_balance;
1136
1137 METHOD reset_to_full_thermo;
1138 RUN demo.Column.reset_to_full_thermo;
1139 END reset_to_full_thermo;
1140
1141 METHOD reset_to_adiabatic;
1142 RUN demo.Column.reset_to_adiabatic;
1143 END reset_to_adiabatic;
1144
1145 END test_demo_column;
1146
1147 MODEL mw_demo_column() REFINES test_demo_column();
1148 demo IS_A demo_column(['methanol','water'],'water',13,7);
1149 METHODS
1150 END mw_demo_column;
1151
1152 MODEL abc_demo_column() REFINES test_demo_column();
1153 demo IS_A
1154 demo_column(['benzene','chloroform','acetone'],'benzene',13,7);
1155 METHODS
1156 END abc_demo_column;
1157
1158 MODEL c567_demo_column() REFINES test_demo_column();
1159 demo IS_A
1160 demo_column(['n_pentane','n_hexane','n_heptane'],'n_heptane',13,7);
1161 METHODS
1162 END c567_demo_column;

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22