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

Contents of /trunk/models/column.a4l

Parent Directory Parent Directory | Revision Log Revision Log


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

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