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

Contents of /trunk/models/collocation.a4l

Parent Directory Parent Directory | Revision Log Revision Log


Revision 576 - (show annotations) (download) (as text)
Tue May 9 03:42:08 2006 UTC (18 years, 1 month ago) by johnpye
File MIME type: text/x-ascend
File size: 71595 byte(s)
Changed all cases of *.fixed := {TRUE,FALSE} to 'FIX' and 'FREE' statements.
1 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 coll[j].z_set
1878 .FREE z_values[coll[j].ntrays+1];
1879 FREE coll[j].z_set.stot;
1880 END FOR;
1881 FIX stot;
1882 FIX split[1..ncolls-1];
1883 IF (hb_on) THEN
1884 RUN heat_balance;
1885 END IF;
1886 FREE z_shift;
1887 FREE s_shift;
1888 END seqmod_massbal;
1889
1890 METHOD seqmod_fullthermo;
1891 hb_on := FALSE;
1892 equilibrated := TRUE;
1893 RUN coll[1..ncolls].seqmod_fullthermo;
1894 FOR j IN [1..ncolls] DO
1895 (*FREE coll[j].botliq.state.H;*)
1896
1897 coll[j].z_set
1898 .FREE z_values[coll[j].ntrays+1];
1899 FREE coll[j].z_set.stot;
1900 END FOR;
1901 FIX stot;
1902 FIX split[1..ncolls-1];
1903 IF (hb_on) THEN
1904 RUN heat_balance;
1905 END IF;
1906
1907 FREE z_shift;
1908 FREE s_shift;
1909 END seqmod_fullthermo;
1910
1911 METHOD seqmod_adiabatic;
1912 hb_on := TRUE;
1913 equilibrated := TRUE;
1914 RUN coll[1..ncolls].seqmod_adiabatic;
1915 FOR j IN [1..ncolls] DO
1916 (*FREE coll[j].botliq.state.H;*)
1917
1918 coll[j].z_set
1919 .FREE z_values[coll[j].ntrays+1];
1920 FREE coll[j].z_set.stot;
1921 END FOR;
1922 FIX stot;
1923 FIX split[1..ncolls-1];
1924 IF (hb_on) THEN
1925 RUN heat_balance;
1926 END IF;
1927
1928 FREE z_shift;
1929 FREE s_shift;
1930 END seqmod_adiabatic;
1931
1932
1933 METHOD specify;
1934 IF (hb_on AND NOT(equilibrated)) THEN
1935 equilibrated := TRUE;
1936 END IF;
1937 IF (hb_on AND equilibrated) THEN
1938 RUN seqmod_adiabatic;
1939 END IF;
1940 IF (NOT(hb_on) AND equilibrated) THEN
1941 RUN seqmod_fullthermo;
1942 END IF;
1943 IF (NOT(hb_on) AND NOT(equilibrated)) THEN
1944 RUN seqmod_massbal;
1945 END IF;
1946 RUN coll[1].topliq.specify;
1947 RUN coll[ncolls].botvap.specify;
1948 FIX z_shift;
1949 FIX s_shift;
1950 END specify;
1951 METHOD reset;
1952 RUN ClearAll;
1953 RUN specify;
1954 END reset;
1955 METHOD standard_poly;
1956 RUN coll[1..ncolls].standard_poly;
1957 END standard_poly;
1958 METHOD trans_poly;
1959 RUN coll[1..ncolls].trans_poly;
1960 END trans_poly;
1961 METHOD z_based_poly;
1962 RUN coll[1..ncolls].z_based_poly;
1963 END z_based_poly;
1964 METHOD s_based_poly;
1965 RUN coll[1..ncolls].s_based_poly;
1966 END s_based_poly;
1967
1968 METHOD heat_balance;
1969 RUN coll[1..ncolls].heat_balance;
1970 END heat_balance;
1971
1972 METHOD reset_to_massbal;
1973 hb_on := FALSE;
1974 equilibrated := FALSE;
1975 RUN reset;
1976 END reset_to_massbal;
1977
1978 METHOD reset_to_fullthermo;
1979 hb_on := FALSE;
1980 equilibrated := TRUE;
1981 RUN reset;
1982 END reset_to_fullthermo;
1983
1984 METHOD reset_to_adiabatic;
1985 hb_on := TRUE;
1986 equilibrated := TRUE;
1987 RUN reset;
1988 END reset_to_adiabatic;
1989
1990 METHOD reduce_Q;
1991 RUN coll[1..ncolls].reduce_Q;
1992 END reduce_Q;
1993
1994 METHOD zero_Q;
1995 reduce := 0;
1996 RUN reduce_Q;
1997 END zero_Q;
1998
1999 METHOD CMO;
2000 RUN coll[1..ncolls].CMO;
2001 END CMO;
2002
2003
2004 END std_coll_stack;
2005
2006 MODEL simple_coll_column(
2007 ntrays WILL_BE integer_constant;
2008 pdVL WILL_BE phases_data;
2009 distillate WILL_BE stream;
2010 feed WILL_BE stream;
2011 bottoms WILL_BE stream;
2012 equilibrated WILL_BE boolean;
2013 reduce WILL_BE fraction;
2014 z_on WILL_BE boolean;
2015 hat_on WILL_BE boolean;
2016 hb_on WILL_BE boolean;
2017 ) WHERE (
2018 distillate, bottoms, feed WILL_NOT_BE_THE_SAME;
2019 feed.cd, distillate.cd, bottoms.cd WILL_BE_THE_SAME;
2020 pdVL.phase_indicator == 'VL';
2021 distillate.pd.phase_indicator IN ['L','VL'] == TRUE;
2022 pdVL.liquid1_option == distillate.pd.liquid1_option;
2023 feed.pd.phase_indicator IN ['V','L','VL'] == TRUE;
2024 );
2025
2026 pdL ALIASES bottoms.pd;
2027 pdV IS_A phases_data('V', pdVL.vapor_option, 'none', 'none');
2028 pdM IS_A phases_data('M', 'none', 'none', 'none');
2029 cd ALIASES feed.cd;
2030 components ALIASES feed.components;
2031
2032 nfeeds IS_A integer_constant;
2033 nfeeds :== 1;
2034
2035 coll_stack[cs] ALIASES
2036 (rectifying_section,stripping_section)
2037 WHERE cs IS_A set OF integer_constant
2038 WITH_VALUE (1..2);
2039
2040 (*feed condition*)
2041 saturated_liquid_feed IS_A start_true;
2042 saturated_vapor_feed IS_A start_false;
2043
2044 (* inter-section streams *)
2045 rectifier_vapin "vapor rising from feed tray",
2046 stripper_vapin "vapor rising from reboiler"
2047 IS_A stream(cd, pdV, equilibrated);
2048
2049 condenser_vapin "vapor rising to condenser",
2050 feed_tray_vapin "vapor rising from stripper"
2051 IS_A coll_material_stream(cd, pdM, equilibrated);
2052
2053 rectifier_liqin "reflux condensate",
2054 stripper_liqin "liquid falling from feed tray"
2055 IS_A stream(cd, pdL, equilibrated);
2056
2057 feed_tray_liqin "liquid falling from rectifier",
2058 reboiler_liqin "liquid falling to reboiler"
2059 IS_A coll_material_stream(cd, pdM, equilibrated);
2060
2061 (* typical heat duties *)
2062 Qin_condenser "condenser duty",
2063 Qin_feed "feed heater duty",
2064 Qin_reboiler "reboiler duty" IS_A energy_rate;
2065
2066 (* column sections *)
2067 condenser IS_A coll_partial_condenser(
2068 Qin_condenser,
2069 condenser_vapin,
2070 rectifier_liqin,
2071 distillate,
2072 equilibrated
2073 );
2074 rectifying_section "the trays above the feed" IS_A std_coll_stack(
2075 ntrays,
2076 condenser_vapin,
2077 rectifier_liqin,
2078 rectifier_vapin,
2079 feed_tray_liqin,
2080 pdL,
2081 pdV,
2082 reduce,
2083 equilibrated,
2084 z_on,
2085 hat_on,
2086 hb_on
2087 );
2088 feed_tray IS_A coll_feed_tray(
2089 Qin_feed,
2090 equilibrated,
2091 feed,
2092 feed_tray_liqin,
2093 feed_tray_vapin,
2094 stripper_liqin,
2095 rectifier_vapin
2096 );
2097 stripping_section "the trays below the feed" IS_A std_coll_stack(
2098 ntrays,
2099 feed_tray_vapin,
2100 stripper_liqin,
2101 stripper_vapin,
2102 reboiler_liqin,
2103 pdL,
2104 pdV,
2105 reduce,
2106 equilibrated,
2107 z_on,
2108 hat_on,
2109 hb_on
2110 );
2111 reboiler IS_A coll_simple_reboiler(
2112 Qin_reboiler,
2113 equilibrated,
2114 reboiler_liqin,
2115 stripper_vapin,
2116 bottoms
2117 );
2118
2119 stot,
2120 s_stack[1..nfeeds+1] IS_A factor;
2121 split[1..nfeeds+1] IS_A fraction;
2122 xsi[components] IS_A fraction;
2123 xsi_set[components] IS_A fraction;
2124 xsi_diff[components] IS_A fraction;
2125 scale IS_A scaling_constant;
2126
2127 s_stack[1],
2128 rectifying_section.stot ARE_THE_SAME;
2129 s_stack[2],
2130 stripping_section.stot ARE_THE_SAME;
2131 stot = SUM[s_stack[1..nfeeds+1]];
2132
2133 FOR j IN [1..nfeeds+1] CREATE
2134
2135 tray_split[j]: s_stack[j] = split[j]*stot;
2136 END FOR;
2137
2138 FOR i IN components CREATE
2139 OverallMB[i]: feed_tray.feed.f[i] =
2140 condenser.distillate.f[i] +
2141 reboiler.bottoms.f[i];
2142 END FOR;
2143
2144 FOR i IN components CREATE
2145 xsi[i]*feed_tray.feed.f[i]
2146 = condenser.distillate.f[i];
2147 xsi_diff[i] = 0.5*sqr(xsi[i] - xsi_set[i]);
2148 END FOR;
2149
2150 recovery: MINIMIZE SUM[xsi_diff[i] | i IN components];
2151
2152 binary_sep[components][components] IS_A factor;
2153
2154 FOR i IN components CREATE
2155 FOR j IN components CREATE
2156 binary_sep[i][j] *
2157 (condenser.distillate.f[i] + condenser.distillate.f[j]) *
2158 (reboiler.bottoms.f[i] + reboiler.bottoms.f[j]) =
2159 (condenser.distillate.f[i] *
2160 (reboiler.bottoms.f[i] + reboiler.bottoms.f[j]) -
2161 reboiler.bottoms.f[i] *
2162 (condenser.distillate.f[i] + condenser.distillate.f[j]));
2163
2164 sep_opt[i][j]: MINIMIZE -sqr(binary_sep[i][j]);
2165
2166 END FOR;
2167 END FOR;
2168
2169 (* costing *)
2170 V[ns] ALIASES
2171 (coll_stack[1..nfeeds+1].coll[1].tray[1].vapout.flow)
2172 WHERE ns IS_A set OF integer_constant
2173 WITH_VALUE (1..nfeeds+1);
2174
2175 V_bar[ns2] ALIASES
2176 (coll_stack[1..nfeeds+1].coll[1].tray[1].vapout.state.V)
2177 WHERE ns2 IS_A set OF integer_constant
2178 WITH_VALUE (1..nfeeds+1);
2179
2180 M_g IS_A molar_mass;
2181
2182 mol_mass: M_g = SUM[feed.Details.state.cd.data[i].mw*
2183 feed_tray.vapout.state.y[i]
2184 | i IN components];
2185
2186 nsections IS_A integer_constant;
2187 nsections :== nfeeds+1;
2188
2189 column_cost IS_A cost_per_time;
2190 cost_calc IS_A cost_calc(
2191 column_cost,
2192 distillate.state.T,
2193 condenser.Qin,
2194 reboiler.Qin,
2195 nsections,
2196 V,
2197 V_bar,
2198 stot,
2199 M_g,
2200 feed.flow
2201 );
2202
2203 objmult IS_A factor;
2204 opcost, capcost IS_A cost_per_time;
2205 optime IS_A fraction;
2206 op_cost_def: opcost = cost_calc.water_cost + cost_calc.steam_cost;
2207 cap_cost_def: capcost = cost_calc.column_cost +
2208 cost_calc.condenser_cost +
2209 cost_calc.reboiler_cost;
2210 tot_cost: MINIMIZE objmult*(capcost + optime*opcost);
2211 cap_cost: MINIMIZE objmult*capcost;
2212 op_cost: MINIMIZE objmult*opcost;
2213
2214 (*
2215 * Cost calculation doesn't mean much for constant alpha case.
2216 * We do provide overide though. :)
2217 *)
2218
2219 WHEN (equilibrated)
2220 CASE TRUE:
2221 USE cost_calc;
2222 USE mol_mass;
2223 USE tot_cost;
2224 USE cap_cost;
2225 USE op_cost;
2226 USE cap_cost_def;
2227 USE op_cost_def;
2228 OTHERWISE:
2229 END WHEN;
2230
2231 do_cost_calc IS_A boolean;
2232 WHEN (do_cost_calc)
2233 CASE TRUE:
2234 USE cost_calc;
2235 USE mol_mass;
2236 USE tot_cost;
2237 USE cap_cost;
2238 USE op_cost;
2239 USE cap_cost_def;
2240 USE op_cost_def;
2241 OTHERWISE:
2242 END WHEN;
2243
2244
2245 (* Plotting Section *)
2246 z_shift IS_A factor;
2247 s_shift IS_A factor;
2248
2249 n_plt_points_x IS_A set OF integer_constant;
2250 n_plt_points_x :== [0..(nfeeds+1)*(coll_stack[1].ncolls*ntrays+3)];
2251 n_plt_points_y IS_A set OF integer_constant;
2252 n_plt_points_y :== [0..(nfeeds+1)*(coll_stack[1].ncolls*ntrays+3)-1];
2253
2254 z_loc_1: coll_stack[1].z_shift = z_shift;
2255 s_loc_1: coll_stack[1].s_shift = s_shift;
2256
2257 z_space IS_A factor;
2258
2259 FOR i IN [2..nfeeds+1] CREATE
2260 z_loc[i]: coll_stack[i].z_shift =
2261 coll_stack[i-1].z_tray_loc[CARD[coll_stack[i-1].n_plt_points]-1]
2262 + z_space; (* add arbitrary factor *)
2263 s_loc[i]: coll_stack[i].s_shift =
2264 coll_stack[i-1].s_tray_loc[coll_stack[1].ncolls*(ntrays+1)]
2265 + 1; (* FOR feed tray *)
2266 END FOR;
2267
2268
2269 reboiler_s_loc, reboiler_z_loc IS_A factor;
2270
2271 z_tray_loc_x[tp] ALIASES (
2272 coll_stack[1..nfeeds+1].z_tray_loc[0..coll_stack[1].ncolls*(ntrays+1)]
2273 , reboiler_z_loc
2274 ) WHERE
2275 tp IS_A set OF integer_constant
2276 WITH_VALUE (0..(nfeeds+1)*(coll_stack[1].ncolls*ntrays+3));
2277
2278 s_tray_loc_x[tp2] ALIASES (
2279 coll_stack[1..nfeeds+1].s_tray_loc[0..coll_stack[1].ncolls*(ntrays+1)]
2280 , reboiler_s_loc
2281 ) WHERE
2282 tp2 IS_A set OF integer_constant
2283 WITH_VALUE (0..(nfeeds+1)*(coll_stack[1].ncolls*ntrays+3));
2284
2285 reb_s_loc: reboiler_s_loc = 1 +
2286 s_tray_loc_x[(nfeeds+1)*(coll_stack[1].ncolls*ntrays+3)-1];
2287 reb_z_loc: reboiler_z_loc =
2288 coll_stack[nfeeds+1].
2289 z_tray_loc[CARD[coll_stack[nfeeds+1].n_plt_points]-1] +
2290 z_space;
2291
2292 z_tray_loc_y[tp3] ALIASES (
2293 coll_stack[1..nfeeds+1].z_tray_loc[0..coll_stack[1].ncolls*(ntrays+1)]
2294 ) WHERE
2295 tp3 IS_A set OF integer_constant
2296 WITH_VALUE (0..(nfeeds+1)*(coll_stack[1].ncolls*ntrays+3)-1);
2297
2298 s_tray_loc_y[tp4] ALIASES (
2299 coll_stack[1..nfeeds+1].s_tray_loc[0..coll_stack[1].ncolls*(ntrays+1)]
2300 ) WHERE
2301 tp4 IS_A set OF integer_constant
2302 WITH_VALUE (0..(nfeeds+1)*(coll_stack[1].ncolls*ntrays+3)-1);
2303
2304
2305 FOR i IN coll_stack[1].topliq.components CREATE
2306 x_plot[i][np[i]] ALIASES (
2307 coll_stack[1..nfeeds+1].
2308 x_plot[i][0..coll_stack[1].ncolls*(ntrays+1)],
2309 reboiler.bottoms.state.y[i]
2310 ) WHERE
2311 np[i] IS_A set OF integer_constant
2312 WITH_VALUE (0..(nfeeds+1)*(coll_stack[1].ncolls*ntrays+3));
2313 y_plot[i][np2[i]] ALIASES (
2314 coll_stack[1..nfeeds+1].
2315 y_plot[i][0..coll_stack[1].ncolls*(ntrays+1)]
2316 ) WHERE
2317 np2[i] IS_A set OF integer_constant
2318 WITH_VALUE (0..(nfeeds+1)*(coll_stack[1].ncolls*ntrays+3)-1);
2319 END FOR;
2320
2321 FOR i IN coll_stack[1].topliq.components CREATE
2322 x_z_curves[i] IS_A plt_curve(n_plt_points_x,x_plot[i],z_tray_loc_x);
2323 x_s_curves[i] IS_A plt_curve(n_plt_points_x,x_plot[i],s_tray_loc_x);
2324 y_z_curves[i] IS_A plt_curve(n_plt_points_y,y_plot[i],z_tray_loc_y);
2325 y_s_curves[i] IS_A plt_curve(n_plt_points_y,y_plot[i],s_tray_loc_y);
2326 END FOR;
2327
2328 Plot_xz IS_A plt_plot_symbol(coll_stack[1].topliq.components,x_z_curves);
2329 Plot_xs IS_A plt_plot_symbol(coll_stack[1].topliq.components,x_s_curves);
2330
2331 Plot_yz IS_A plt_plot_symbol(coll_stack[1].topliq.components,y_z_curves);
2332 Plot_ys IS_A plt_plot_symbol(coll_stack[1].topliq.components,y_s_curves);
2333
2334 ncomps IS_A integer_constant;
2335 ncomps :== CARD[components];
2336
2337 SELECT (ncomps)
2338 CASE 3:
2339 T_Liq_diagram_e IS_A
2340 ternary_plot_equilateral('liquid composition profiles',
2341 components,
2342 CHOICE[components],
2343 CHOICE[components - [CHOICE[components]]],
2344 n_plt_points_x,x_plot);
2345 T_Vap_diagram_e IS_A
2346 ternary_plot_equilateral('vapor composition profiles',
2347 components,
2348 CHOICE[components],
2349 CHOICE[components - [CHOICE[components]]],
2350 n_plt_points_y,y_plot);
2351 END SELECT;
2352
2353 METHODS
2354
2355 METHOD default_self;
2356
2357 RUN condenser_vapin.default_self;
2358 RUN rectifier_liqin.default_self;
2359 RUN rectifier_vapin.default_self;
2360 RUN feed_tray_liqin.default_self;
2361 RUN feed_tray_vapin.default_self;
2362 RUN stripper_liqin.default_self;
2363 RUN stripper_vapin.default_self;
2364 RUN reboiler_liqin.default_self;
2365
2366 RUN condenser.default_self;
2367 RUN coll_stack[1..nfeeds+1].default_self;
2368 RUN feed_tray.default_self;
2369 RUN reboiler.default_self;
2370
2371 RUN cost_calc.default_self;
2372
2373 hb_on := FALSE;
2374 equilibrated := FALSE;
2375 do_cost_calc := FALSE;
2376 FIX objmult;
2377 objmult := 10000;
2378 FIX optime;
2379 optime := 1.0;
2380 split[1..nfeeds+1] := 1.0/(nfeeds+1);
2381
2382 FIX z_shift;
2383 FIX s_shift;
2384 z_shift := 0;
2385 s_shift := 0;
2386 z_space := 0.1;
2387
2388 distillate.state.phase_fraction['vapor'] := 0;
2389
2390 Plot_xz.title := 'Liquid Compositions vs. z';
2391 Plot_xz.YLabel := 'Liquid Compositions';
2392 Plot_xz.XLabel := 'transformed stage location (z)';
2393 Plot_xz.Ylow := 0;
2394 Plot_xz.Yhigh := 1;
2395
2396 Plot_xs.title := 'Liquid Compositions vs. s';
2397 Plot_xs.YLabel := 'Liquid Compositions';
2398 Plot_xs.XLabel := 'stage location (s)';
2399 Plot_xs.Ylow := 0;
2400 Plot_xs.Yhigh := 1;
2401
2402 Plot_yz.title := 'Vapor Compositions vs. z';
2403 Plot_yz.YLabel := 'Vapor Compositions';
2404 Plot_yz.XLabel := 'transformed stage location (z)';
2405 Plot_yz.Ylow := 0;
2406 Plot_yz.Yhigh := 1;
2407
2408 Plot_ys.title := 'Vapor Compositions vs. s';
2409 Plot_ys.YLabel := 'Vapor Compositions';
2410 Plot_ys.XLabel := 'stage location (s)';
2411 Plot_ys.Ylow := 0;
2412 Plot_ys.Yhigh := 1;
2413
2414 FOR i IN components DO
2415 Plot_xz.curve[i].legend := i;
2416 Plot_xs.curve[i].legend := i;
2417 Plot_yz.curve[i].legend := i;
2418 Plot_ys.curve[i].legend := i;
2419 END FOR;
2420
2421 IF (ncomps == 3) THEN
2422 RUN T_Liq_diagram_e.default_self;
2423 RUN T_Vap_diagram_e.default_self;
2424 END IF;
2425
2426 END default_self;
2427 METHOD default_all;
2428 RUN distillate.default_all;
2429 RUN feed.default_all;
2430 RUN bottoms.default_all;
2431 RUN default_self;
2432 END default_all;
2433
2434 METHOD scale_self;
2435 stot.nominal := stot;
2436 coll_stack[1..nfeeds+1].stot.upper_bound :=
2437 stot.upper_bound/(nfeeds+1) + 1.0;
2438 RUN condenser.scale_self;
2439 RUN coll_stack[1..nfeeds+1].scale_self;
2440 RUN feed_tray.scale_self;
2441 RUN reboiler.scale_self;
2442 FOR i IN components DO
2443 xsi[i].nominal := xsi[i];
2444 xsi_set[i].nominal := xsi_set[i];
2445 xsi_diff[i].nominal := xsi_diff[i];
2446 END FOR;
2447 END scale_self;
2448 METHOD scale_all;
2449 RUN scale_self;
2450 RUN distillate.scale_all;
2451 RUN feed.scale_all;
2452 RUN bottoms.scale_all;
2453 END scale_all;
2454 METHOD bound_self;
2455 stot.lower_bound := 4;
2456 stot.upper_bound := 100;
2457 RUN condenser.bound_self;
2458 RUN coll_stack[1..nfeeds+1].bound_self;
2459 RUN feed_tray.bound_self;
2460 RUN reboiler.bound_self;
2461 END bound_self;
2462 METHOD bound_all;
2463 RUN bound_self;
2464 RUN distillate.bound_all;
2465 RUN feed.bound_all;
2466 RUN bottoms.bound_all;
2467 END bound_all;
2468 METHOD check_self;
2469 END check_self;
2470 METHOD check_all;
2471 RUN check_self;
2472 RUN distillate.check_all;
2473 RUN feed.check_all;
2474 RUN bottoms.check_all;
2475 END check_all;
2476
2477 METHOD values;
2478 RUN coll_stack[1..nfeeds+1].values;
2479 END values;
2480
2481 METHOD heat_balance;
2482 RUN coll_stack[1..nfeeds+1].heat_balance;
2483 FREE feed_tray.q;
2484 FIX feed_tray.Qin;
2485 hb_on := TRUE;
2486 END heat_balance;
2487 METHOD CMO;
2488 RUN coll_stack[1..nfeeds+1].CMO;
2489 FIX feed_tray[1..nfeeds].q;
2490 FREE feed_tray[1..nfeeds].Qin;
2491 hb_on := FALSE;
2492 END CMO;
2493 METHOD reduce_Q;
2494 FOR i IN [1..nfeeds+1] DO
2495 FOR j IN [1..coll_stack[i].ncolls] DO
2496 coll_stack[i].coll[j].Qtot :=
2497 coll_stack[i].coll[j].Qtot*reduce;
2498 FOR k IN [1..coll_stack[i].coll[j].ntrays] DO
2499 coll_stack[i].coll[j].Qin[k] :=
2500 coll_stack[i].coll[j].Qin[k]*reduce;
2501 coll_stack[i].coll[j].tray[k].Qin :=
2502 coll_stack[i].coll[j].tray[k].Qin*reduce;
2503 END FOR;
2504 END FOR;
2505 END FOR;
2506 feed_tray.Qin :=
2507 feed_tray.Qin*reduce;
2508 END reduce_Q;
2509 METHOD zero_Q;
2510 reduce := 0;
2511 RUN reduce_Q;
2512 END zero_Q;
2513
2514 METHOD specify_feed;
2515 RUN feed.ClearAll;
2516 IF (feed.pd.phase_indicator == 'VL') THEN
2517 feed.equilibrated := equilibrated;
2518 RUN feed.specify;
2519 IF (equilibrated == TRUE) THEN
2520 IF (saturated_liquid_feed == TRUE) THEN
2521 saturated_vapor_feed := FALSE;
2522 FREE feed.T;
2523 FIX feed.state.phase_fraction['vapor'];
2524 feed.state.phase_fraction['vapor'] := 0.0;
2525 END IF;
2526 IF (saturated_vapor_feed == TRUE) THEN
2527 FREE feed.T;
2528 FIX feed.state.phase_fraction['vapor'];
2529 feed.state.phase_fraction['vapor'] := 1.0;
2530 END IF;
2531 END IF;
2532 ELSE
2533 RUN feed.specify;
2534 END IF;
2535 END specify_feed;
2536 METHOD seqmod;
2537 RUN condenser.seqmod;
2538 RUN coll_stack[1..nfeeds+1].seqmod;
2539 RUN feed_tray.seqmod;
2540 RUN reboiler.seqmod;
2541 OverallMB[components].included := FALSE;
2542 FREE reboiler.reboil_ratio;
2543 FIX condenser.distillate.flow;
2544 FIX xsi_set[components];
2545 IF (hb_on) THEN
2546 RUN heat_balance;
2547 END IF;
2548 recovery.included := FALSE;
2549 sep_opt[components][components].included := FALSE;
2550 FIX z_space;
2551 FIX s_shift;
2552 FIX z_shift;
2553 END seqmod;
2554
2555 METHOD seqmod_massbal;
2556 FIX objmult;
2557 FIX optime;
2558 hb_on := FALSE;
2559 equilibrated := FALSE;
2560
2561 RUN cost_calc.seqmod;
2562 RUN condenser.seqmod;
2563 RUN coll_stack[1..nfeeds+1].seqmod_massbal;
2564 RUN feed_tray.seqmod_massbal;
2565 RUN reboiler.seqmod;
2566 OverallMB[components].included := FALSE;
2567 FREE reboiler.reboil_ratio;
2568 FIX condenser.distillate.flow;
2569 FIX xsi_set[components];
2570 recovery.included := FALSE;
2571 sep_opt[components][components].included := FALSE;
2572
2573 FIX z_space;
2574 FIX s_shift;
2575 FIX z_shift;
2576
2577 END seqmod_massbal;
2578
2579 METHOD seqmod_fullthermo;
2580 FIX objmult;
2581 FIX optime;
2582 hb_on := FALSE;
2583 equilibrated := TRUE;
2584
2585 RUN cost_calc.seqmod;
2586 RUN condenser.seqmod;
2587 RUN coll_stack[1..nfeeds+1].seqmod_fullthermo;
2588 RUN feed_tray.seqmod_fullthermo;
2589 RUN reboiler.seqmod;
2590 OverallMB[components].included := FALSE;
2591 FREE reboiler.reboil_ratio;
2592 FIX condenser.distillate.flow;
2593 FIX xsi_set[components];
2594 recovery.included := FALSE;
2595 sep_opt[components][components].included := FALSE;
2596
2597 FIX z_space;
2598 FIX s_shift;
2599 FIX z_shift;
2600
2601 END seqmod_fullthermo;
2602
2603 METHOD seqmod_adiabatic;
2604 FIX objmult;
2605 FIX optime;
2606 hb_on := TRUE;
2607 equilibrated := TRUE;
2608 RUN seqmod_fullthermo;
2609 RUN heat_balance;
2610
2611 FIX z_space;
2612 FIX s_shift;
2613 FIX z_shift;
2614
2615 END seqmod_adiabatic;
2616
2617 METHOD specify;
2618 IF (hb_on AND NOT(equilibrated)) THEN
2619 equilibrated := TRUE;
2620 END IF;
2621 IF (hb_on AND equilibrated) THEN
2622 RUN seqmod_adiabatic;
2623 END IF;
2624 IF (NOT(hb_on) AND equilibrated) THEN
2625 RUN seqmod_fullthermo;
2626 END IF;
2627 IF (NOT(hb_on) AND NOT(equilibrated)) THEN
2628 RUN seqmod_massbal;
2629 END IF;
2630 RUN specify_feed;
2631
2632 FREE condenser.liqout.T;
2633 FREE condenser.liqout.P;
2634 END specify;
2635 METHOD reset;
2636 RUN ClearAll;
2637 RUN specify;
2638 END reset;
2639 METHOD standard_poly;
2640 hat_on := FALSE;
2641 END standard_poly;
2642 METHOD trans_poly;
2643 hat_on := TRUE;
2644 END trans_poly;
2645 METHOD z_based_poly;
2646 z_on := TRUE;
2647 END z_based_poly;
2648 METHOD s_based_poly;
2649 z_on := FALSE;
2650 END s_based_poly;
2651 METHOD propagate_feed_values;
2652 FOR i IN components DO
2653 FOR k IN [1..nfeeds+1] DO
2654 FOR j IN [1..coll_stack[k].ncolls] DO
2655 coll_stack[k].coll[j].tray[1..coll_stack[k]
2656 .coll[j].ntrays].alpha[i]
2657 := feed_tray.alpha[i];
2658 END FOR;
2659 END FOR;
2660 reboiler.alpha[i] :=
2661 feed_tray.alpha[i];
2662 END FOR;
2663 END propagate_feed_values;
2664 METHOD initialize_feed_tray_state;
2665 FOR i IN components DO
2666 feed_tray.state.y[i] :=
2667 feed.f[i]/SUM[feed.f[j] | j IN components];
2668 END FOR;
2669 feed_tray.state.T := feed.T;
2670 feed_tray.state.P := feed.P;
2671 END initialize_feed_tray_state;
2672
2673 METHOD overallMB;
2674 OverallMB[components].included := TRUE;
2675 feed_tray[1].totfeedflow[components].included := FALSE;
2676 END overallMB;
2677
2678 METHOD reset_to_massbal;
2679 hb_on := FALSE;
2680 equilibrated := FALSE;
2681 RUN reset;
2682 END reset_to_massbal;
2683
2684 METHOD reset_to_fullthermo;
2685 hb_on := FALSE;
2686 equilibrated := TRUE;
2687 RUN reset;
2688 FREE distillate.T;
2689 FIX distillate.state.phase_fraction['vapor'];
2690 distillate.state.phase_fraction['vapor'] := 0;
2691 END reset_to_fullthermo;
2692
2693 METHOD reset_to_adiabatic;
2694 hb_on := TRUE;
2695 equilibrated := TRUE;
2696 RUN reset;
2697 FREE distillate.T;
2698 FIX distillate.state.phase_fraction['vapor'];
2699 distillate.state.phase_fraction['vapor'] := 0;
2700 END reset_to_adiabatic;
2701
2702 METHOD equipment_bounds;
2703 RUN cost_calc.equipment_bounds;
2704 END equipment_bounds;
2705
2706 METHOD optimization_DOF;
2707 FREE distillate.flow;
2708 FREE condenser.reflux_ratio;
2709 FREE s_stack[1..2];
2710 END optimization_DOF;
2711 END simple_coll_column;
2712
2713
2714 MODEL test_coll_column();
2715 cd IS_A components_data(
2716 ['acetone','benzene','chloroform'],'chloroform'
2717 );
2718 pdVL IS_A phases_data('VL','Pitzer_vapor_mixture',
2719 'Wilson_liquid_mixture','none');
2720 pdV IS_A phases_data('V','Pitzer_vapor_mixture','none','none');
2721 pdL IS_A phases_data('L','none','Wilson_liquid_mixture','none');
2722
2723
2724 Feed_equil, Equilibrated IS_A start_false;
2725 Feed IS_A stream(cd, pdVL, Feed_equil);
2726 Distillate IS_A stream(cd, pdVL, Equilibrated);
2727 Bottoms IS_A stream(cd, pdL, Equilibrated);
2728
2729 ntrays IS_A integer_constant;
2730 ntrays :== 2;
2731
2732 reduce IS_A fraction;
2733
2734 z_on, hat_on, hb_on IS_A start_false;
2735
2736 Column IS_A simple_coll_column(
2737 ntrays,
2738 pdVL,
2739 Distillate,
2740 Feed,
2741 Bottoms,
2742 Equilibrated,
2743 reduce,
2744 z_on,
2745 hat_on,
2746 hb_on
2747 );
2748 boundwidth IS_A bound_width;
2749
2750 METHODS
2751
2752 METHOD default_self;
2753 RUN Feed.default_self;
2754 RUN Distillate.default_self;
2755 RUN Bottoms.default_self;
2756 RUN Column.default_self;
2757 boundwidth := 100;
2758 END default_self;
2759
2760 METHOD check_self;
2761 RUN Feed.check_self;
2762 RUN Distillate.check_self;
2763 RUN Bottoms.check_self;
2764 RUN Column.check_self;
2765 END check_self;
2766
2767 METHOD scale_self;
2768 RUN Feed.scale_self;
2769 RUN Distillate.scale_self;
2770 RUN Bottoms.scale_self;
2771 RUN Column.scale_self;
2772 END scale_self;
2773
2774 METHOD bound_self;
2775 Column.boundwidth := boundwidth;
2776 Profile.boundwidth := boundwidth;
2777 Feed.boundwidth := boundwidth;
2778 Distillate.boundwidth := boundwidth;
2779 Bottoms.boundwidth := boundwidth;
2780 RUN Feed.bound_self;
2781 RUN Distillate.bound_self;
2782 RUN Bottoms.bound_self;
2783 RUN Column.bound_self;
2784 END bound_self;
2785
2786 METHOD bound_all;
2787 RUN bound_self;
2788 END bound_all;
2789
2790 METHOD scale_all;
2791 RUN scale_self;
2792 END scale_all;
2793
2794 METHOD check_all;
2795 RUN check_self;
2796 END check_all;
2797
2798 METHOD default_all;
2799 RUN default_self;
2800 END default_all;
2801
2802 METHOD values;
2803 Column.condenser.reflux_ratio := 2.0;
2804 Column.s_stack[1] := 10;
2805 Column.s_stack[2] := 10;
2806 Feed.T := 298 {K};
2807 Feed.P := 1{atm};
2808 Feed.f['acetone'] := 3.6 {mole/s};
2809 Feed.f['benzene'] := 4 {mole/s};
2810 Feed.f['chloroform'] := 2.4 {mole/s};
2811 Distillate.flow := 6.0 {mole/s};
2812
2813 RUN Column.initialize_feed_tray_state;
2814 END values;
2815
2816 END test_coll_column;

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