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

Annotation of /trunk/models/column.a4l

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2651 - (hide 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 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 jpye 2651 * along with this program. If not, see <http://www.gnu.org/licenses/>.
32 aw0a 1 *)
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 johnpye 576 FREE Stack[Tray_set].cmo_ratio;
317     FIX Stack[Tray_set].Qin;
318 aw0a 1 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 johnpye 576 FREE feed.Details.state.phase[feed.pd.reference_phase].T;
713     FIX feed.Details.state.phase_fraction[feed.pd.other_phases];
714 aw0a 1 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 johnpye 576 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 aw0a 1 Tray[1..N_trays-1].Qin := 0{W};
736 johnpye 576 FREE feed_tray.q;
737 aw0a 1 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