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

Contents of /trunk/models/collocation.a4l

Parent Directory Parent Directory | Revision Log Revision Log


Revision 835 - (show annotations) (download) (as text)
Wed Sep 6 15:52:46 2006 UTC (17 years, 10 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 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 FIX reflux_ratio;
210 FREE liqout.T;
211 FREE liqout.P;
212 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 FIX w_points[0..npoints];
374 FIX f_int;
375 FIX f_mid;
376 FIX mult[1..ntrays];
377 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 FIX a;
440 FIX s;
441 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 FIX s;
452 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 FREE lgr.w_points[0..lgr.npoints];
615 FIX a;
616 FIX s_values[0];
617 FIX stot;
618 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 FIX state.H;
659 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 FIX state.H;
692 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 FIX cmo[1..ntrays];
1323 FIX cmotot;
1324
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 FIX topvap.state.H;
1336 FIX botliq.state.H;
1337
1338 FIX liqin_state[1..ntrays].H;
1339 FIX tray[1..ntrays].Qin;
1340 FREE s_shift;
1341 FREE z_shift;
1342 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 FIX cmo[1..ntrays];
1350 FIX cmotot;
1351 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 FREE topliq.state.T;
1362 FREE botvap.state.T;
1363 FREE topvap.state.T;
1364 FREE botliq.state.T;
1365
1366
1367 FREE topliq.state.H;
1368 FREE botvap.state.H;
1369 FREE topvap.state.H;
1370 FREE botliq.state.H;
1371
1372 FREE s_shift;
1373 FREE z_shift;
1374 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 FREE s_shift;
1383 FREE z_shift;
1384 END seqmod_adiabatic;
1385
1386 METHOD heat_balance;
1387 hb_on := TRUE;
1388 RUN tray[1..ntrays].heat_balance;
1389 FIX Qtot;
1390 FREE cmotot;
1391 FIX Qin[1..ntrays];
1392 FREE cmo[1..ntrays];
1393 END heat_balance;
1394 METHOD CMO;
1395 hb_on := FALSE;
1396 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 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 FIX s_shift;
1420 FIX z_shift;
1421 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 (*FREE coll[j].botliq.state.H;*)
1876
1877 FREE coll[j].z_set.z_values[coll[j].ntrays+1];
1878 FREE coll[j].z_set.stot;
1879 END FOR;
1880 FIX stot;
1881 FIX split[1..ncolls-1];
1882 IF (hb_on) THEN
1883 RUN heat_balance;
1884 END IF;
1885 FREE z_shift;
1886 FREE s_shift;
1887 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 (*FREE coll[j].botliq.state.H;*)
1895
1896 FREE coll[j].z_set.z_values[coll[j].ntrays+1];
1897 FREE coll[j].z_set.stot;
1898 END FOR;
1899 FIX stot;
1900 FIX split[1..ncolls-1];
1901 IF (hb_on) THEN
1902 RUN heat_balance;
1903 END IF;
1904
1905 FREE z_shift;
1906 FREE s_shift;
1907 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 (*FREE coll[j].botliq.state.H;*)
1915
1916 FREE coll[j].z_set.z_values[coll[j].ntrays+1];
1917 FREE coll[j].z_set.stot;
1918 END FOR;
1919 FIX stot;
1920 FIX split[1..ncolls-1];
1921 IF (hb_on) THEN
1922 RUN heat_balance;
1923 END IF;
1924
1925 FREE z_shift;
1926 FREE s_shift;
1927 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 FIX z_shift;
1946 FIX s_shift;
1947 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)]
2297 ) WHERE
2298 tp4 IS_A set OF integer_constant
2299 WITH_VALUE (0..(nfeeds+1)*(coll_stack[1].ncolls*ntrays+3)-1);
2300
2301
2302 FOR i IN coll_stack[1].topliq.components CREATE
2303 x_plot[i][np[i]] ALIASES (
2304 coll_stack[1..nfeeds+1].
2305 x_plot[i][0..coll_stack[1].ncolls*(ntrays+1)],
2306 reboiler.bottoms.state.y[i]
2307 ) WHERE
2308 np[i] IS_A set OF integer_constant
2309 WITH_VALUE (0..(nfeeds+1)*(coll_stack[1].ncolls*ntrays+3));
2310 y_plot[i][np2[i]] ALIASES (
2311 coll_stack[1..nfeeds+1].
2312 y_plot[i][0..coll_stack[1].ncolls*(ntrays+1)]
2313 ) WHERE
2314 np2[i] IS_A set OF integer_constant
2315 WITH_VALUE (0..(nfeeds+1)*(coll_stack[1].ncolls*ntrays+3)-1);
2316 END FOR;
2317
2318 FOR i IN coll_stack[1].topliq.components CREATE
2319 x_z_curves[i] IS_A plt_curve(n_plt_points_x,x_plot[i],z_tray_loc_x);
2320 x_s_curves[i] IS_A plt_curve(n_plt_points_x,x_plot[i],s_tray_loc_x);
2321 y_z_curves[i] IS_A plt_curve(n_plt_points_y,y_plot[i],z_tray_loc_y);
2322 y_s_curves[i] IS_A plt_curve(n_plt_points_y,y_plot[i],s_tray_loc_y);
2323 END FOR;
2324
2325 Plot_xz IS_A plt_plot_symbol(coll_stack[1].topliq.components,x_z_curves);
2326 Plot_xs IS_A plt_plot_symbol(coll_stack[1].topliq.components,x_s_curves);
2327
2328 Plot_yz IS_A plt_plot_symbol(coll_stack[1].topliq.components,y_z_curves);
2329 Plot_ys IS_A plt_plot_symbol(coll_stack[1].topliq.components,y_s_curves);
2330
2331 ncomps IS_A integer_constant;
2332 ncomps :== CARD[components];
2333
2334 SELECT (ncomps)
2335 CASE 3:
2336 T_Liq_diagram_e IS_A
2337 ternary_plot_equilateral('liquid composition profiles',
2338 components,
2339 CHOICE[components],
2340 CHOICE[components - [CHOICE[components]]],
2341 n_plt_points_x,x_plot);
2342 T_Vap_diagram_e IS_A
2343 ternary_plot_equilateral('vapor composition profiles',
2344 components,
2345 CHOICE[components],
2346 CHOICE[components - [CHOICE[components]]],
2347 n_plt_points_y,y_plot);
2348 END SELECT;
2349
2350 METHODS
2351
2352 METHOD default_self;
2353
2354 RUN condenser_vapin.default_self;
2355 RUN rectifier_liqin.default_self;
2356 RUN rectifier_vapin.default_self;
2357 RUN feed_tray_liqin.default_self;
2358 RUN feed_tray_vapin.default_self;
2359 RUN stripper_liqin.default_self;
2360 RUN stripper_vapin.default_self;
2361 RUN reboiler_liqin.default_self;
2362
2363 RUN condenser.default_self;
2364 RUN coll_stack[1..nfeeds+1].default_self;
2365 RUN feed_tray.default_self;
2366 RUN reboiler.default_self;
2367
2368 RUN cost_calc.default_self;
2369
2370 hb_on := FALSE;
2371 equilibrated := FALSE;
2372 do_cost_calc := FALSE;
2373 FIX objmult;
2374 objmult := 10000;
2375 FIX optime;
2376 optime := 1.0;
2377 split[1..nfeeds+1] := 1.0/(nfeeds+1);
2378
2379 FIX z_shift;
2380 FIX s_shift;
2381 z_shift := 0;
2382 s_shift := 0;
2383 z_space := 0.1;
2384
2385 distillate.state.phase_fraction['vapor'] := 0;
2386
2387 Plot_xz.title := 'Liquid Compositions vs. z';
2388 Plot_xz.YLabel := 'Liquid Compositions';
2389 Plot_xz.XLabel := 'transformed stage location (z)';
2390 Plot_xz.Ylow := 0;
2391 Plot_xz.Yhigh := 1;
2392
2393 Plot_xs.title := 'Liquid Compositions vs. s';
2394 Plot_xs.YLabel := 'Liquid Compositions';
2395 Plot_xs.XLabel := 'stage location (s)';
2396 Plot_xs.Ylow := 0;
2397 Plot_xs.Yhigh := 1;
2398
2399 Plot_yz.title := 'Vapor Compositions vs. z';
2400 Plot_yz.YLabel := 'Vapor Compositions';
2401 Plot_yz.XLabel := 'transformed stage location (z)';
2402 Plot_yz.Ylow := 0;
2403 Plot_yz.Yhigh := 1;
2404
2405 Plot_ys.title := 'Vapor Compositions vs. s';
2406 Plot_ys.YLabel := 'Vapor Compositions';
2407 Plot_ys.XLabel := 'stage location (s)';
2408 Plot_ys.Ylow := 0;
2409 Plot_ys.Yhigh := 1;
2410
2411 FOR i IN components DO
2412 Plot_xz.curve[i].legend := i;
2413 Plot_xs.curve[i].legend := i;
2414 Plot_yz.curve[i].legend := i;
2415 Plot_ys.curve[i].legend := i;
2416 END FOR;
2417
2418 IF (ncomps == 3) THEN
2419 RUN T_Liq_diagram_e.default_self;
2420 RUN T_Vap_diagram_e.default_self;
2421 END IF;
2422
2423 END default_self;
2424 METHOD default_all;
2425 RUN distillate.default_all;
2426 RUN feed.default_all;
2427 RUN bottoms.default_all;
2428 RUN default_self;
2429 END default_all;
2430
2431 METHOD scale_self;
2432 stot.nominal := stot;
2433 coll_stack[1..nfeeds+1].stot.upper_bound :=
2434 stot.upper_bound/(nfeeds+1) + 1.0;
2435 RUN condenser.scale_self;
2436 RUN coll_stack[1..nfeeds+1].scale_self;
2437 RUN feed_tray.scale_self;
2438 RUN reboiler.scale_self;
2439 FOR i IN components DO
2440 xsi[i].nominal := xsi[i];
2441 xsi_set[i].nominal := xsi_set[i];
2442 xsi_diff[i].nominal := xsi_diff[i];
2443 END FOR;
2444 END scale_self;
2445 METHOD scale_all;
2446 RUN scale_self;
2447 RUN distillate.scale_all;
2448 RUN feed.scale_all;
2449 RUN bottoms.scale_all;
2450 END scale_all;
2451 METHOD bound_self;
2452 stot.lower_bound := 4;
2453 stot.upper_bound := 100;
2454 RUN condenser.bound_self;
2455 RUN coll_stack[1..nfeeds+1].bound_self;
2456 RUN feed_tray.bound_self;
2457 RUN reboiler.bound_self;
2458 END bound_self;
2459 METHOD bound_all;
2460 RUN bound_self;
2461 RUN distillate.bound_all;
2462 RUN feed.bound_all;
2463 RUN bottoms.bound_all;
2464 END bound_all;
2465 METHOD check_self;
2466 END check_self;
2467 METHOD check_all;
2468 RUN check_self;
2469 RUN distillate.check_all;
2470 RUN feed.check_all;
2471 RUN bottoms.check_all;
2472 END check_all;
2473
2474 METHOD values;
2475 RUN coll_stack[1..nfeeds+1].values;
2476 END values;
2477
2478 METHOD heat_balance;
2479 RUN coll_stack[1..nfeeds+1].heat_balance;
2480 FREE feed_tray.q;
2481 FIX feed_tray.Qin;
2482 hb_on := TRUE;
2483 END heat_balance;
2484 METHOD CMO;
2485 RUN coll_stack[1..nfeeds+1].CMO;
2486 FIX feed_tray[1..nfeeds].q;
2487 FREE feed_tray[1..nfeeds].Qin;
2488 hb_on := FALSE;
2489 END CMO;
2490 METHOD reduce_Q;
2491 FOR i IN [1..nfeeds+1] DO
2492 FOR j IN [1..coll_stack[i].ncolls] DO
2493 coll_stack[i].coll[j].Qtot :=
2494 coll_stack[i].coll[j].Qtot*reduce;
2495 FOR k IN [1..coll_stack[i].coll[j].ntrays] DO
2496 coll_stack[i].coll[j].Qin[k] :=
2497 coll_stack[i].coll[j].Qin[k]*reduce;
2498 coll_stack[i].coll[j].tray[k].Qin :=
2499 coll_stack[i].coll[j].tray[k].Qin*reduce;
2500 END FOR;
2501 END FOR;
2502 END FOR;
2503 feed_tray.Qin :=
2504 feed_tray.Qin*reduce;
2505 END reduce_Q;
2506 METHOD zero_Q;
2507 reduce := 0;
2508 RUN reduce_Q;
2509 END zero_Q;
2510
2511 METHOD specify_feed;
2512 RUN feed.ClearAll;
2513 IF (feed.pd.phase_indicator == 'VL') THEN
2514 feed.equilibrated := equilibrated;
2515 RUN feed.specify;
2516 IF (equilibrated == TRUE) THEN
2517 IF (saturated_liquid_feed == TRUE) THEN
2518 saturated_vapor_feed := FALSE;
2519 FREE feed.T;
2520 FIX feed.state.phase_fraction['vapor'];
2521 feed.state.phase_fraction['vapor'] := 0.0;
2522 END IF;
2523 IF (saturated_vapor_feed == TRUE) THEN
2524 FREE feed.T;
2525 FIX feed.state.phase_fraction['vapor'];
2526 feed.state.phase_fraction['vapor'] := 1.0;
2527 END IF;
2528 END IF;
2529 ELSE
2530 RUN feed.specify;
2531 END IF;
2532 END specify_feed;
2533 METHOD seqmod;
2534 RUN condenser.seqmod;
2535 RUN coll_stack[1..nfeeds+1].seqmod;
2536 RUN feed_tray.seqmod;
2537 RUN reboiler.seqmod;
2538 OverallMB[components].included := FALSE;
2539 FREE reboiler.reboil_ratio;
2540 FIX condenser.distillate.flow;
2541 FIX xsi_set[components];
2542 IF (hb_on) THEN
2543 RUN heat_balance;
2544 END IF;
2545 recovery.included := FALSE;
2546 sep_opt[components][components].included := FALSE;
2547 FIX z_space;
2548 FIX s_shift;
2549 FIX z_shift;
2550 END seqmod;
2551
2552 METHOD seqmod_massbal;
2553 FIX objmult;
2554 FIX optime;
2555 hb_on := FALSE;
2556 equilibrated := FALSE;
2557
2558 RUN cost_calc.seqmod;
2559 RUN condenser.seqmod;
2560 RUN coll_stack[1..nfeeds+1].seqmod_massbal;
2561 RUN feed_tray.seqmod_massbal;
2562 RUN reboiler.seqmod;
2563 OverallMB[components].included := FALSE;
2564 FREE reboiler.reboil_ratio;
2565 FIX condenser.distillate.flow;
2566 FIX xsi_set[components];
2567 recovery.included := FALSE;
2568 sep_opt[components][components].included := FALSE;
2569
2570 FIX z_space;
2571 FIX s_shift;
2572 FIX z_shift;
2573
2574 END seqmod_massbal;
2575
2576 METHOD seqmod_fullthermo;
2577 FIX objmult;
2578 FIX optime;
2579 hb_on := FALSE;
2580 equilibrated := TRUE;
2581
2582 RUN cost_calc.seqmod;
2583 RUN condenser.seqmod;
2584 RUN coll_stack[1..nfeeds+1].seqmod_fullthermo;
2585 RUN feed_tray.seqmod_fullthermo;
2586 RUN reboiler.seqmod;
2587 OverallMB[components].included := FALSE;
2588 FREE reboiler.reboil_ratio;
2589 FIX condenser.distillate.flow;
2590 FIX xsi_set[components];
2591 recovery.included := FALSE;
2592 sep_opt[components][components].included := FALSE;
2593
2594 FIX z_space;
2595 FIX s_shift;
2596 FIX z_shift;
2597
2598 END seqmod_fullthermo;
2599
2600 METHOD seqmod_adiabatic;
2601 FIX objmult;
2602 FIX optime;
2603 hb_on := TRUE;
2604 equilibrated := TRUE;
2605 RUN seqmod_fullthermo;
2606 RUN heat_balance;
2607
2608 FIX z_space;
2609 FIX s_shift;
2610 FIX z_shift;
2611
2612 END seqmod_adiabatic;
2613
2614 METHOD specify;
2615 IF (hb_on AND NOT(equilibrated)) THEN
2616 equilibrated := TRUE;
2617 END IF;
2618 IF (hb_on AND equilibrated) THEN
2619 RUN seqmod_adiabatic;
2620 END IF;
2621 IF (NOT(hb_on) AND equilibrated) THEN
2622 RUN seqmod_fullthermo;
2623 END IF;
2624 IF (NOT(hb_on) AND NOT(equilibrated)) THEN
2625 RUN seqmod_massbal;
2626 END IF;
2627 RUN specify_feed;
2628
2629 FREE condenser.liqout.T;
2630 FREE condenser.liqout.P;
2631 END specify;
2632 METHOD reset;
2633 RUN ClearAll;
2634 RUN specify;
2635 END reset;
2636 METHOD standard_poly;
2637 hat_on := FALSE;
2638 END standard_poly;
2639 METHOD trans_poly;
2640 hat_on := TRUE;
2641 END trans_poly;
2642 METHOD z_based_poly;
2643 z_on := TRUE;
2644 END z_based_poly;
2645 METHOD s_based_poly;
2646 z_on := FALSE;
2647 END s_based_poly;
2648 METHOD propagate_feed_values;
2649 FOR i IN components DO
2650 FOR k IN [1..nfeeds+1] DO
2651 FOR j IN [1..coll_stack[k].ncolls] DO
2652 coll_stack[k].coll[j].tray[1..coll_stack[k]
2653 .coll[j].ntrays].alpha[i]
2654 := feed_tray.alpha[i];
2655 END FOR;
2656 END FOR;
2657 reboiler.alpha[i] :=
2658 feed_tray.alpha[i];
2659 END FOR;
2660 END propagate_feed_values;
2661 METHOD initialize_feed_tray_state;
2662 FOR i IN components DO
2663 feed_tray.state.y[i] :=
2664 feed.f[i]/SUM[feed.f[j] | j IN components];
2665 END FOR;
2666 feed_tray.state.T := feed.T;
2667 feed_tray.state.P := feed.P;
2668 END initialize_feed_tray_state;
2669
2670 METHOD overallMB;
2671 OverallMB[components].included := TRUE;
2672 feed_tray[1].totfeedflow[components].included := FALSE;
2673 END overallMB;
2674
2675 METHOD reset_to_massbal;
2676 hb_on := FALSE;
2677 equilibrated := FALSE;
2678 RUN reset;
2679 END reset_to_massbal;
2680
2681 METHOD reset_to_fullthermo;
2682 hb_on := FALSE;
2683 equilibrated := TRUE;
2684 RUN reset;
2685 FREE distillate.T;
2686 FIX distillate.state.phase_fraction['vapor'];
2687 distillate.state.phase_fraction['vapor'] := 0;
2688 END reset_to_fullthermo;
2689
2690 METHOD reset_to_adiabatic;
2691 hb_on := TRUE;
2692 equilibrated := TRUE;
2693 RUN reset;
2694 FREE distillate.T;
2695 FIX distillate.state.phase_fraction['vapor'];
2696 distillate.state.phase_fraction['vapor'] := 0;
2697 END reset_to_adiabatic;
2698
2699 METHOD equipment_bounds;
2700 RUN cost_calc.equipment_bounds;
2701 END equipment_bounds;
2702
2703 METHOD optimization_DOF;
2704 FREE distillate.flow;
2705 FREE condenser.reflux_ratio;
2706 FREE s_stack[1..2];
2707 END optimization_DOF;
2708 END simple_coll_column;
2709
2710
2711 MODEL test_coll_column();
2712 cd IS_A components_data(
2713 ['acetone','benzene','chloroform'],'chloroform'
2714 );
2715 pdVL IS_A phases_data('VL','Pitzer_vapor_mixture',
2716 'Wilson_liquid_mixture','none');
2717 pdV IS_A phases_data('V','Pitzer_vapor_mixture','none','none');
2718 pdL IS_A phases_data('L','none','Wilson_liquid_mixture','none');
2719
2720
2721 Feed_equil, Equilibrated IS_A start_false;
2722 Feed IS_A stream(cd, pdVL, Feed_equil);
2723 Distillate IS_A stream(cd, pdVL, Equilibrated);
2724 Bottoms IS_A stream(cd, pdL, Equilibrated);
2725
2726 ntrays IS_A integer_constant;
2727 ntrays :== 2;
2728
2729 reduce IS_A fraction;
2730
2731 z_on, hat_on, hb_on IS_A start_false;
2732
2733 Column IS_A simple_coll_column(
2734 ntrays,
2735 pdVL,
2736 Distillate,
2737 Feed,
2738 Bottoms,
2739 Equilibrated,
2740 reduce,
2741 z_on,
2742 hat_on,
2743 hb_on
2744 );
2745 boundwidth IS_A bound_width;
2746
2747 METHODS
2748
2749 METHOD default_self;
2750 RUN Feed.default_self;
2751 RUN Distillate.default_self;
2752 RUN Bottoms.default_self;
2753 RUN Column.default_self;
2754 boundwidth := 100;
2755 END default_self;
2756
2757 METHOD check_self;
2758 RUN Feed.check_self;
2759 RUN Distillate.check_self;
2760 RUN Bottoms.check_self;
2761 RUN Column.check_self;
2762 END check_self;
2763
2764 METHOD scale_self;
2765 RUN Feed.scale_self;
2766 RUN Distillate.scale_self;
2767 RUN Bottoms.scale_self;
2768 RUN Column.scale_self;
2769 END scale_self;
2770
2771 METHOD bound_self;
2772 Column.boundwidth := boundwidth;
2773 Profile.boundwidth := boundwidth;
2774 Feed.boundwidth := boundwidth;
2775 Distillate.boundwidth := boundwidth;
2776 Bottoms.boundwidth := boundwidth;
2777 RUN Feed.bound_self;
2778 RUN Distillate.bound_self;
2779 RUN Bottoms.bound_self;
2780 RUN Column.bound_self;
2781 END bound_self;
2782
2783 METHOD bound_all;
2784 RUN bound_self;
2785 END bound_all;
2786
2787 METHOD scale_all;
2788 RUN scale_self;
2789 END scale_all;
2790
2791 METHOD check_all;
2792 RUN check_self;
2793 END check_all;
2794
2795 METHOD default_all;
2796 RUN default_self;
2797 END default_all;
2798
2799 METHOD values;
2800 Column.condenser.reflux_ratio := 2.0;
2801 Column.s_stack[1] := 10;
2802 Column.s_stack[2] := 10;
2803 Feed.T := 298 {K};
2804 Feed.P := 1{atm};
2805 Feed.f['acetone'] := 3.6 {mole/s};
2806 Feed.f['benzene'] := 4 {mole/s};
2807 Feed.f['chloroform'] := 2.4 {mole/s};
2808 Distillate.flow := 6.0 {mole/s};
2809
2810 RUN Column.initialize_feed_tray_state;
2811 END values;
2812
2813 END test_coll_column;

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22