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

Annotation of /trunk/models/column.a4l

Parent Directory Parent Directory | Revision Log Revision Log


Revision 576 - (hide annotations) (download) (as text)
Tue May 9 03:42:08 2006 UTC (18 years, 1 month 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 aw0a 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 johnpye 576 FREE Stack[Tray_set].cmo_ratio;
319     FIX Stack[Tray_set].Qin;
320 aw0a 1 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 johnpye 576 FREE feed.Details.state.phase[feed.pd.reference_phase].T;
715     FIX feed.Details.state.phase_fraction[feed.pd.other_phases];
716 aw0a 1 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 johnpye 576 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 aw0a 1 Tray[1..N_trays-1].Qin := 0{W};
738 johnpye 576 FREE feed_tray.q;
739 aw0a 1 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