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

Annotation of /trunk/models/collocation.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: 71595 byte(s)
Changed all cases of *.fixed := {TRUE,FALSE} to 'FIX' and 'FREE' statements.
1 aw0a 1 REQUIRE "cost_column.a4l";
2     (* => cost_column.a4l, atoms.a4l, measures.a4l, system.a4l, basemodel.a4l *)
3     REQUIRE "flash.a4l";
4     (* => flash.a4l, stream_holdup.a4l, thermodynamics.a4l, components.a4l,
5     * phases.a4l, atoms.a4l, measures.a4l, system.a4l, basemodel.a4l *)
6     REQUIRE "ternary_plot.a4l";
7     (* => ternary_plot.a4l, plot.a4l, atoms.a4l, measures.a4l, system.a4l,
8     * basemodel.a4l *)
9     PROVIDE "collocation.a4l";
10    
11     (*
12     * collocation.a4l
13     * by Robert S. Huss
14     * major revisions by Kenneth H. Tyner
15     * Part of the ASCEND Library
16     * $Date: 1998/06/17 19:46:38 $
17     * $Revision: 1.6 $
18     * $Author: mthomas $
19     * $Source: /afs/cs.cmu.edu/project/ascend/Repository/models/collocation.a4l,v $
20     *
21     * This file is part of the ASCEND Modeling Library.
22     *
23     * Copyright (C) 1994, 1997 Carnegie Mellon University
24     *
25     * The ASCEND Modeling Library is free software; you can redistribute
26     * it and/or modify it under the terms of the GNU General Public
27     * License as published by the Free Software Foundation; either
28     * version 2 of the License, or (at your option) any later version.
29     *
30     * The ASCEND Modeling Library is distributed in hope that it
31     * will be useful, but WITHOUT ANY WARRANTY; without even the implied
32     * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
33     * See the GNU General Public License for more details.
34     *
35     * You should have received a copy of the GNU General Public License
36     * along with the program; if not, write to the Free Software
37     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139 USA. Check
38     * the file named COPYING.
39     *)
40    
41     (*
42     C O L L O C A T I O N . A 4 L
43     -----------------------------
44    
45     AUTHORS: Robert S. Huss
46     Kenneth H. Tyner
47    
48     DATES: 5/95 - First Public Release
49     4/96 - Modified for using constant instance types
50     6/97 - Second Public Release
51     Now using parameterized models.
52    
53     CONTENTS: Collocation models for distillation modeling.
54    
55    
56    
57    
58     REQUIRES: "system.a4l"
59     "atoms.a4l"
60     "components.a4l"
61     "thermodynamics.a4l"
62     "plot.a4l"
63     "stream.a4l"
64     "flash.a4l"
65    
66     *)
67    
68     MODEL coll_partial_condenser(
69     Qin WILL_BE energy_rate;
70     vapin WILL_BE stream;
71     liqout WILL_BE stream;
72     distillate WILL_BE stream;
73     equilibrated WILL_BE boolean;
74     ) WHERE (
75     vapin, liqout, distillate WILL_NOT_BE_THE_SAME;
76     distillate.state, liqout.state WILL_NOT_BE_THE_SAME;
77     distillate.cd, liqout.cd, vapin.cd WILL_BE_THE_SAME;
78     vapin.pd.phase_indicator IN ['V','M'] == TRUE;
79     liqout.pd.phase_indicator == 'L';
80     distillate.pd.phase_indicator == 'VL';
81     ) REFINES flash_base;
82    
83     NOTES
84     'purpose' SELF {
85     This models a condenser that produces a two phase stream as a
86     distillate product. This is primarilly used for modeling a total
87     condenser with a saturated liquid product.
88     }
89     'ascii-picture' SELF {
90     |
91     v Vapin
92     /-------------\
93     |OOOOOOOOOOOOO+--< Qin
94     |~~~~~~~~~~~~~|
95     \_____________+--> Distillate
96     | Liqout
97     v
98     }
99     END NOTES;
100    
101     cd ALIASES vapin.cd;
102     state ALIASES distillate.state;
103     P ALIASES state.P;
104     T ALIASES state.T;
105    
106     reflux_ratio IS_A factor;
107    
108     reflux_eqn: (liqout.flow - reflux_ratio * distillate.flow)
109     / flowscale = 0;
110    
111     FOR i IN cd.other_components CREATE
112     distillate.state.y[i] = vapin.state.y[i];
113     liqout.state.y[i] = vapin.state.y[i];
114     END FOR;
115    
116     liqout.T = distillate.T;
117     liqout.P = distillate.P;
118    
119     flowscale IS_A molar_rate_scale;
120     (vapin.flow - distillate.flow - liqout.flow) / flowscale = 0;
121    
122     H_flowscale IS_A energy_rate_scale;
123     energy_balance: (vapin.H_flow + Qin -
124     (liqout.H_flow + distillate.H_flow)) / H_flowscale =0;
125    
126    
127    
128     METHODS
129    
130     METHOD check_all;
131     RUN vapin.check_all;
132     RUN liqout.check_all;
133     RUN distillate.check_all;
134     RUN check_self;
135     END check_all;
136    
137     METHOD check_self;
138     IF (vapin.flow < 1e-4 {mole/s}) THEN
139     STOP {Vapor flow to condenser disappeared};
140     END IF;
141     IF (liqout.flow < 1e-4 {mole/s}) THEN
142     STOP {No reflux leaving condenser};
143     END IF;
144     IF (distillate.flow < 1e-4 {mole/s}) THEN
145     STOP {No distillate leaving condenser};
146     END IF;
147     IF (abs(vapin.flow -
148     distillate.flow - liqout.flow)/flowscale > 1.0e-4) THEN
149     STOP {Condensor violates overall mass-balance};
150     END IF;
151     END check_self;
152    
153     METHOD default_self;
154     H_flowscale := vapin.H_flow + abs(Qin);
155     flowscale := vapin.Details.flowscale;
156     reflux_ratio := 10;
157     reflux_ratio.upper_bound := 1000;
158     reflux_ratio.lower_bound := 0;
159     END default_self;
160    
161     METHOD default_all;
162     RUN vapin.default_all;
163     RUN liqout.default_all;
164     RUN distillate.default_all;
165     RUN default_self;
166     END default_all;
167    
168     METHOD bound_self;
169     reflux_ratio.lower_bound :=
170     reflux_ratio - boundwidth * reflux_ratio.nominal;
171     reflux_ratio.upper_bound :=
172     reflux_ratio + boundwidth * reflux_ratio.nominal;
173     IF (reflux_ratio.lower_bound < 0) THEN
174     reflux_ratio.lower_bound := 0;
175     END IF;
176     END bound_self;
177    
178     METHOD bound_all;
179     vapin.boundwidth := boundwidth;
180     liqout.boundwidth := boundwidth;
181     distillate.boundwidth := boundwidth;
182     RUN vapin.bound_all;
183     RUN liqout.bound_all;
184     RUN distillate.bound_all;
185     RUN bound_self;
186     STOP {MODEL total_condenser method bound_all needs to do Qin};
187     END bound_all;
188    
189     METHOD scale_self;
190     flowscale := vapin.Details.flowscale + liqout.Details.flowscale
191     + distillate.Details.flowscale;
192     H_flowscale := liqout.Details.H_flowscale + vapin.Details.H_flowscale
193     + distillate.Details.H_flowscale;
194     reflux_ratio.nominal := abs(reflux_ratio)*1.01 + 1;
195     END scale_self;
196    
197     METHOD scale_all;
198     RUN vapin.scale_all;
199     RUN liqout.scale_all;
200     RUN distillate.scale_all;
201     RUN scale_self;
202     STOP {MODEL total_condenser method scale_all needs to do Qin};
203     END scale_all;
204    
205     METHOD seqmod;
206     RUN liqout.seqmod;
207     RUN distillate.seqmod;
208     RUN vapin.seqmod;
209 johnpye 576 FIX reflux_ratio;
210     FREE liqout.T;
211     FREE liqout.P;
212 aw0a 1 END seqmod;
213    
214     METHOD specify;
215     RUN seqmod;
216     RUN vapin.specify;
217     END specify;
218    
219     END coll_partial_condenser;
220    
221     MODEL lagrange_polynomial(
222     ntrays WILL_BE integer_constant;
223     );
224    
225     npoints,
226     order IS_A integer_constant;
227     W[0..npoints][0..order],
228     w_tray[0..ntrays+1],
229     w_points[0..npoints],
230     w_mid IS_A factor;
231     f_int,
232     f_mid IS_A fraction;
233     scale IS_A scaling_constant;
234    
235     npoints :== 2*ntrays + 1;
236     order :== ntrays;
237    
238     w_tray[0],
239     w_points[0] ARE_THE_SAME;
240     w_tray[ntrays+1],
241     w_points[npoints] ARE_THE_SAME;
242    
243     w_mid = w_tray[0] + f_mid*(w_tray[ntrays+1] - w_tray[0]);
244    
245     FOR i IN [0..npoints] CREATE
246     FOR k IN [0..ntrays] CREATE
247     W[i][k]*PROD[(w_tray[k] - w_tray[j]) | j IN
248     [0..k-1,k+1..ntrays]] = PROD[(w_points[i] - w_tray[j])
249     | j IN [0..k-1,k+1..ntrays]];
250     END FOR;
251     END FOR;
252    
253     (* point spacing equations *)
254     even IS_A boolean_constant;
255     tray_comp IS_A integer_constant;
256    
257     tray_comp :== 2*(ntrays/2);
258     even :== (tray_comp == ntrays);
259    
260    
261     count IS_A integer_constant;
262     mult[1..ntrays] IS_A factor;
263     f_count IS_A factor; (* need floating point arithmetic
264     to set up multipliers *)
265     f_ntrays IS_A factor; (* need floating point arithmetic
266     to set up multipliers *)
267    
268     SELECT (even)
269     CASE FALSE: (* odd number OF trays *)
270     count :== (ntrays + 1)/2;
271     w_tray[count], w_mid ARE_THE_SAME;
272     FOR i IN [1..count - 1] CREATE
273     w_tray[i] = w_mid - f_int*mult[i]*(w_mid - w_tray[0]);
274     END FOR;
275     FOR i IN [count + 1..ntrays] CREATE
276     w_tray[i] = w_mid + f_int*mult[i]*(w_mid - w_tray[0]);
277     END FOR;
278     CASE TRUE: (* even number OF trays *)
279     count :== ntrays/2;
280     FOR i IN [1..count] CREATE
281     w_tray[i] = w_mid - f_int*mult[i]*(w_mid - w_tray[0]);
282     END FOR;
283     FOR i IN [count + 1..ntrays] CREATE
284     w_tray[i] = w_mid + f_int*mult[i]*(w_mid - w_tray[0]);
285     END FOR;
286     END SELECT;
287    
288    
289     METHODS
290    
291     METHOD default_self;
292     f_mid := 0.5;
293     IF (even == FALSE) THEN
294     f_count := count;
295     f_ntrays := ntrays;
296     f_int := 2/(f_ntrays + 1)*(f_count - 1);
297     mult[1] := 1;
298     FOR i IN [2..count - 1] DO
299     mult[i] := (f_count - i)/(f_count - 1);
300     END FOR;
301     FOR i IN [count + 1..ntrays] DO
302     mult[i] := mult[ntrays + 1 - i];
303     END FOR;
304     ELSE
305     f_count := count;
306     f_ntrays := ntrays;
307     f_int := 2/(f_ntrays + 1)*(f_count - 1 + 0.5);
308     mult[1] := 1;
309     FOR i IN [2..count] DO
310     mult[i] := 1/(f_count + i - 1);
311     END FOR;
312     FOR i IN [count + 1..ntrays] DO
313     mult[i] := mult[ntrays + 1 - i];
314     END FOR;
315     END IF;
316     END default_self;
317     METHOD default_all;
318     RUN default_self;
319     END default_all;
320     METHOD scale_self;
321     f_int.nominal := f_int;
322     f_mid.nominal := f_mid;
323     FOR i IN [0..npoints] DO
324     w_points[i].nominal := abs(w_points[i]) + 0.01;
325    
326     FOR j IN [0..order] DO
327     W[i][j].nominal := abs(W[i][j]) + 0.01;
328     END FOR;
329     END FOR;
330     FOR j IN [0..ntrays+1] DO
331     w_tray[j].nominal := abs(w_tray[j]) + 0.01;
332     END FOR;
333     w_mid.nominal := abs(w_mid) + 0.01;
334     END scale_self;
335     METHOD scale_all;
336     RUN scale_self;
337     END scale_all;
338     METHOD bound_self;
339     (* FOR i IN [0..npoints] DO
340     (* w_points[i].lower_bound := -2.0;
341     w_points[i].upper_bound := abs(w_points[i]) +
342     scale*w_points[i].nominal;
343     *)
344     FOR j IN [0..order] DO
345     (* NEED BETTER BOUNDING HERE
346     note that lower bound can go negative for
347     some Wij and others will have zero lower bound.
348     W[i][j].lower_bound := ??;
349     W[i][j].upper_bound := ??;
350     *)
351     END FOR;
352     END FOR;
353     (* FOR j IN [0..ntrays+1] DO
354     w_tray[j].lower_bound := -2.0;
355     w_tray[j].upper_bound := w_tray[j] +
356     scale*w_tray[j].nominal;
357     END FOR;
358     w_mid.lower_bound := -2.0;
359     w_mid.upper_bound := w_mid + scale*w_mid.nominal;
360     *)
361     *)
362     END bound_self;
363     METHOD bound_all;
364     RUN bound_self;
365     END bound_all;
366     METHOD check_self;
367     END check_self;
368     METHOD check_all;
369     RUN check_self;
370     END check_all;
371    
372     METHOD specify;
373 johnpye 576 FIX w_points[0..npoints];
374     FIX f_int;
375     FIX f_mid;
376     FIX mult[1..ntrays];
377 aw0a 1 END specify;
378     METHOD reset;
379     RUN ClearAll;
380     RUN specify;
381     END reset;
382    
383     END lagrange_polynomial;
384    
385    
386     MODEL collpoint(
387     z WILL_BE factor;
388     s WILL_BE factor;
389     up_down WILL_BE real;
390     a WILL_BE factor;
391     );
392     ztop IS_A factor;
393     scale IS_A scaling_constant;
394    
395     s_def: z = 1-exp(-a*s);
396     ztopdefn: ztop = 1-(1-z)*exp(-up_down*a);
397    
398     METHODS
399     METHOD default_self;
400     ztop := 0.5;
401     ztop.upper_bound := 1.0;
402     ztop.lower_bound := -0.5;
403     END default_self;
404     METHOD default_all;
405     s := 1.0;
406     s.lower_bound := 0.0;
407     s.upper_bound := 100.0;
408     z := 0.5;
409     RUN default_self;
410     END default_all;
411     METHOD scale_self;
412     ztop.nominal := abs(ztop) + 0.01;
413     END scale_self;
414     METHOD scale_all;
415     a.nominal := a + 0.01;
416     z.nominal := abs(z) + 0.01;
417     s.nominal := s + 0.01;
418     RUN scale_self;
419     END scale_all;
420     METHOD bound_self;
421     ztop.lower_bound := 1-(1-z.lower_bound)*exp(-up_down*a);
422     ztop.upper_bound := 1-(1-z.upper_bound)*exp(-up_down*a);
423     END bound_self;
424     METHOD bound_all;
425     ztop.nominal := abs(ztop) + 0.01;
426     a.lower_bound := 0.0;
427     a.upper_bound := 3.0;
428     z.lower_bound := 1-exp(-a*s.lower_bound);
429     z.upper_bound := 1-exp(-a*s.upper_bound);
430     RUN bound_self;
431     END bound_all;
432     METHOD check_self;
433     END check_self;
434     METHOD check_all;
435     RUN check_self;
436     END check_all;
437    
438     METHOD seqmod;
439 johnpye 576 FIX a;
440     FIX s;
441 aw0a 1 END seqmod;
442     METHOD specify;
443     RUN seqmod;
444     END specify;
445     METHOD reset;
446     RUN ClearAll;
447     RUN specify;
448     END reset;
449     METHOD s_off;
450     s_def.included := FALSE;
451 johnpye 576 FIX s;
452 aw0a 1 END s_off;
453    
454     END collpoint;
455    
456    
457     MODEL z_set(
458     ntrays WILL_BE integer_constant;
459     up_down WILL_BE real;
460     a WILL_BE factor;
461     z_on WILL_BE boolean;
462     );
463    
464     s_values[0..ntrays+1],
465     z_values[0..ntrays+1],
466     stot IS_A factor;
467    
468    
469     FOR i IN [0..ntrays+1] CREATE
470     z[i] IS_A collpoint(z_values[i],s_values[i],up_down,a);
471     END FOR;
472    
473     ztop,
474     zbot IS_A factor;
475    
476     lgr IS_A lagrange_polynomial(ntrays);
477    
478     scale IS_A scaling_constant;
479    
480     stot = s_values[ntrays+1] - s_values[0];
481    
482     FOR j IN [1..ntrays] CREATE
483     lgr.w_points[2*j-1],
484     lgr.w_tray[j] ARE_THE_SAME;
485     END FOR;
486    
487    
488     (* z_based *)
489     FOR j IN [1..ntrays] CREATE
490    
491     z_based_odd[2*j-1]: lgr.w_points[2*j-1] =
492     z_values[j];
493     z_based_even[2*j]: lgr.w_points[2*j] =
494     z[j].ztop;
495     END FOR;
496    
497     z_based_0: lgr.w_points[0] = z_values[0];
498     z_based_n: lgr.w_points[lgr.npoints] =
499     z_values[ntrays+1];
500    
501    
502     (* s_based *)
503    
504     FOR j IN [1..ntrays] CREATE
505    
506     s_based_odd[2*j-1]: lgr.w_points[2*j-1] =
507     s_values[j];
508     s_based_even[2*j]: lgr.w_points[2*j] =
509     s_values[j] + z[0].up_down;
510     END FOR;
511    
512     s_based_0: lgr.w_points[0] = s_values[0];
513     s_based_n: lgr.w_points[lgr.npoints] =
514     s_values[ntrays+1];
515    
516    
517     ztop = (up_down+1)*z_values[ntrays+1]/2 +(1-up_down)*z_values[0]/2;
518     zbot = (up_down+1)*z_values[0]/2 +(1-up_down)*z_values[ntrays+1]/2;
519    
520     tray_delta IS_A factor;
521    
522     s_values[ntrays] + tray_delta = s_values[ntrays+1];
523    
524     WHEN(z_on)
525     CASE TRUE:
526     USE z_based_odd;
527     USE z_based_even;
528     USE z_based_0;
529     USE z_based_n;
530     CASE FALSE:
531     USE s_based_odd;
532     USE s_based_even;
533     USE s_based_0;
534     USE s_based_n;
535     END WHEN;
536    
537    
538     METHODS
539     METHOD default_self;
540     s_values[0] := 0;
541     s_values[1..ntrays+1] := 1.0;
542     s_values[0..ntrays+1].lower_bound := 0.0;
543     z_values[0] := 0;
544     z_values[1..ntrays+1] := 0.5;
545     z_values[0..ntrays+1].lower_bound := 0.0;
546     z_values[0..ntrays+1].upper_bound := 1.0;
547     stot.lower_bound := 1;
548     stot.upper_bound := 100;
549    
550     RUN z[0..ntrays+1].default_self;
551     RUN lgr.default_self;
552     END default_self;
553     METHOD default_all;
554     RUN default_self;
555     END default_all;
556    
557     METHOD scale_self;
558     RUN z[0..ntrays+1].scale_self;
559     RUN lgr.scale_self;
560     stot.nominal := stot + 0.01;
561     tray_delta.nominal := tray_delta + 0.01;
562     ztop.nominal := abs(ztop) + 0.01;
563     zbot.nominal := abs(zbot) + 0.01;
564     END scale_self;
565     METHOD scale_all;
566     RUN scale_self;
567     END scale_all;
568    
569     METHOD bound_self;
570     s_values[0..ntrays+1].upper_bound := stot.upper_bound;
571     RUN z[0..ntrays+1].bound_self;
572    
573     RUN lgr.bound_self;
574     tray_delta.lower_bound := 1e-8;
575     tray_delta.upper_bound := tray_delta +
576     scale*tray_delta.nominal;
577     ztop.lower_bound := -0.5;
578     ztop.upper_bound := 1.0;
579     zbot.lower_bound := -0.5;
580     zbot.upper_bound := 1.0;
581    
582     IF (z_on) THEN
583     FOR j IN [1..ntrays] DO
584     lgr.w_points[2*j-1].lower_bound := z_values[j].lower_bound; (* 0 *)
585     lgr.w_points[2*j-1].upper_bound := z_values[j].upper_bound; (* 1 *)
586     lgr.w_points[2*j].lower_bound := z[j].ztop.lower_bound;
587     lgr.w_points[2*j].upper_bound := z[j].ztop.upper_bound;
588     END FOR;
589     lgr.w_tray[0..ntrays+1].lower_bound := 0;
590     lgr.w_tray[0..ntrays+1].upper_bound := 1;
591     ELSE
592     FOR j IN [1..ntrays] DO
593     lgr.w_points[2*j-1].lower_bound := 0;
594     lgr.w_points[2*j-1].upper_bound := stot.upper_bound;
595     lgr.w_points[2*j].lower_bound := 0 + z[0].up_down;
596     lgr.w_points[2*j].upper_bound := stot.upper_bound + z[0].up_down;
597     END FOR;
598     lgr.w_tray[0..ntrays+1].lower_bound := 0;
599     lgr.w_tray[0..ntrays+1].upper_bound := stot.upper_bound;
600     END IF;
601    
602     END bound_self;
603     METHOD bound_all;
604     RUN bound_self;
605     END bound_all;
606     METHOD check_self;
607     END check_self;
608     METHOD check_all;
609     RUN check_self;
610     END check_all;
611    
612     METHOD specify;
613     RUN lgr.specify;
614 johnpye 576 FREE lgr.w_points[0..lgr.npoints];
615     FIX a;
616     FIX s_values[0];
617     FIX stot;
618 aw0a 1 END specify;
619     METHOD reset;
620     RUN ClearAll;
621     RUN specify;
622     END reset;
623    
624     METHOD s_off;
625     RUN z[ntrays..ntrays+1].s_off;
626     END s_off;
627    
628     END z_set;
629    
630     MODEL coll_material_detailed_stream(
631     state WILL_BE thermodynamics;
632     ) WHERE (
633     state.pd.phase_indicator == 'M';
634     ) REFINES detailed_stream;
635    
636     sum_y: SUM[state.y[i] | i IN components] = 1.0;
637    
638     (* this is a wrapper that permanently removes equations *)
639     false_cond IS_A boolean_constant;
640     false_cond :== FALSE;
641     WHEN (false_cond)
642     CASE TRUE:
643     USE state.overall_h;
644     USE state.overall_g;
645     USE state.overall_v;
646     USE state.overall_y;
647     USE V_eqn;
648     USE state.phase['material'].g_mix;
649     USE state.phase['material'].v_mix;
650     USE state.phase['material'].h_mix;
651     USE state.phase['material'].sum_y;
652     USE state.sum_phase_fractions;
653     OTHERWISE:
654     END WHEN;
655     METHODS
656     METHOD specify;
657     RUN detailed_stream::specify;
658 johnpye 576 FIX state.H;
659 aw0a 1 END specify;
660     END coll_material_detailed_stream;
661    
662     MODEL coll_material_stream(
663     cd WILL_BE components_data;
664     pd WILL_BE phases_data;
665     equilibrated WILL_BE boolean;
666     ) WHERE (
667     pd.phase_indicator == 'M';
668     ) REFINES stream;
669    
670     sum_y: SUM[state.y[i] | i IN components] = 1.0;
671     (* this is a wrapper that permanently removes equations *)
672     false_cond IS_A boolean_constant;
673     false_cond :== FALSE;
674     WHEN (false_cond)
675     CASE TRUE:
676     USE state.overall_h;
677     USE state.overall_g;
678     USE state.overall_v;
679     USE state.overall_y;
680     USE Details.V_eqn;
681     USE state.phase['material'].g_mix;
682     USE state.phase['material'].v_mix;
683     USE state.phase['material'].h_mix;
684     USE state.phase['material'].sum_y;
685     USE state.sum_phase_fractions;
686     OTHERWISE:
687     END WHEN;
688     METHODS
689     METHOD specify;
690     RUN stream::specify;
691 johnpye 576 FIX state.H;
692 aw0a 1 END specify;
693     END coll_material_stream;
694    
695    
696     MODEL coll_detailed_tray(
697     Qin WILL_BE energy_rate;
698     equilibrated WILL_BE boolean;
699     liqin WILL_BE detailed_stream;
700     vapin WILL_BE detailed_stream;
701     liqout WILL_BE detailed_stream;
702     vapout WILL_BE detailed_stream;
703     state WILL_BE thermodynamics;
704     ) WHERE (
705     vapin.state.pd.phase_indicator IN ['V','M'] == TRUE;
706     vapout.state.pd.phase_indicator == 'V';
707     liqin.state.pd.phase_indicator IN ['L','M'] == TRUE;
708     liqout.state.pd.phase_indicator == 'L';
709     state.pd.phase_indicator == 'VL';
710     liqout.state, vapout.state WILL_NOT_BE_THE_SAME;
711     state.phase['liquid1'], liqout.state.phase['liquid1'] WILL_BE_THE_SAME;
712     state.phase['vapor'], vapout.state.phase['vapor'] WILL_BE_THE_SAME;
713     state.cd, liqin.state.cd, liqout.state.cd,
714     vapin.state.cd, vapout.state.cd WILL_BE_THE_SAME;
715     ) REFINES detailed_tray;
716    
717     METHODS
718     METHOD seqmod;
719     RUN detailed_tray::seqmod;
720     RUN liqin.seqmod;
721     RUN vapin.seqmod;
722     END seqmod;
723     END coll_detailed_tray;
724    
725     MODEL coll_feed_tray(
726     Qin WILL_BE energy_rate;
727     equilibrated WILL_BE boolean;
728     feed WILL_BE stream;
729     liqin WILL_BE stream;
730     vapin WILL_BE stream;
731     liqout WILL_BE stream;
732     vapout WILL_BE stream;
733     ) WHERE (
734     feed, liqin, vapin, vapout, liqout WILL_NOT_BE_THE_SAME;
735     feed.cd, liqin.cd, liqout.cd, vapin.cd, vapout.cd WILL_BE_THE_SAME;
736     liqin.pd.phase_indicator IN ['L','M'] == TRUE;
737     liqout.pd.phase_indicator == 'L';
738     vapin.pd.phase_indicator IN ['V','M'] == TRUE;
739     vapout.pd.phase_indicator == 'V';
740     (feed.pd.phase_indicator IN ['V','L','VL']) == TRUE;
741     ) REFINES feed_tray;
742     METHODS
743     METHOD seqmod;
744     RUN feed_tray::seqmod;
745     RUN liqin.seqmod;
746     RUN vapin.seqmod;
747     RUN feed.seqmod;
748     END seqmod;
749     END coll_feed_tray;
750    
751     MODEL coll_simple_reboiler(
752     Qin WILL_BE energy_rate;
753     equilibrated WILL_BE boolean;
754     liqin WILL_BE stream;
755     vapout WILL_BE stream;
756     bottoms WILL_BE stream;
757     ) WHERE (
758     liqin, vapout, bottoms WILL_NOT_BE_THE_SAME;
759     liqin.cd, vapout.cd, bottoms.cd WILL_BE_THE_SAME;
760     liqin.pd.phase_indicator IN ['L','M'] == TRUE;
761     vapout.pd.phase_indicator == 'V';
762     bottoms.pd.phase_indicator == 'L';
763     ) REFINES simple_reboiler;
764     METHODS
765     METHOD seqmod;
766     RUN simple_reboiler::seqmod;
767     RUN liqin.seqmod;
768     END seqmod;
769     END coll_simple_reboiler;
770    
771     MODEL coll(
772     ntrays WILL_BE integer_constant;
773     topvap WILL_BE stream;
774     topliq WILL_BE stream;
775     botvap WILL_BE stream;
776     botliq WILL_BE stream;
777     pdL WILL_BE phases_data;
778     pdV WILL_BE phases_data;
779     reduce WILL_BE fraction;
780     equilibrated WILL_BE boolean;
781     up_down WILL_BE real;
782     a WILL_BE factor;
783     z_on WILL_BE boolean;
784     hat_on WILL_BE boolean;
785     hb_on WILL_BE boolean;
786     ) WHERE (
787     ntrays >= 1;
788     topvap, topliq, botvap, botliq WILL_NOT_BE_THE_SAME;
789     topvap.cd, botvap.cd, botliq.cd, topliq.cd WILL_BE_THE_SAME;
790     botliq.pd.phase_indicator IN ['M','L'] == TRUE;
791     botvap.pd.phase_indicator IN ['M','V'] == TRUE;
792     topliq.pd.phase_indicator IN ['M','L'] == TRUE;
793     topvap.pd.phase_indicator IN ['M','V'] == TRUE;
794     ) REFINES cmumodel();
795    
796     cd ALIASES topliq.state.cd;
797     vap_option ALIASES pdV.vapor_option;
798     liq_option ALIASES pdL.liquid1_option;
799     pdVL IS_A phases_data('VL', vap_option, liq_option, 'none');
800     pdM IS_A phases_data('M', 'none', 'none', 'none');
801     mat_option ALIASES pdM.liquid1_option; (* none *)
802    
803    
804     FOR i IN [1..ntrays] CREATE
805     liqin_mix[i] IS_A select_mixture_type(cd, mat_option);
806     liqout_mix[i] IS_A select_mixture_type(cd, liq_option);
807     vapin_mix[i] IS_A select_mixture_type(cd, mat_option);
808     vapout_mix[i] IS_A select_mixture_type(cd, vap_option);
809     END FOR;
810    
811     FOR i IN [1..ntrays] CREATE
812     liqin_phase[i]['material'] ALIASES liqin_mix[i].phase;
813     liqout_phase[i]['liquid1'] ALIASES liqout_mix[i].phase;
814     vapin_phase[i]['material'] ALIASES vapin_mix[i].phase;
815     vapout_phase[i]['vapor'] ALIASES vapout_mix[i].phase;
816     END FOR;
817    
818     FOR i IN [1..ntrays] CREATE
819     liqin_state[i] IS_A thermodynamics(
820     cd,
821     pdM,
822     liqin_phase[i],
823     equilibrated
824     );
825     liqout_state[i] IS_A thermodynamics(
826     cd,
827     pdL,
828     liqout_phase[i],
829     equilibrated
830     );
831     vapin_state[i] IS_A thermodynamics(
832     cd,
833     pdM,
834     vapin_phase[i],
835     equilibrated
836     );
837     vapout_state[i] IS_A thermodynamics(
838     cd,
839     pdV,
840     vapout_phase[i],
841     equilibrated
842     );
843     END FOR;
844     FOR i IN [1..ntrays] CREATE
845     liqin[i] IS_A coll_material_detailed_stream(liqin_state[i]);
846     liqout[i] IS_A detailed_stream(liqout_state[i]);
847     vapin[i] IS_A coll_material_detailed_stream(vapin_state[i]);
848     vapout[i] IS_A detailed_stream(vapout_state[i]);
849     END FOR;
850    
851     FOR i IN [1..ntrays] CREATE
852     trayVL[i][VLphases[i]] ALIASES
853     (vapout_mix[i].phase,liqout_mix[i].phase)
854     WHERE VLphases[i] IS_A set OF symbol_constant
855     WITH_VALUE ('vapor','liquid1');
856     END FOR;
857    
858     FOR i IN [1..ntrays] CREATE
859     tray_state[i] IS_A thermodynamics(
860     cd,
861     pdVL,
862     trayVL[i],
863     equilibrated
864     );
865     END FOR;
866    
867     Qin_tray[1..ntrays] IS_A energy_rate;
868    
869     FOR i IN [1..ntrays] CREATE
870     tray[i] IS_A coll_detailed_tray(
871     Qin_tray[i],
872     equilibrated,
873     liqin[i],
874     vapin[i],
875     liqout[i],
876     vapout[i],
877     tray_state[i]
878     );
879     END FOR;
880    
881     components ALIASES cd.components;
882     inactive_component ALIASES cd.reference;
883    
884     x_order,
885     y_order IS_A integer_constant;
886    
887     x_coeff[components
888     - [inactive_component]]
889     [0..x_order],
890     y_coeff[components
891     - [inactive_component]]
892     [0..y_order],
893     cmo[1..ntrays],
894     cmotot IS_A factor;
895    
896     z_set IS_A z_set(ntrays,up_down,a,z_on);
897     x[1..ntrays][components] IS_A fraction;
898     y[1..ntrays][components] IS_A fraction;
899     x_hat[1..ntrays][components] IS_A factor;
900     scale IS_A scaling_constant;
901    
902    
903     FOR i IN components CREATE
904     FOR j IN [1..ntrays] CREATE
905     x[j][i] = (1+z_set.up_down)
906     *tray[ntrays+1-j].liqout.state.y[i]/2
907     + (1-z_set.up_down)
908     *tray[j].liqout.state.y[i]/2;
909     y[j][i] = (1+z_set.up_down)
910     *tray[ntrays+1-j].vapin.state.y[i]/2
911     + (1-z_set.up_down)
912     *tray[j].vapin.state.y[i]/2;
913     x_hat[j][i] = (1+z_set.up_down)
914     *tray_x_hat['out'][i][ntrays+1-j]/2
915     + (1-z_set.up_down)
916     *tray_x_hat['out'][i][j]/2;
917     END FOR;
918     END FOR;
919    
920     x_order :== ntrays;
921     y_order :== ntrays;
922    
923    
924     (* constant molar overflow model - instead of heat balance *)
925    
926     FOR j IN [1..ntrays] CREATE
927     cmo[j]*tray[j].liqin.flow = botliq.flow;
928     END FOR;
929    
930     cmotot*topliq.flow = botliq.flow;
931    
932     FOR i IN components CREATE
933     overall_MB[i]: topliq.f[i] - topvap.f[i] =
934     botliq.f[i] - botvap.f[i];
935     END FOR;
936    
937     (* xtrans stuff *)
938    
939     tray_x_hat['in','out'][components][1..ntrays],
940     tray_y_hat['in','out'][components][1..ntrays],
941     end_x_hat['top','bot'][components],
942     end_y_hat['top','bot'][components] IS_A factor;
943     td IS_A real;
944    
945    
946     FOR i IN components CREATE
947     tanh_botliq[i]: (1.0)*(2.0*botliq.state.y[i] - 1.0)
948     = tanh(end_x_hat['bot'][i]*td);
949     tanh_topliq[i]: (1.0)*(2.0*topliq.state.y[i] - 1.0)
950     = tanh(end_x_hat['top'][i]*td);
951     tanh_botvap[i]: (1.0)*(2.0*botvap.state.y[i] - 1.0)
952     = tanh(end_y_hat['bot'][i]*td);
953     tanh_topvap[i]: (1.0)*(2.0*topvap.state.y[i] - 1.0)
954     = tanh(end_y_hat['top'][i]*td);
955    
956     END FOR;
957    
958     FOR i IN components CREATE
959    
960     FOR j IN [1..ntrays] CREATE
961    
962     tanh_liqout[i][j]: (1.0)*(2.0*tray[j].liqout.state.y[i] - 1.0)
963     = tanh(tray_x_hat['out'][i][j]*td);
964     tanh_liqin[i][j]: (1.0)*(2.0*tray[j].liqin.state.y[i] - 1.0)
965     = tanh(tray_x_hat['in'][i][j]*td);
966     tanh_vapout[i][j]: (1.0)*(2.0*tray[j].vapout.state.y[i] - 1.0)
967     = tanh(tray_y_hat['out'][i][j]*td);
968     tanh_vapin[i][j]: (1.0)*(2.0*tray[j].vapin.state.y[i] - 1.0)
969     = tanh(tray_y_hat['in'][i][j]*td);
970     END FOR;
971     END FOR;
972    
973     (* polynomial *)
974    
975     (* Overall material balances *)
976    
977     FOR j IN [1..ntrays] CREATE
978     tot_trayMB[j]: botvap.flow - botliq.flow =
979     tray[j].vapout.flow -
980     tray[j].liqin.flow;
981    
982     END FOR;
983    
984     FOR i IN components - [inactive_component] CREATE
985     FOR j IN [1..ntrays] CREATE
986     frac_x_in[j][i]: tray[j].liqin.state.y[i] =
987     SUM[z_set.lgr.W[2*j][k]*x_coeff[i][k]
988     | k IN [0..x_order]];
989     frac_y_in[j][i]: tray[j].vapin.state.y[i] =
990     SUM[z_set.lgr.W[2*j-1][k]*y_coeff[i][k]
991     | k IN [0..y_order]];
992     frac_x_out[j][i]: tray[j].liqout.state.y[i] =
993     SUM[z_set.lgr.W[2*j-1][k]*x_coeff[i][k]
994     | k IN [0..x_order]];
995     frac_y_out[j][i]: tray[j].vapout.state.y[i] =
996     SUM[z_set.lgr.W[2*j][k]*y_coeff[i][k]
997     | k IN [0..y_order]];
998     END FOR;
999     END FOR;
1000    
1001     FOR i IN components - [inactive_component] CREATE
1002     FOR j IN [1..ntrays] CREATE
1003    
1004     trans_x_out[j][i]: tray_x_hat['out'][i][j] =
1005     SUM[z_set.lgr.W[2*j-1][k]*x_coeff[i][k]
1006     | k IN [0..x_order]];
1007     trans_x_in[j][i]: tray_x_hat['in'][i][j] =
1008     SUM[z_set.lgr.W[2*j][k]*x_coeff[i][k]
1009     | k IN [0..x_order]];
1010     trans_y_out[j][i]: tray_y_hat['out'][i][j] =
1011     SUM[z_set.lgr.W[2*j][k]*y_coeff[i][k]
1012     | k IN [0..y_order]];
1013     trans_y_in[j][i]: tray_y_hat['in'][i][j] =
1014     SUM[z_set.lgr.W[2*j-1][k]*y_coeff[i][k]
1015     | k IN [0..y_order]];
1016     END FOR;
1017     END FOR;
1018    
1019    
1020     FOR i IN components - [inactive_component] CREATE
1021     frac_x_top[i]: topliq.state.y[i]
1022     = SUM[((z_set.up_down+1)
1023     *z_set.lgr.W[z_set.lgr.npoints][k]/2
1024     + (1-z_set.up_down)
1025     *z_set.lgr.W[0][k]/2)*x_coeff[i][k]
1026     | k IN [0..x_order]];
1027     frac_y_top[i]: topvap.state.y[i]
1028     = SUM[((z_set.up_down+1)
1029     *z_set.lgr.W[z_set.lgr.npoints][k]/2
1030     + (1-z_set.up_down)
1031     *z_set.lgr.W[0][k]/2)*y_coeff[i][k]
1032     | k IN [0..y_order]];
1033     frac_y_bot[i]: botvap.state.y[i]
1034     = SUM[((z_set.up_down+1)
1035     *z_set.lgr.W[0][k]/2
1036     + (1-z_set.up_down)
1037     *z_set.lgr.W[z_set.lgr.npoints][k]/2)
1038     *y_coeff[i][k]
1039     | k IN [0..y_order]];
1040     END FOR;
1041    
1042     FOR i IN components - [inactive_component] CREATE
1043     trans_x_top[i]: end_x_hat['top'][i]
1044     = SUM[(((z_set.up_down+1)*z_set.lgr.W[z_set.lgr.npoints][k]/2
1045     + (1-z_set.up_down)*z_set.lgr.W[0][k]/2))*x_coeff[i][k]
1046     | k IN [0..x_order]];
1047     trans_y_top[i]: end_y_hat['top'][i]
1048     = SUM[(((z_set.up_down+1)*z_set.lgr.W[z_set.lgr.npoints][k]/2
1049     + (1-z_set.up_down)*z_set.lgr.W[0][k]/2))*y_coeff[i][k]
1050     | k IN [0..y_order]];
1051     trans_y_bot[i]: end_y_hat['bot'][i]
1052     = SUM[((z_set.up_down+1)*z_set.lgr.W[0][k]/2
1053     + (1-z_set.up_down)
1054     *z_set.lgr.W[z_set.lgr.npoints][k]/2)*y_coeff[i][k]
1055     | k IN [0..y_order]];
1056     END FOR;
1057    
1058    
1059     slope[components] IS_A factor;
1060    
1061     FOR i IN components CREATE
1062     slope[i]*z_set.stot = abs(topliq.state.y[i] - botliq.state.y[i]);
1063     END FOR;
1064    
1065    
1066     aslope[components] IS_A factor;
1067     intercept[components] IS_A fraction;
1068     slope_slack[1..ntrays][components] IS_A factor;
1069    
1070    
1071    
1072    
1073     FOR i IN components CREATE
1074     botpoint[i]: botliq.state.y[i] = aslope[i]*z_set.zbot +
1075     intercept[i];
1076     toppoint[i]: topliq.state.y[i] = aslope[i]*z_set.ztop +
1077     intercept[i];
1078     FOR j IN [1..ntrays] CREATE
1079     midpoint[j][i]: tray[j].liqout.state.y[i] =
1080     aslope[i]*(z_set.z_values[j] - z_set.zbot) +
1081     intercept[i] + slope_slack[j][i];
1082     END FOR;
1083     END FOR;
1084    
1085     WHEN(hat_on)
1086     CASE TRUE:
1087     USE trans_x_out;
1088     USE trans_x_in;
1089     USE trans_y_out;
1090     USE trans_y_in;
1091     USE trans_x_top;
1092     USE trans_y_top;
1093     USE trans_y_bot;
1094     CASE FALSE:
1095     USE frac_x_in;
1096     USE frac_y_in;
1097     USE frac_x_out;
1098     USE frac_y_out;
1099     USE frac_x_top;
1100     USE frac_y_top;
1101     USE frac_y_bot;
1102     END WHEN;
1103    
1104     (* ENTHALPY / HEAT-BALANCE SECTION *)
1105     h_order ALIASES ntrays;
1106     h_coeff['liquid','vapor'][0..h_order] IS_A molar_energy;
1107     Qtot,
1108     Qin[1..ntrays] IS_A energy_rate;
1109    
1110     Overall_HB: Qtot + topliq.H_flow + botvap.H_flow =
1111     botliq.H_flow + topvap.H_flow;
1112    
1113     FOR j IN [1..ntrays] CREATE
1114     tot_trayHB[j]: Qin[j] +topliq.H_flow - topvap.H_flow =
1115     tray[j].liqout.H_flow -
1116     tray[j].vapin.H_flow;
1117     END FOR;
1118    
1119     (* end points *)
1120    
1121     h_end_topliq: topliq.state.H = SUM[((z_set.up_down+1)
1122     *z_set.lgr.W[z_set.lgr.npoints][k]/2
1123     + (1-z_set.up_down)*z_set.lgr.W[0][k]/2)
1124     *h_coeff['liquid'][k]
1125     | k IN [0..h_order]];
1126     h_end_topvap: topvap.state.H = SUM[((z_set.up_down+1)
1127     *z_set.lgr.W[z_set.lgr.npoints][k]/2
1128     + (1-z_set.up_down)*z_set.lgr.W[0][k]/2)
1129     *h_coeff['vapor'][k]
1130     | k IN [0..h_order]];
1131     h_end_botliq: botliq.state.H = SUM[((z_set.up_down+1)
1132     *z_set.lgr.W[0][k]/2
1133     + (1-z_set.up_down)
1134     *z_set.lgr.W[z_set.lgr.npoints][k]/2)
1135     *h_coeff['liquid'][k]
1136     | k IN [0..h_order]];
1137     h_end_botvap: botvap.state.H = SUM[((z_set.up_down+1)
1138     *z_set.lgr.W[0][k]/2
1139     + (1-z_set.up_down)
1140     *z_set.lgr.W[z_set.lgr.npoints][k]/2)
1141     *h_coeff['vapor'][k]
1142     | k IN [0..h_order]];
1143     (* interior points *)
1144     FOR j IN [1..ntrays] CREATE
1145    
1146     h_int_liqout[j]: tray[j].liqout.state.H =
1147     SUM[z_set.lgr.W[2*j-1][k]*h_coeff['liquid'][k]
1148     | k IN [0..h_order]];
1149     h_int_liqin[j]: tray[j].liqin.state.H =
1150     SUM[z_set.lgr.W[2*j][k]*h_coeff['liquid'][k]
1151     | k IN [0..h_order]];
1152     h_int_vapout[j]: tray[j].vapout.state.H =
1153     SUM[z_set.lgr.W[2*j][k]*h_coeff['vapor'][k]
1154     | k IN [0..h_order]];
1155     h_int_vapin[j]: tray[j].vapin.state.H =
1156     SUM[z_set.lgr.W[2*j-1][k]*h_coeff['vapor'][k]
1157     | k IN [0..h_order]];
1158     END FOR;
1159    
1160     use_H_eqns IS_A boolean;
1161     WHEN(use_H_eqns)
1162     CASE TRUE:
1163     USE Overall_HB;
1164     USE tot_trayHB;
1165     USE h_end_topliq;
1166     USE h_end_topvap;
1167     USE h_end_botliq;
1168     USE h_end_botvap;
1169     USE h_int_liqout;
1170     USE h_int_liqin;
1171     USE h_int_vapout;
1172     USE h_int_vapin;
1173     OTHERWISE:
1174     END WHEN;
1175    
1176    
1177    
1178     (* Plotting Section *)
1179     z_shift IS_A factor;
1180     s_shift IS_A factor;
1181    
1182     n_plt_points IS_A set OF integer_constant;
1183     n_plt_points :== [0..ntrays+1];
1184     z_tray_loc[0..ntrays+1] IS_A factor;
1185     s_tray_loc[0..ntrays+1] IS_A factor;
1186     x_plot[components][0..ntrays+1] IS_A fraction;
1187     y_plot[components][0..ntrays+1] IS_A fraction;
1188    
1189     z_tray_0: z_tray_loc[0] = z_set.z_values[0] + z_shift;
1190     z_tray_end: z_tray_loc[ntrays+1] = z_set.z_values[ntrays+1] + z_shift;
1191     s_tray_0: s_tray_loc[0] = z_set.s_values[0] + s_shift;
1192     s_tray_end: s_tray_loc[ntrays+1] = z_set.s_values[ntrays+1] + s_shift;
1193     FOR i IN [1..ntrays] CREATE
1194     z_tray[i]: z_tray_loc[i] =
1195     (1+up_down)*(z_set.z_values[ntrays+1]
1196     - z_set.z_values[ntrays+1-i])*0.5
1197     + (1-up_down)*z_set.z_values[i]*0.5 + z_shift;
1198    
1199     s_tray[i]: s_tray_loc[i] =
1200     (1+up_down)*(z_set.s_values[ntrays+1]
1201     - z_set.s_values[ntrays+1-i])*0.5
1202     + (1-up_down)*z_set.s_values[i]*0.5 + s_shift;
1203     END FOR;
1204    
1205     FOR i IN components CREATE
1206     x_plot[i][0] = topliq.state.y[i];
1207     y_plot[i][0] = topvap.state.y[i];
1208     FOR j IN [1..ntrays] CREATE
1209     x_plot[i][j] =
1210     (1 - up_down)*tray[j].liqout.state.y[i]/2 +
1211     (1 + up_down)*tray[ntrays - j + 1].liqout.state.y[i]/2;
1212    
1213     y_plot[i][j] =
1214     (1 - up_down)*tray[j].vapout.state.y[i]/2 +
1215     (1 + up_down)*tray[ntrays - j + 1].vapout.state.y[i]/2;
1216     END FOR;
1217     x_plot[i][ntrays+1] = botliq.state.y[i];
1218     y_plot[i][ntrays+1] = botvap.state.y[i];
1219    
1220     x_z_curves[i] IS_A plt_curve(n_plt_points,x_plot[i],z_tray_loc);
1221     x_s_curves[i] IS_A plt_curve(n_plt_points,x_plot[i],s_tray_loc);
1222     y_z_curves[i] IS_A plt_curve(n_plt_points,y_plot[i],z_tray_loc);
1223     y_s_curves[i] IS_A plt_curve(n_plt_points,y_plot[i],s_tray_loc);
1224     END FOR;
1225    
1226     Plot_xz IS_A plt_plot_symbol(components,x_z_curves);
1227     Plot_xs IS_A plt_plot_symbol(components,x_s_curves);
1228     Plot_yz IS_A plt_plot_symbol(components,y_z_curves);
1229     Plot_ys IS_A plt_plot_symbol(components,y_s_curves);
1230    
1231     METHODS
1232     METHOD default_self;
1233     y_coeff[components - [inactive_component]][0..y_order] := 0.5;
1234     x_coeff[components - [inactive_component]][0..x_order] := 0.5;
1235     td := 1.0;
1236    
1237     tray_x_hat['in','out'][components][1..ntrays].nominal := 20;
1238     tray_y_hat['in','out'][components][1..ntrays].nominal := 20;
1239     end_x_hat['top','bot'][components].nominal := 20;
1240     end_y_hat['top','bot'][components].nominal := 20;
1241    
1242     tray_x_hat['in','out'][components][1..ntrays] := 1;
1243     tray_y_hat['in','out'][components][1..ntrays] := 1;
1244     end_x_hat['top','bot'][components] := 1;
1245     end_y_hat['top','bot'][components] := 1;
1246    
1247     RUN liqin_mix[1..ntrays].default_self;
1248     RUN liqout_mix[1..ntrays].default_self;
1249     RUN vapin_mix[1..ntrays].default_self;
1250     RUN vapout_mix[1..ntrays].default_self;
1251    
1252     RUN liqin_state[1..ntrays].default_self;
1253     RUN liqout_state[1..ntrays].default_self;
1254     RUN vapin_state[1..ntrays].default_self;
1255     RUN vapout_state[1..ntrays].default_self;
1256     RUN tray_state[1..ntrays].default_self;
1257    
1258     RUN liqin[1..ntrays].default_self;
1259     RUN liqout[1..ntrays].default_self;
1260     RUN vapin[1..ntrays].default_self;
1261     RUN vapout[1..ntrays].default_self;
1262     RUN tray[1..ntrays].default_self;
1263    
1264     RUN z_set.default_self;
1265    
1266     z_shift := 0.0;
1267     s_shift := 0.0;
1268    
1269     Plot_xz.title := 'Liquid Compositions vs. z';
1270     Plot_xz.YLabel := 'Liquid Compositions';
1271     Plot_xz.XLabel := 'transformed stage location (z)';
1272     Plot_xz.Ylow := 0;
1273     Plot_xz.Yhigh := 1;
1274    
1275     Plot_xs.title := 'Liquid Compositions vs. s';
1276     Plot_xs.YLabel := 'Liquid Compositions';
1277     Plot_xs.XLabel := 'stage location (s)';
1278     Plot_xs.Ylow := 0;
1279     Plot_xs.Yhigh := 1;
1280    
1281     Plot_yz.title := 'Vapor Compositions vs. z';
1282     Plot_yz.YLabel := 'Vapor Compositions';
1283     Plot_yz.XLabel := 'transformed stage location (z)';
1284     Plot_yz.Ylow := 0;
1285     Plot_yz.Yhigh := 1;
1286    
1287     Plot_ys.title := 'Vapor Compositions vs. s';
1288     Plot_ys.YLabel := 'Vapor Compositions';
1289     Plot_ys.XLabel := 'stage location (s)';
1290     Plot_ys.Ylow := 0;
1291     Plot_ys.Yhigh := 1;
1292    
1293     FOR i IN components DO
1294     Plot_xz.curve[i].legend := i;
1295     Plot_xs.curve[i].legend := i;
1296     Plot_yz.curve[i].legend := i;
1297     Plot_ys.curve[i].legend := i;
1298     END FOR;
1299    
1300     END default_self;
1301     METHOD default_all;
1302     RUN default_self;
1303     z_on := FALSE;
1304     hat_on := FALSE;
1305    
1306     RUN topliq[1..ntrays].default_all;
1307     RUN botliq[1..ntrays].default_all;
1308     RUN topvap[1..ntrays].default_all;
1309     RUN botvap[1..ntrays].default_all;
1310    
1311     END default_all;
1312    
1313     METHOD values;
1314    
1315     END values;
1316    
1317     METHOD seqmod_massbal;
1318     hb_on := FALSE;
1319     equilibrated := FALSE;
1320     use_H_eqns := hb_on OR equilibrated;
1321    
1322 johnpye 576 FIX cmo[1..ntrays];
1323     FIX cmotot;
1324 aw0a 1
1325     RUN tray[1..ntrays].seqmod_massbal;
1326     RUN z_set.specify;
1327    
1328     RUN topliq.seqmod;
1329     RUN botvap.seqmod;
1330     RUN topvap.seqmod;
1331     RUN botliq.seqmod;
1332    
1333     RUN CMO;
1334    
1335 johnpye 576 FIX topvap.state.H;
1336     FIX botliq.state.H;
1337 aw0a 1
1338 johnpye 576 FIX liqin_state[1..ntrays].H;
1339     FIX tray[1..ntrays].Qin;
1340     FREE s_shift;
1341     FREE z_shift;
1342 aw0a 1 END seqmod_massbal;
1343    
1344     METHOD seqmod_fullthermo;
1345     hb_on := FALSE;
1346     equilibrated := TRUE;
1347     use_H_eqns := hb_on OR equilibrated;
1348    
1349 johnpye 576 FIX cmo[1..ntrays];
1350     FIX cmotot;
1351 aw0a 1 RUN tray[1..ntrays].seqmod_fullthermo;
1352     RUN z_set.specify;
1353    
1354     RUN topliq.seqmod;
1355     RUN botvap.seqmod;
1356     RUN topvap.seqmod;
1357     RUN botliq.seqmod;
1358    
1359     RUN CMO;
1360    
1361 johnpye 576 FREE topliq.state.T;
1362     FREE botvap.state.T;
1363     FREE topvap.state.T;
1364     FREE botliq.state.T;
1365 aw0a 1
1366    
1367 johnpye 576 FREE topliq.state.H;
1368     FREE botvap.state.H;
1369     FREE topvap.state.H;
1370     FREE botliq.state.H;
1371 aw0a 1
1372 johnpye 576 FREE s_shift;
1373     FREE z_shift;
1374 aw0a 1 END seqmod_fullthermo;
1375    
1376     METHOD seqmod_adiabatic;
1377     hb_on := TRUE;
1378     equilibrated := TRUE;
1379     use_H_eqns := hb_on OR equilibrated;
1380     RUN seqmod_fullthermo;
1381     RUN heat_balance;
1382 johnpye 576 FREE s_shift;
1383     FREE z_shift;
1384 aw0a 1 END seqmod_adiabatic;
1385    
1386     METHOD heat_balance;
1387     hb_on := TRUE;
1388     RUN tray[1..ntrays].heat_balance;
1389 johnpye 576 FIX Qtot;
1390     FREE cmotot;
1391     FIX Qin[1..ntrays];
1392     FREE cmo[1..ntrays];
1393 aw0a 1 END heat_balance;
1394     METHOD CMO;
1395     hb_on := FALSE;
1396 johnpye 576 FIX tray[1..ntrays].cmo_ratio;
1397     FREE tray[1..ntrays].Qin;
1398     FREE Qtot;
1399     FIX cmotot;
1400     FREE Qin[1..ntrays];
1401     FIX cmo[1..ntrays];
1402 aw0a 1 END CMO;
1403     METHOD specify;
1404     IF (hb_on AND NOT(equilibrated)) THEN
1405     equilibrated := TRUE;
1406     END IF;
1407     IF (hb_on AND equilibrated) THEN
1408     RUN seqmod_adiabatic;
1409     END IF;
1410     IF (NOT(hb_on) AND equilibrated) THEN
1411     RUN seqmod_fullthermo;
1412     END IF;
1413     IF (NOT(hb_on) AND NOT(equilibrated)) THEN
1414     RUN seqmod_massbal;
1415     END IF;
1416    
1417     RUN topliq.specify;
1418     RUN botvap.specify;
1419 johnpye 576 FIX s_shift;
1420     FIX z_shift;
1421 aw0a 1 END specify;
1422     METHOD reset;
1423     RUN ClearAll;
1424     RUN specify;
1425     END reset;
1426    
1427     METHOD reset_to_massbal;
1428     hb_on := FALSE;
1429     equilibrated := FALSE;
1430     RUN reset;
1431     END reset_to_massbal;
1432    
1433     METHOD reset_to_fullthermo;
1434     hb_on := FALSE;
1435     equilibrated := TRUE;
1436     RUN reset;
1437     END reset_to_fullthermo;
1438    
1439     METHOD reset_to_adiabatic;
1440     hb_on := TRUE;
1441     equilibrated := TRUE;
1442     RUN reset;
1443     END reset_to_adiabatic;
1444    
1445     METHOD zero_Q;
1446     reduce := 0;
1447     RUN reduce_Q;
1448     END zero_Q;
1449    
1450     METHOD reduce_Q;
1451     Qtot := reduce * Qtot;
1452     FOR i IN [1..ntrays] DO
1453     tray[i].Qin := reduce * tray[i].Qin;
1454     Qin[i] := reduce * Qin[i];
1455     END FOR;
1456     END reduce_Q;
1457    
1458     METHOD scale_self;
1459     RUN tray[1..ntrays].scale_self;
1460     RUN z_set.scale_self;
1461    
1462     RUN liqin_mix[1..ntrays].scale_self;
1463     RUN liqout_mix[1..ntrays].scale_self;
1464     RUN vapin_mix[1..ntrays].scale_self;
1465     RUN vapout_mix[1..ntrays].scale_self;
1466    
1467     RUN liqin_state[1..ntrays].scale_self;
1468     RUN liqout_state[1..ntrays].scale_self;
1469     RUN vapin_state[1..ntrays].scale_self;
1470     RUN vapout_state[1..ntrays].scale_self;
1471     RUN tray_state[1..ntrays].scale_self;
1472    
1473     RUN liqin[1..ntrays].scale_self;
1474     RUN liqout[1..ntrays].scale_self;
1475     RUN vapin[1..ntrays].scale_self;
1476     RUN vapout[1..ntrays].scale_self;
1477    
1478     FOR i IN components - [inactive_component] DO
1479     FOR j IN [0..x_order] DO
1480     x_coeff[i][j].nominal :=
1481     abs(x_coeff[i][j]) + 0.00001;
1482     END FOR;
1483     FOR j IN [0..y_order] DO
1484     y_coeff[i][j].nominal :=
1485     abs(y_coeff[i][j]) + 0.00001;
1486     END FOR;
1487     END FOR;
1488     FOR j IN [1..ntrays] DO
1489     cmo[j].nominal := cmo[j];
1490     END FOR;
1491     cmotot.nominal := cmotot;
1492     FOR i IN components DO
1493     FOR j IN [1..ntrays] DO
1494     x[j][i].nominal := x[j][i];
1495     y[j][i].nominal := y[j][i];
1496     x_hat[j][i].nominal := abs(x_hat[j][i]);
1497    
1498     FOR k IN ['in','out'] DO
1499     tray_x_hat[k][i][j].nominal :=
1500     abs(tray_x_hat[k][i][j]);
1501     tray_y_hat[k][i][j].nominal :=
1502     abs(tray_y_hat[k][i][j]);
1503     END FOR;
1504     END FOR;
1505     FOR k IN ['top','bot'] DO
1506     end_x_hat[k][i].nominal := abs(end_x_hat[k][i]);
1507     end_y_hat[k][i].nominal := abs(end_y_hat[k][i]);
1508     END FOR;
1509     slope[i].nominal := abs(slope[i]);
1510     END FOR;
1511     FOR i IN ['liquid','vapor'] DO
1512     FOR j IN [0..h_order] DO
1513     h_coeff[i][j].nominal := abs(h_coeff[i][j]);
1514     END FOR;
1515     END FOR;
1516     (*
1517     THIS CAUSES SEVERE PROBLEMS WHEN SWITCHING BETWEEN ADIABATIC AND
1518     MASS BALANCE: we need better scaling here
1519     Qtot.nominal := abs(Qtot);
1520     FOR j IN [1..ntrays] DO
1521     Qin[j].nominal := abs(Qin[j]);
1522     END FOR;
1523     *)
1524     END scale_self;
1525    
1526     METHOD scale_all;
1527     RUN topliq.scale_all;
1528     RUN topvap.scale_all;
1529     RUN botliq.scale_all;
1530     RUN botvap.scale_all;
1531     RUN scale_self;
1532     END scale_all;
1533    
1534     METHOD bound_self;
1535     RUN tray[1..ntrays].bound_self;
1536     RUN z_set.bound_self;
1537    
1538     (* NEED BETTER BOUNDING HERE!
1539     running these methods leads to convergence problems*)
1540     RUN liqin_mix[1..ntrays].bound_self;
1541     RUN liqout_mix[1..ntrays].bound_self;
1542     RUN vapin_mix[1..ntrays].bound_self;
1543     RUN vapout_mix[1..ntrays].bound_self;
1544    
1545     RUN liqin_state[1..ntrays].bound_self;
1546     RUN liqout_state[1..ntrays].bound_self;
1547     RUN vapin_state[1..ntrays].bound_self;
1548     RUN vapout_state[1..ntrays].bound_self;
1549     RUN tray_state[1..ntrays].bound_self;
1550    
1551     RUN liqin[1..ntrays].bound_self;
1552     RUN liqout[1..ntrays].bound_self;
1553     RUN vapin[1..ntrays].bound_self;
1554     RUN vapout[1..ntrays].bound_self;
1555    
1556    
1557     IF (hat_on == TRUE) THEN
1558     x_coeff[components - [inactive_component]][0..x_order].lower_bound
1559     := -18;
1560     x_coeff[components - [inactive_component]][0..x_order].upper_bound
1561     := 18;
1562     ELSE
1563     x_coeff[components - [inactive_component]][0..x_order].lower_bound
1564     := 0;
1565     x_coeff[components - [inactive_component]][0..x_order].upper_bound
1566     := 0;
1567     END IF;
1568     FOR j IN [1..ntrays] DO
1569     cmo[j].lower_bound := 1e-8;
1570     cmo[j].upper_bound := cmo[j] + scale*cmo[j].nominal;
1571     END FOR;
1572     cmotot.lower_bound := 1e-8;
1573     (* NEED BETTER SCALING HERE
1574     cmotot.upper_bound := cmotot + scale*cmotot.nominal;
1575     *)
1576     x_hat[1..ntrays][components].lower_bound
1577     := -18;
1578     x_hat[1..ntrays][components].upper_bound
1579     := 18;
1580     FOR i IN components DO
1581     FOR j IN [1..ntrays] DO
1582     FOR k IN ['in','out'] DO
1583     tray_x_hat[k][i][j].lower_bound := -18;
1584     tray_x_hat[k][i][j].upper_bound := 18;
1585     tray_y_hat[k][i][j].lower_bound := -18;
1586     tray_y_hat[k][i][j].upper_bound := 18;
1587     END FOR;
1588     END FOR;
1589     FOR k IN ['top','bot'] DO
1590     end_x_hat[k][i].lower_bound := -18;
1591     end_x_hat[k][i].upper_bound := 18;
1592     end_y_hat[k][i].lower_bound := -18;
1593     end_y_hat[k][i].upper_bound := 18;
1594     END FOR;
1595     slope[i].lower_bound := 0;
1596     slope[i].upper_bound := 1/z_set.stot.lower_bound;
1597     END FOR;
1598    
1599     (* NEED BETTER BOUNDING HERE!
1600     h_coeff['vapor'][1..h_order].lower_bound :=
1601     tray[1].vapout.state.H.lower_bound;
1602     h_coeff['vapor'][1..h_order].upper_bound :=
1603     tray[1].vapout.state.H.upper_bound;
1604     h_coeff['liquid'][1..h_order].lower_bound :=
1605     tray[1].vapout.state.H.lower_bound;
1606     h_coeff['liquid'][1..h_order].upper_bound :=
1607     tray[1].vapout.state.H.upper_bound;
1608     *)
1609     (*
1610     THIS CAUSES SEVERE PROBLEMS WHEN SWITCHING BETWEEN ADIABATIC AND
1611     MASS BALANCE: we need better bounding here
1612     Qtot.lower_bound := Qtot - scale*Qtot.nominal;
1613     Qtot.upper_bound := Qtot + scale*Qtot.nominal;
1614     FOR j IN [1..ntrays] DO
1615     Qin[j].lower_bound := Qin[j] - scale*Qin[j].nominal;
1616     Qin[j].upper_bound := Qin[j] + scale*Qin[j].nominal;
1617     END FOR;
1618     *)
1619     END bound_self;
1620    
1621     METHOD bound_all;
1622     RUN topliq.bound_all;
1623     RUN topvap.bound_all;
1624     RUN botliq.bound_all;
1625     RUN botvap.bound_all;
1626     RUN bound_self;
1627     END bound_all;
1628    
1629    
1630     METHOD s_off;
1631     RUN z_set.s_off;
1632     END s_off;
1633     END coll;
1634    
1635    
1636    
1637     MODEL std_coll_stack(
1638     ntrays WILL_BE integer_constant;
1639     topvap WILL_BE stream;
1640     topliq WILL_BE stream;
1641     botvap WILL_BE stream;
1642     botliq WILL_BE stream;
1643     pdL WILL_BE phases_data;
1644     pdV WILL_BE phases_data;
1645     reduce WILL_BE fraction;
1646     equilibrated WILL_BE boolean;
1647     z_on WILL_BE boolean;
1648     hat_on WILL_BE boolean;
1649     hb_on WILL_BE boolean;
1650     );
1651    
1652     cd ALIASES topliq.state.cd;
1653     vap_option ALIASES pdV.vapor_option;
1654     liq_option ALIASES pdL.liquid1_option;
1655     pdVL IS_A phases_data('VL', vap_option, liq_option, 'none');
1656     pdM IS_A phases_data('M', 'none', 'none', 'none');
1657     mat_option ALIASES pdM.liquid1_option; (* none *)
1658    
1659     FOR i IN [1..ncolls-1] CREATE
1660     internal_liquid[i] IS_A coll_material_stream(cd,pdM,equilibrated);
1661     internal_vapor[i] IS_A coll_material_stream(cd,pdM,equilibrated);
1662     END FOR;
1663    
1664     coll_vapin[csV] ALIASES
1665     (topvap, internal_vapor[1..ncolls-1], botvap)
1666     WHERE csV IS_A set OF integer_constant
1667     WITH_VALUE (0..ncolls);
1668     coll_liqin[csL] ALIASES
1669     (topliq, internal_liquid[1..ncolls-1], botliq)
1670     WHERE csL IS_A set OF integer_constant
1671     WITH_VALUE (1..ncolls+1);
1672    
1673     Coll_set IS_A set OF integer_constant;
1674    
1675     ncolls IS_A integer_constant;
1676     ncolls :== 2;
1677    
1678     up_down[1..ncolls] IS_A real;
1679    
1680     a IS_A factor;
1681    
1682     FOR i IN [1..ncolls] CREATE
1683     coll[i] IS_A coll(
1684     ntrays,
1685     coll_vapin[i-1],
1686     coll_liqin[i],
1687     coll_vapin[i],
1688     coll_liqin[i+1],
1689     pdL,
1690     pdV,
1691     reduce,
1692     equilibrated,
1693     up_down[i],
1694     a,
1695     z_on,
1696     hat_on,
1697     hb_on
1698     );
1699     END FOR;
1700    
1701     straight_choice IS_A symbol_constant;
1702     split[1..ncolls] IS_A fraction;
1703     stot IS_A factor;
1704     scale IS_A scaling_constant;
1705    
1706     FOR j IN [1..ncolls] CREATE
1707     tray_split[j]: coll[j].z_set.stot = split[j]*stot;
1708     END FOR;
1709    
1710     stot_def: stot = SUM[coll[j].z_set.stot | j IN [1..ncolls]];
1711    
1712    
1713     (* Plotting Section *)
1714     z_shift IS_A factor;
1715     s_shift IS_A factor;
1716    
1717     n_plt_points IS_A set OF integer_constant;
1718     n_plt_points :== [0..ncolls*(ntrays+1)];
1719    
1720     z_loc_1: coll[1].z_shift = z_shift;
1721     s_loc_1: coll[1].s_shift = s_shift;
1722     FOR i IN [2..ncolls] CREATE
1723     z_loc[i]: coll[i].z_shift = coll[i-1].z_shift +
1724     coll[i-1].z_set.z_values[ntrays+1];
1725     s_loc[i]: coll[i].s_shift = coll[i-1].s_shift +
1726     coll[i-1].z_set.s_values[ntrays+1];
1727     END FOR;
1728    
1729    
1730     z_tray_loc[tp] ALIASES (
1731     coll[1].z_tray_loc[0],
1732     coll[1..ncolls].z_tray_loc[1..ntrays+1]
1733     ) WHERE
1734     tp IS_A set OF integer_constant
1735     WITH_VALUE (0..ncolls*(ntrays+1));
1736    
1737     s_tray_loc[tp2] ALIASES (
1738     coll[1].s_tray_loc[0],
1739     coll[1..ncolls].s_tray_loc[1..ntrays+1]
1740     ) WHERE
1741     tp2 IS_A set OF integer_constant
1742     WITH_VALUE (0..ncolls*(ntrays+1));
1743    
1744    
1745     FOR i IN topliq.components CREATE
1746     x_plot[i][np[i]] ALIASES (
1747     topliq.state.y[i],
1748     coll[1..ncolls].x_plot[i][1..ntrays+1]
1749     ) WHERE
1750     np[i] IS_A set OF integer_constant
1751     WITH_VALUE (0..ncolls*(ntrays+1));
1752     y_plot[i][np2[i]] ALIASES (
1753     topvap.state.y[i],
1754     coll[1..ncolls].y_plot[i][1..ntrays+1]
1755     ) WHERE
1756     np2[i] IS_A set OF integer_constant
1757     WITH_VALUE (0..ncolls*(ntrays+1));
1758     END FOR;
1759    
1760     FOR i IN topliq.components CREATE
1761     x_z_curves[i] IS_A plt_curve(n_plt_points,x_plot[i],z_tray_loc);
1762     x_s_curves[i] IS_A plt_curve(n_plt_points,x_plot[i],s_tray_loc);
1763     y_z_curves[i] IS_A plt_curve(n_plt_points,y_plot[i],z_tray_loc);
1764     y_s_curves[i] IS_A plt_curve(n_plt_points,y_plot[i],s_tray_loc);
1765     END FOR;
1766    
1767     Plot_xz IS_A plt_plot_symbol(topliq.components,x_z_curves);
1768     Plot_xs IS_A plt_plot_symbol(topliq.components,x_s_curves);
1769    
1770     Plot_yz IS_A plt_plot_symbol(topliq.components,y_z_curves);
1771     Plot_ys IS_A plt_plot_symbol(topliq.components,y_s_curves);
1772    
1773     METHODS
1774     METHOD default_self;
1775     up_down[1] := -1;
1776     up_down[2] := 1;
1777     a := 0.1;
1778     a.lower_bound := 0.0;
1779     a.upper_bound := 3.0;
1780     stot := 2;
1781     stot.lower_bound := 2;
1782     split[1..ncolls] := 1.0/ncolls;
1783     RUN internal_liquid[1..ncolls-1].default_self;
1784     RUN internal_vapor[1..ncolls-1].default_self;
1785     RUN coll[1..ncolls].default_self;
1786    
1787     z_shift := 0.0;
1788     s_shift := 0.0;
1789    
1790     Plot_xz.title := 'Liquid Compositions vs. z';
1791     Plot_xz.YLabel := 'Liquid Compositions';
1792     Plot_xz.XLabel := 'transformed stage location (z)';
1793     Plot_xz.Ylow := 0;
1794     Plot_xz.Yhigh := 1;
1795    
1796     Plot_xs.title := 'Liquid Compositions vs. s';
1797     Plot_xs.YLabel := 'Liquid Compositions';
1798     Plot_xs.XLabel := 'stage location (s)';
1799     Plot_xs.Ylow := 0;
1800     Plot_xs.Yhigh := 1;
1801    
1802     Plot_yz.title := 'Vapor Compositions vs. z';
1803     Plot_yz.YLabel := 'Vapor Compositions';
1804     Plot_yz.XLabel := 'transformed stage location (z)';
1805     Plot_yz.Ylow := 0;
1806     Plot_yz.Yhigh := 1;
1807    
1808     Plot_ys.title := 'Vapor Compositions vs. s';
1809     Plot_ys.YLabel := 'Vapor Compositions';
1810     Plot_ys.XLabel := 'stage location (s)';
1811     Plot_ys.Ylow := 0;
1812     Plot_ys.Yhigh := 1;
1813    
1814    
1815     FOR i IN topliq.components DO
1816     Plot_xz.curve[i].legend := i;
1817     Plot_xs.curve[i].legend := i;
1818     Plot_yz.curve[i].legend := i;
1819     Plot_ys.curve[i].legend := i;
1820     END FOR;
1821    
1822     END default_self;
1823     METHOD default_all;
1824     RUN topvap[1..ntrays].default_all;
1825     RUN topliq[1..ntrays].default_all;
1826     RUN botvap[1..ntrays].default_all;
1827     RUN botliq[1..ntrays].default_all;
1828     (* reduce := *)
1829     RUN default_self;
1830     END default_all;
1831     METHOD scale_self;
1832     stot.nominal := stot;
1833     RUN internal_liquid[1..ncolls-1].scale_self;
1834     RUN internal_vapor[1..ncolls-1].scale_self;
1835     RUN coll[1..ncolls].scale_self;
1836     END scale_self;
1837     METHOD scale_all;
1838     RUN topvap[1..ntrays].scale_all;
1839     RUN topliq[1..ntrays].scale_all;
1840     RUN botvap[1..ntrays].scale_all;
1841     RUN botliq[1..ntrays].scale_all;
1842     (* reduce := *)
1843     RUN scale_self;
1844     END scale_all;
1845     METHOD bound_self;
1846     coll[1..ncolls].z_set.stot.upper_bound :=
1847     stot.upper_bound/ncolls + 1.0;
1848     RUN internal_liquid[1..ncolls-1].bound_self;
1849     RUN internal_vapor[1..ncolls-1].bound_self;
1850     RUN coll[1..ncolls].bound_self;
1851     END bound_self;
1852     METHOD bound_all;
1853     RUN topvap[1..ntrays].bound_all;
1854     RUN topliq[1..ntrays].bound_all;
1855     RUN botvap[1..ntrays].bound_all;
1856     RUN botliq[1..ntrays].bound_all;
1857     (* reduce := *)
1858     RUN bound_self;
1859     END bound_all;
1860     METHOD check_self;
1861     END check_self;
1862     METHOD check_all;
1863     RUN check_self;
1864     END check_all;
1865    
1866     METHOD values;
1867    
1868     RUN coll[1..ncolls].values;
1869     END values;
1870     METHOD seqmod_massbal;
1871     hb_on := FALSE;
1872     equilibrated := FALSE;
1873     RUN coll[1..ncolls].seqmod_massbal;
1874     FOR j IN [1..ncolls] DO
1875 johnpye 576 (*FREE coll[j].botliq.state.H;*)
1876 aw0a 1
1877     coll[j].z_set
1878 johnpye 576 .FREE z_values[coll[j].ntrays+1];
1879     FREE coll[j].z_set.stot;
1880 aw0a 1 END FOR;
1881 johnpye 576 FIX stot;
1882     FIX split[1..ncolls-1];
1883 aw0a 1 IF (hb_on) THEN
1884     RUN heat_balance;
1885     END IF;
1886 johnpye 576 FREE z_shift;
1887     FREE s_shift;
1888 aw0a 1 END seqmod_massbal;
1889    
1890     METHOD seqmod_fullthermo;
1891     hb_on := FALSE;
1892     equilibrated := TRUE;
1893     RUN coll[1..ncolls].seqmod_fullthermo;
1894     FOR j IN [1..ncolls] DO
1895 johnpye 576 (*FREE coll[j].botliq.state.H;*)
1896 aw0a 1
1897     coll[j].z_set
1898 johnpye 576 .FREE z_values[coll[j].ntrays+1];
1899     FREE coll[j].z_set.stot;
1900 aw0a 1 END FOR;
1901 johnpye 576 FIX stot;
1902     FIX split[1..ncolls-1];
1903 aw0a 1 IF (hb_on) THEN
1904     RUN heat_balance;
1905     END IF;
1906    
1907 johnpye 576 FREE z_shift;
1908     FREE s_shift;
1909 aw0a 1 END seqmod_fullthermo;
1910    
1911     METHOD seqmod_adiabatic;
1912     hb_on := TRUE;
1913     equilibrated := TRUE;
1914     RUN coll[1..ncolls].seqmod_adiabatic;
1915     FOR j IN [1..ncolls] DO
1916 johnpye 576 (*FREE coll[j].botliq.state.H;*)
1917 aw0a 1
1918     coll[j].z_set
1919 johnpye 576 .FREE z_values[coll[j].ntrays+1];
1920     FREE coll[j].z_set.stot;
1921 aw0a 1 END FOR;
1922 johnpye 576 FIX stot;
1923     FIX split[1..ncolls-1];
1924 aw0a 1 IF (hb_on) THEN
1925     RUN heat_balance;
1926     END IF;
1927    
1928 johnpye 576 FREE z_shift;
1929     FREE s_shift;
1930 aw0a 1 END seqmod_adiabatic;
1931    
1932    
1933     METHOD specify;
1934     IF (hb_on AND NOT(equilibrated)) THEN
1935     equilibrated := TRUE;
1936     END IF;
1937     IF (hb_on AND equilibrated) THEN
1938     RUN seqmod_adiabatic;
1939     END IF;
1940     IF (NOT(hb_on) AND equilibrated) THEN
1941     RUN seqmod_fullthermo;
1942     END IF;
1943     IF (NOT(hb_on) AND NOT(equilibrated)) THEN
1944     RUN seqmod_massbal;
1945     END IF;
1946     RUN coll[1].topliq.specify;
1947     RUN coll[ncolls].botvap.specify;
1948 johnpye 576 FIX z_shift;
1949     FIX s_shift;
1950 aw0a 1 END specify;
1951     METHOD reset;
1952     RUN ClearAll;
1953     RUN specify;
1954     END reset;
1955     METHOD standard_poly;
1956     RUN coll[1..ncolls].standard_poly;
1957     END standard_poly;
1958     METHOD trans_poly;
1959     RUN coll[1..ncolls].trans_poly;
1960     END trans_poly;
1961     METHOD z_based_poly;
1962     RUN coll[1..ncolls].z_based_poly;
1963     END z_based_poly;
1964     METHOD s_based_poly;
1965     RUN coll[1..ncolls].s_based_poly;
1966     END s_based_poly;
1967    
1968     METHOD heat_balance;
1969     RUN coll[1..ncolls].heat_balance;
1970     END heat_balance;
1971    
1972     METHOD reset_to_massbal;
1973     hb_on := FALSE;
1974     equilibrated := FALSE;
1975     RUN reset;
1976     END reset_to_massbal;
1977    
1978     METHOD reset_to_fullthermo;
1979     hb_on := FALSE;
1980     equilibrated := TRUE;
1981     RUN reset;
1982     END reset_to_fullthermo;
1983    
1984     METHOD reset_to_adiabatic;
1985     hb_on := TRUE;
1986     equilibrated := TRUE;
1987     RUN reset;
1988     END reset_to_adiabatic;
1989    
1990     METHOD reduce_Q;
1991     RUN coll[1..ncolls].reduce_Q;
1992     END reduce_Q;
1993    
1994     METHOD zero_Q;
1995     reduce := 0;
1996     RUN reduce_Q;
1997     END zero_Q;
1998    
1999     METHOD CMO;
2000     RUN coll[1..ncolls].CMO;
2001     END CMO;
2002    
2003    
2004     END std_coll_stack;
2005    
2006     MODEL simple_coll_column(
2007     ntrays WILL_BE integer_constant;
2008     pdVL WILL_BE phases_data;
2009     distillate WILL_BE stream;
2010     feed WILL_BE stream;
2011     bottoms WILL_BE stream;
2012     equilibrated WILL_BE boolean;
2013     reduce WILL_BE fraction;
2014     z_on WILL_BE boolean;
2015     hat_on WILL_BE boolean;
2016     hb_on WILL_BE boolean;
2017     ) WHERE (
2018     distillate, bottoms, feed WILL_NOT_BE_THE_SAME;
2019     feed.cd, distillate.cd, bottoms.cd WILL_BE_THE_SAME;
2020     pdVL.phase_indicator == 'VL';
2021     distillate.pd.phase_indicator IN ['L','VL'] == TRUE;
2022     pdVL.liquid1_option == distillate.pd.liquid1_option;
2023     feed.pd.phase_indicator IN ['V','L','VL'] == TRUE;
2024     );
2025    
2026     pdL ALIASES bottoms.pd;
2027     pdV IS_A phases_data('V', pdVL.vapor_option, 'none', 'none');
2028     pdM IS_A phases_data('M', 'none', 'none', 'none');
2029     cd ALIASES feed.cd;
2030     components ALIASES feed.components;
2031    
2032     nfeeds IS_A integer_constant;
2033     nfeeds :== 1;
2034    
2035     coll_stack[cs] ALIASES
2036     (rectifying_section,stripping_section)
2037     WHERE cs IS_A set OF integer_constant
2038     WITH_VALUE (1..2);
2039    
2040     (*feed condition*)
2041     saturated_liquid_feed IS_A start_true;
2042     saturated_vapor_feed IS_A start_false;
2043    
2044     (* inter-section streams *)
2045     rectifier_vapin "vapor rising from feed tray",
2046     stripper_vapin "vapor rising from reboiler"
2047     IS_A stream(cd, pdV, equilibrated);
2048    
2049     condenser_vapin "vapor rising to condenser",
2050     feed_tray_vapin "vapor rising from stripper"
2051     IS_A coll_material_stream(cd, pdM, equilibrated);
2052    
2053     rectifier_liqin "reflux condensate",
2054     stripper_liqin "liquid falling from feed tray"
2055     IS_A stream(cd, pdL, equilibrated);
2056    
2057     feed_tray_liqin "liquid falling from rectifier",
2058     reboiler_liqin "liquid falling to reboiler"
2059     IS_A coll_material_stream(cd, pdM, equilibrated);
2060    
2061     (* typical heat duties *)
2062     Qin_condenser "condenser duty",
2063     Qin_feed "feed heater duty",
2064     Qin_reboiler "reboiler duty" IS_A energy_rate;
2065    
2066     (* column sections *)
2067     condenser IS_A coll_partial_condenser(
2068     Qin_condenser,
2069     condenser_vapin,
2070     rectifier_liqin,
2071     distillate,
2072     equilibrated
2073     );
2074     rectifying_section "the trays above the feed" IS_A std_coll_stack(
2075     ntrays,
2076     condenser_vapin,
2077     rectifier_liqin,
2078     rectifier_vapin,
2079     feed_tray_liqin,
2080     pdL,
2081     pdV,
2082     reduce,
2083     equilibrated,
2084     z_on,
2085     hat_on,
2086     hb_on
2087     );
2088     feed_tray IS_A coll_feed_tray(
2089     Qin_feed,
2090     equilibrated,
2091     feed,
2092     feed_tray_liqin,
2093     feed_tray_vapin,
2094     stripper_liqin,
2095     rectifier_vapin
2096     );
2097     stripping_section "the trays below the feed" IS_A std_coll_stack(
2098     ntrays,
2099     feed_tray_vapin,
2100     stripper_liqin,
2101     stripper_vapin,
2102     reboiler_liqin,
2103     pdL,
2104     pdV,
2105     reduce,
2106     equilibrated,
2107     z_on,
2108     hat_on,
2109     hb_on
2110     );
2111     reboiler IS_A coll_simple_reboiler(
2112     Qin_reboiler,
2113     equilibrated,
2114     reboiler_liqin,
2115     stripper_vapin,
2116     bottoms
2117     );
2118    
2119     stot,
2120     s_stack[1..nfeeds+1] IS_A factor;
2121     split[1..nfeeds+1] IS_A fraction;
2122     xsi[components] IS_A fraction;
2123     xsi_set[components] IS_A fraction;
2124     xsi_diff[components] IS_A fraction;
2125     scale IS_A scaling_constant;
2126    
2127     s_stack[1],
2128     rectifying_section.stot ARE_THE_SAME;
2129     s_stack[2],
2130     stripping_section.stot ARE_THE_SAME;
2131     stot = SUM[s_stack[1..nfeeds+1]];
2132    
2133     FOR j IN [1..nfeeds+1] CREATE
2134    
2135     tray_split[j]: s_stack[j] = split[j]*stot;
2136     END FOR;
2137    
2138     FOR i IN components CREATE
2139     OverallMB[i]: feed_tray.feed.f[i] =
2140     condenser.distillate.f[i] +
2141     reboiler.bottoms.f[i];
2142     END FOR;
2143    
2144     FOR i IN components CREATE
2145     xsi[i]*feed_tray.feed.f[i]
2146     = condenser.distillate.f[i];
2147     xsi_diff[i] = 0.5*sqr(xsi[i] - xsi_set[i]);
2148     END FOR;
2149    
2150     recovery: MINIMIZE SUM[xsi_diff[i] | i IN components];
2151    
2152     binary_sep[components][components] IS_A factor;
2153    
2154     FOR i IN components CREATE
2155     FOR j IN components CREATE
2156     binary_sep[i][j] *
2157     (condenser.distillate.f[i] + condenser.distillate.f[j]) *
2158     (reboiler.bottoms.f[i] + reboiler.bottoms.f[j]) =
2159     (condenser.distillate.f[i] *
2160     (reboiler.bottoms.f[i] + reboiler.bottoms.f[j]) -
2161     reboiler.bottoms.f[i] *
2162     (condenser.distillate.f[i] + condenser.distillate.f[j]));
2163    
2164     sep_opt[i][j]: MINIMIZE -sqr(binary_sep[i][j]);
2165    
2166     END FOR;
2167     END FOR;
2168    
2169     (* costing *)
2170     V[ns] ALIASES
2171     (coll_stack[1..nfeeds+1].coll[1].tray[1].vapout.flow)
2172     WHERE ns IS_A set OF integer_constant
2173     WITH_VALUE (1..nfeeds+1);
2174    
2175     V_bar[ns2] ALIASES
2176     (coll_stack[1..nfeeds+1].coll[1].tray[1].vapout.state.V)
2177     WHERE ns2 IS_A set OF integer_constant
2178     WITH_VALUE (1..nfeeds+1);
2179    
2180     M_g IS_A molar_mass;
2181    
2182     mol_mass: M_g = SUM[feed.Details.state.cd.data[i].mw*
2183     feed_tray.vapout.state.y[i]
2184     | i IN components];
2185    
2186     nsections IS_A integer_constant;
2187     nsections :== nfeeds+1;
2188    
2189     column_cost IS_A cost_per_time;
2190     cost_calc IS_A cost_calc(
2191     column_cost,
2192     distillate.state.T,
2193     condenser.Qin,
2194     reboiler.Qin,
2195     nsections,
2196     V,
2197     V_bar,
2198     stot,
2199     M_g,
2200     feed.flow
2201     );
2202    
2203     objmult IS_A factor;
2204     opcost, capcost IS_A cost_per_time;
2205     optime IS_A fraction;
2206     op_cost_def: opcost = cost_calc.water_cost + cost_calc.steam_cost;
2207     cap_cost_def: capcost = cost_calc.column_cost +
2208     cost_calc.condenser_cost +
2209     cost_calc.reboiler_cost;
2210     tot_cost: MINIMIZE objmult*(capcost + optime*opcost);
2211     cap_cost: MINIMIZE objmult*capcost;
2212     op_cost: MINIMIZE objmult*opcost;
2213    
2214     (*
2215     * Cost calculation doesn't mean much for constant alpha case.
2216     * We do provide overide though. :)
2217     *)
2218    
2219     WHEN (equilibrated)
2220     CASE TRUE:
2221     USE cost_calc;
2222     USE mol_mass;
2223     USE tot_cost;
2224     USE cap_cost;
2225     USE op_cost;
2226     USE cap_cost_def;
2227     USE op_cost_def;
2228     OTHERWISE:
2229     END WHEN;
2230    
2231     do_cost_calc IS_A boolean;
2232     WHEN (do_cost_calc)
2233     CASE TRUE:
2234     USE cost_calc;
2235     USE mol_mass;
2236     USE tot_cost;
2237     USE cap_cost;
2238     USE op_cost;
2239     USE cap_cost_def;
2240     USE op_cost_def;
2241     OTHERWISE:
2242     END WHEN;
2243    
2244    
2245     (* Plotting Section *)
2246     z_shift IS_A factor;
2247     s_shift IS_A factor;
2248    
2249     n_plt_points_x IS_A set OF integer_constant;
2250     n_plt_points_x :== [0..(nfeeds+1)*(coll_stack[1].ncolls*ntrays+3)];
2251     n_plt_points_y IS_A set OF integer_constant;
2252     n_plt_points_y :== [0..(nfeeds+1)*(coll_stack[1].ncolls*ntrays+3)-1];
2253    
2254     z_loc_1: coll_stack[1].z_shift = z_shift;
2255     s_loc_1: coll_stack[1].s_shift = s_shift;
2256    
2257     z_space IS_A factor;
2258    
2259     FOR i IN [2..nfeeds+1] CREATE
2260     z_loc[i]: coll_stack[i].z_shift =
2261     coll_stack[i-1].z_tray_loc[CARD[coll_stack[i-1].n_plt_points]-1]
2262     + z_space; (* add arbitrary factor *)
2263     s_loc[i]: coll_stack[i].s_shift =
2264     coll_stack[i-1].s_tray_loc[coll_stack[1].ncolls*(ntrays+1)]
2265     + 1; (* FOR feed tray *)
2266     END FOR;
2267    
2268    
2269     reboiler_s_loc, reboiler_z_loc IS_A factor;
2270    
2271     z_tray_loc_x[tp] ALIASES (
2272     coll_stack[1..nfeeds+1].z_tray_loc[0..coll_stack[1].ncolls*(ntrays+1)]
2273     , reboiler_z_loc
2274     ) WHERE
2275     tp IS_A set OF integer_constant
2276     WITH_VALUE (0..(nfeeds+1)*(coll_stack[1].ncolls*ntrays+3));
2277    
2278     s_tray_loc_x[tp2] ALIASES (
2279     coll_stack[1..nfeeds+1].s_tray_loc[0..coll_stack[1].ncolls*(ntrays+1)]
2280     , reboiler_s_loc
2281     ) WHERE
2282     tp2 IS_A set OF integer_constant
2283     WITH_VALUE (0..(nfeeds+1)*(coll_stack[1].ncolls*ntrays+3));
2284    
2285     reb_s_loc: reboiler_s_loc = 1 +
2286     s_tray_loc_x[(nfeeds+1)*(coll_stack[1].ncolls*ntrays+3)-1];
2287     reb_z_loc: reboiler_z_loc =
2288     coll_stack[nfeeds+1].
2289     z_tray_loc[CARD[coll_stack[nfeeds+1].n_plt_points]-1] +
2290     z_space;
2291    
2292     z_tray_loc_y[tp3] ALIASES (
2293     coll_stack[1..nfeeds+1].z_tray_loc[0..coll_stack[1].ncolls*(ntrays+1)]
2294     ) WHERE
2295     tp3 IS_A set OF integer_constant
2296     WITH_VALUE (