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

Annotation of /trunk/models/collocation.a4l

Parent Directory Parent Directory | Revision Log Revision Log


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