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

Contents of /trunk/models/collocation.a4l

Parent Directory Parent Directory | Revision Log Revision Log


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

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