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

Annotation of /trunk/models/collocation.a4l

Parent Directory Parent Directory | Revision Log Revision Log


Revision 835 - (hide annotations) (download) (as text)
Wed Sep 6 15:52:46 2006 UTC (17 years, 9 months ago) by aw0a
File MIME type: text/x-ascend
File size: 71589 byte(s)
corrected collocation.a4l errors created when changing FIXED 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 aw0a 835 FREE coll[j].z_set.z_values[coll[j].ntrays+1];
1878 johnpye 576 FREE coll[j].z_set.stot;
1879 aw0a 1 END FOR;
1880 johnpye 576 FIX stot;
1881     FIX split[1..ncolls-1];
1882 aw0a 1 IF (hb_on) THEN
1883     RUN heat_balance;
1884     END IF;
1885 johnpye 576 FREE z_shift;
1886     FREE s_shift;
1887 aw0a 1 END seqmod_massbal;
1888    
1889     METHOD seqmod_fullthermo;
1890     hb_on := FALSE;
1891     equilibrated := TRUE;
1892     RUN coll[1..ncolls].seqmod_fullthermo;
1893     FOR j IN [1..ncolls] DO
1894 johnpye 576 (*FREE coll[j].botliq.state.H;*)
1895 aw0a 1
1896 aw0a 835 FREE coll[j].z_set.z_values[coll[j].ntrays+1];
1897 johnpye 576 FREE coll[j].z_set.stot;
1898 aw0a 1 END FOR;
1899 johnpye 576 FIX stot;
1900     FIX split[1..ncolls-1];
1901 aw0a 1 IF (hb_on) THEN
1902     RUN heat_balance;
1903     END IF;
1904    
1905 johnpye 576 FREE z_shift;
1906     FREE s_shift;
1907 aw0a 1 END seqmod_fullthermo;
1908    
1909     METHOD seqmod_adiabatic;
1910     hb_on := TRUE;
1911     equilibrated := TRUE;
1912     RUN coll[1..ncolls].seqmod_adiabatic;
1913     FOR j IN [1..ncolls] DO
1914 johnpye 576 (*FREE coll[j].botliq.state.H;*)
1915 aw0a 1
1916 aw0a 835 FREE coll[j].z_set.z_values[coll[j].ntrays+1];
1917 johnpye 576 FREE coll[j].z_set.stot;
1918 aw0a 1 END FOR;
1919 johnpye 576 FIX stot;
1920     FIX split[1..ncolls-1];
1921 aw0a 1 IF (hb_on) THEN
1922     RUN heat_balance;
1923     END IF;
1924    
1925 johnpye 576 FREE z_shift;
1926     FREE s_shift;
1927 aw0a 1 END seqmod_adiabatic;
1928    
1929    
1930     METHOD specify;
1931     IF (hb_on AND NOT(equilibrated)) THEN
1932     equilibrated := TRUE;
1933     END IF;
1934     IF (hb_on AND equilibrated) THEN
1935     RUN seqmod_adiabatic;
1936     END IF;
1937     IF (NOT(hb_on) AND equilibrated) THEN
1938     RUN seqmod_fullthermo;
1939     END IF;
1940     IF (NOT(hb_on) AND NOT(equilibrated)) THEN
1941     RUN seqmod_massbal;
1942     END IF;
1943     RUN coll[1].topliq.specify;
1944     RUN coll[ncolls].botvap.specify;
1945 johnpye 576 FIX z_shift;
1946     FIX s_shift;
1947 aw0a 1 END specify;
1948     METHOD reset;
1949     RUN ClearAll;
1950     RUN specify;
1951     END reset;
1952     METHOD standard_poly;
1953     RUN coll[1..ncolls].standard_poly;
1954     END standard_poly;
1955     METHOD trans_poly;
1956     RUN coll[1..ncolls].trans_poly;
1957     END trans_poly;
1958     METHOD z_based_poly;
1959     RUN coll[1..ncolls].z_based_poly;
1960     END z_based_poly;
1961     METHOD s_based_poly;
1962     RUN coll[1..ncolls].s_based_poly;
1963     END s_based_poly;
1964    
1965     METHOD heat_balance;
1966     RUN coll[1..ncolls].heat_balance;
1967     END heat_balance;
1968    
1969     METHOD reset_to_massbal;
1970     hb_on := FALSE;
1971     equilibrated := FALSE;
1972     RUN reset;
1973     END reset_to_massbal;
1974    
1975     METHOD reset_to_fullthermo;
1976     hb_on := FALSE;
1977     equilibrated := TRUE;
1978     RUN reset;
1979     END reset_to_fullthermo;
1980    
1981     METHOD reset_to_adiabatic;
1982     hb_on := TRUE;
1983     equilibrated := TRUE;
1984     RUN reset;
1985     END reset_to_adiabatic;
1986    
1987     METHOD reduce_Q;
1988     RUN coll[1..ncolls].reduce_Q;
1989     END reduce_Q;
1990    
1991     METHOD zero_Q;
1992     reduce := 0;
1993     RUN reduce_Q;
1994     END zero_Q;
1995    
1996     METHOD CMO;
1997     RUN coll[1..ncolls].CMO;
1998     END CMO;
1999    
2000    
2001     END std_coll_stack;
2002    
2003     MODEL simple_coll_column(
2004     ntrays WILL_BE integer_constant;
2005     pdVL WILL_BE phases_data;
2006     distillate WILL_BE stream;
2007     feed WILL_BE stream;
2008     bottoms WILL_BE stream;
2009     equilibrated WILL_BE boolean;
2010     reduce WILL_BE fraction;
2011     z_on WILL_BE boolean;
2012     hat_on WILL_BE boolean;
2013     hb_on WILL_BE boolean;
2014     ) WHERE (
2015     distillate, bottoms, feed WILL_NOT_BE_THE_SAME;
2016     feed.cd, distillate.cd, bottoms.cd WILL_BE_THE_SAME;
2017     pdVL.phase_indicator == 'VL';
2018     distillate.pd.phase_indicator IN ['L','VL'] == TRUE;
2019     pdVL.liquid1_option == distillate.pd.liquid1_option;
2020     feed.pd.phase_indicator IN ['V','L','VL'] == TRUE;
2021     );
2022    
2023     pdL ALIASES bottoms.pd;
2024     pdV IS_A phases_data('V', pdVL.vapor_option, 'none', 'none');
2025     pdM IS_A phases_data('M', 'none', 'none', 'none');
2026     cd ALIASES feed.cd;
2027     components ALIASES feed.components;
2028    
2029     nfeeds IS_A integer_constant;
2030     nfeeds :== 1;
2031    
2032     coll_stack[cs] ALIASES
2033     (rectifying_section,stripping_section)
2034     WHERE cs IS_A set OF integer_constant
2035     WITH_VALUE (1..2);
2036    
2037     (*feed condition*)
2038     saturated_liquid_feed IS_A start_true;
2039     saturated_vapor_feed IS_A start_false;
2040    
2041     (* inter-section streams *)
2042     rectifier_vapin "vapor rising from feed tray",
2043     stripper_vapin "vapor rising from reboiler"
2044     IS_A stream(cd, pdV, equilibrated);
2045    
2046     condenser_vapin "vapor rising to condenser",
2047     feed_tray_vapin "vapor rising from stripper"
2048     IS_A coll_material_stream(cd, pdM, equilibrated);
2049    
2050     rectifier_liqin "reflux condensate",
2051     stripper_liqin "liquid falling from feed tray"
2052     IS_A stream(cd, pdL, equilibrated);
2053    
2054     feed_tray_liqin "liquid falling from rectifier",
2055     reboiler_liqin "liquid falling to reboiler"
2056     IS_A coll_material_stream(cd, pdM, equilibrated);
2057    
2058     (* typical heat duties *)
2059     Qin_condenser "condenser duty",
2060     Qin_feed "feed heater duty",
2061     Qin_reboiler "reboiler duty" IS_A energy_rate;
2062    
2063     (* column sections *)
2064     condenser IS_A coll_partial_condenser(
2065     Qin_condenser,
2066     condenser_vapin,
2067     rectifier_liqin,
2068     distillate,
2069     equilibrated
2070     );
2071     rectifying_section "the trays above the feed" IS_A std_coll_stack(
2072     ntrays,
2073     condenser_vapin,
2074     rectifier_liqin,
2075     rectifier_vapin,
2076     feed_tray_liqin,
2077     pdL,
2078     pdV,
2079     reduce,
2080     equilibrated,
2081     z_on,
2082     hat_on,
2083     hb_on
2084     );
2085     feed_tray IS_A coll_feed_tray(
2086     Qin_feed,
2087     equilibrated,
2088     feed,
2089     feed_tray_liqin,
2090     feed_tray_vapin,
2091     stripper_liqin,
2092     rectifier_vapin
2093     );
2094     stripping_section "the trays below the feed" IS_A std_coll_stack(
2095     ntrays,
2096     feed_tray_vapin,
2097     stripper_liqin,
2098     stripper_vapin,
2099     reboiler_liqin,
2100     pdL,
2101     pdV,
2102     reduce,
2103     equilibrated,
2104     z_on,
2105     hat_on,
2106     hb_on
2107     );
2108     reboiler IS_A coll_simple_reboiler(
2109     Qin_reboiler,
2110     equilibrated,
2111     reboiler_liqin,
2112     stripper_vapin,
2113     bottoms
2114     );
2115    
2116     stot,
2117     s_stack[1..nfeeds+1] IS_A factor;
2118     split[1..nfeeds+1] IS_A fraction;
2119     xsi[components] IS_A fraction;
2120     xsi_set[components] IS_A fraction;
2121     xsi_diff[components] IS_A fraction;
2122     scale IS_A scaling_constant;
2123    
2124     s_stack[1],
2125     rectifying_section.stot ARE_THE_SAME;
2126     s_stack[2],
2127     stripping_section.stot ARE_THE_SAME;
2128     stot = SUM[s_stack[1..nfeeds+1]];
2129    
2130     FOR j IN [1..nfeeds+1] CREATE
2131    
2132     tray_split[j]: s_stack[j] = split[j]*stot;
2133     END FOR;
2134    
2135     FOR i IN components CREATE
2136     OverallMB[i]: feed_tray.feed.f[i] =
2137     condenser.distillate.f[i] +
2138     reboiler.bottoms.f[i];
2139     END FOR;
2140    
2141     FOR i IN components CREATE
2142     xsi[i]*feed_tray.feed.f[i]
2143     = condenser.distillate.f[i];
2144     xsi_diff[i] = 0.5*sqr(xsi[i] - xsi_set[i]);
2145     END FOR;
2146    
2147     recovery: MINIMIZE SUM[xsi_diff[i] | i IN components];
2148    
2149     binary_sep[components][components] IS_A factor;
2150    
2151     FOR i IN components CREATE
2152     FOR j IN components CREATE
2153     binary_sep[i][j] *
2154     (condenser.distillate.f[i] + condenser.distillate.f[j]) *
2155     (reboiler.bottoms.f[i] + reboiler.bottoms.f[j]) =
2156     (condenser.distillate.f[i] *
2157     (reboiler.bottoms.f[i] + reboiler.bottoms.f[j]) -
2158     reboiler.bottoms.f[i] *
2159     (condenser.distillate.f[i] + condenser.distillate.f[j]));
2160    
2161     sep_opt[i][j]: MINIMIZE -sqr(binary_sep[i][j]);
2162    
2163     END FOR;
2164     END FOR;
2165    
2166     (* costing *)
2167     V[ns] ALIASES
2168     (coll_stack[1..nfeeds+1].coll[1].tray[1].vapout.flow)
2169     WHERE ns IS_A set OF integer_constant
2170     WITH_VALUE (1..nfeeds+1);
2171    
2172     V_bar[ns2] ALIASES
2173     (coll_stack[1..nfeeds+1].coll[1].tray[1].vapout.state.V)
2174     WHERE ns2 IS_A set OF integer_constant
2175     WITH_VALUE (1..nfeeds+1);
2176    
2177     M_g IS_A molar_mass;
2178    
2179     mol_mass: M_g = SUM[feed.Details.state.cd.data[i].mw*
2180     feed_tray.vapout.state.y[i]
2181     | i IN components];
2182    
2183     nsections IS_A integer_constant;
2184     nsections :== nfeeds+1;
2185    
2186     column_cost IS_A cost_per_time;
2187     cost_calc IS_A cost_calc(
2188     column_cost,
2189     distillate.state.T,
2190     condenser.Qin,
2191     reboiler.Qin,
2192     nsections,
2193     V,
2194     V_bar,
2195     stot,
2196     M_g,
2197     feed.flow
2198     );
2199    
2200     objmult IS_A factor;
2201     opcost, capcost IS_A cost_per_time;
2202     optime IS_A fraction;
2203     op_cost_def: opcost = cost_calc.water_cost + cost_calc.steam_cost;
2204     cap_cost_def: capcost = cost_calc.column_cost +
2205     cost_calc.condenser_cost +
2206     cost_calc.reboiler_cost;
2207     tot_cost: MINIMIZE objmult*(capcost + optime*opcost);
2208     cap_cost: MINIMIZE objmult*capcost;
2209     op_cost: MINIMIZE objmult*opcost;
2210    
2211     (*
2212     * Cost calculation doesn't mean much for constant alpha case.
2213     * We do provide overide though. :)
2214     *)
2215    
2216     WHEN (equilibrated)
2217     CASE TRUE:
2218     USE cost_calc;
2219     USE mol_mass;
2220     USE tot_cost;
2221     USE cap_cost;
2222     USE op_cost;
2223     USE cap_cost_def;
2224     USE op_cost_def;
2225     OTHERWISE:
2226     END WHEN;
2227    
2228     do_cost_calc IS_A boolean;
2229     WHEN (do_cost_calc)
2230     CASE TRUE:
2231     USE cost_calc;
2232     USE mol_mass;
2233     USE tot_cost;
2234     USE cap_cost;
2235     USE op_cost;
2236     USE cap_cost_def;
2237     USE op_cost_def;
2238     OTHERWISE:
2239     END WHEN;
2240    
2241    
2242     (* Plotting Section *)
2243     z_shift IS_A factor;
2244     s_shift IS_A factor;
2245    
2246     n_plt_points_x IS_A set OF integer_constant;
2247     n_plt_points_x :== [0..(nfeeds+1)*(coll_stack[1].ncolls*ntrays+3)];
2248     n_plt_points_y IS_A set OF integer_constant;
2249     n_plt_points_y :== [0..(nfeeds+1)*(coll_stack[1].ncolls*ntrays+3)-1];
2250    
2251     z_loc_1: coll_stack[1].z_shift = z_shift;
2252     s_loc_1: coll_stack[1].s_shift = s_shift;
2253    
2254     z_space IS_A factor;
2255    
2256     FOR i IN [2..nfeeds+1] CREATE
2257     z_loc[i]: coll_stack[i].z_shift =
2258     coll_stack[i-1].z_tray_loc[CARD[coll_stack[i-1].n_plt_points]-1]
2259     + z_space; (* add arbitrary factor *)
2260     s_loc[i]: coll_stack[i].s_shift =
2261     coll_stack[i-1].s_tray_loc[coll_stack[1].ncolls*(ntrays+1)]
2262     + 1; (* FOR feed tray *)
2263     END FOR;
2264    
2265    
2266     reboiler_s_loc, reboiler_z_loc IS_A factor;
2267    
2268     z_tray_loc_x[tp] ALIASES (
2269     coll_stack[1..nfeeds+1].z_tray_loc[0..coll_stack[1].ncolls*(ntrays+1)]
2270     , reboiler_z_loc
2271     ) WHERE
2272     tp IS_A set OF integer_constant
2273     WITH_VALUE (0..(nfeeds+1)*(coll_stack[1].ncolls*ntrays+3));
2274    
2275     s_tray_loc_x[tp2] ALIASES (
2276     coll_stack[1..nfeeds+1].s_tray_loc[0..coll_stack[1].ncolls*(ntrays+1)]
2277     , reboiler_s_loc
2278     ) WHERE
2279     tp2 IS_A set OF integer_constant
2280     WITH_VALUE (0..(nfeeds+1)*(coll_stack[1].ncolls*ntrays+3));
2281    
2282     reb_s_loc: reboiler_s_loc = 1 +
2283     s_tray_loc_x[(nfeeds+1)*(coll_stack[1].ncolls*ntrays+3)-1];
2284     reb_z_loc: reboiler_z_loc =
2285     coll_stack[nfeeds+1].
2286     z_tray_loc[CARD[coll_stack[nfeeds+1].n_plt_points]-1] +
2287     z_space;
2288    
2289     z_tray_loc_y[tp3] ALIASES (
2290     coll_stack[1..nfeeds+1].z_tray_loc[0..coll_stack[1].ncolls*(ntrays+1)]
2291     ) WHERE
2292     tp3 IS_A set OF integer_constant
2293     WITH_VALUE (0..(nfeeds+1)*(coll_stack[1].ncolls*ntrays+3)-1);
2294    
2295     s_tray_loc_y[tp4] ALIASES (
2296     coll_stack[1..nfeeds+1].s_tray_loc[0..coll_stack[1].ncolls*(ntrays+1)]