1
/* ASCEND modelling environment
2
Copyright (C) 1990, 1993, 1994 Thomas Guthrie Epperly, Kirk Abbott.
3
Copyright (C) 2006 Carnegie Mellon University
5
This program is free software; you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation; either version 2, or (at your option)
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
GNU General Public License for more details.
15
You should have received a copy of the GNU General Public License
16
along with this program; if not, write to the Free Software
17
Foundation, Inc., 59 Temple Place - Suite 330,
18
Boston, MA 02111-1307, USA.
21
External distillation routines
25
Version: $Revision: 1.5 $
26
Date last modified: $Date: 1997/07/18 12:20:07 $
29
#include <utilities/ascConfig.h>
31
#include <compiler/packages.h>
32
#include <compiler/instance_enum.h>
35
#include <compiler/expr_types.h>
36
#include <general/list.h>
37
#include <compiler/sets.h>
38
#include <compiler/atomvalue.h>
39
#include <compiler/parentchild.h>
40
#include <compiler/instquery.h>
41
#include <compiler/instance_name.h>
42
#include <compiler/symtab.h>
43
#include <compiler/extcall.h>
47
#define KVALUES_DEBUG 1
49
#ifndef EXTERNAL_EPSILON
50
#define EXTERNAL_EPSILON 1.0e-12
53
#define N_INPUT_ARGS 3
54
#define N_OUTPUT_ARGS 1
62
static struct Vpdata VpTable[] = {
63
{ "benzene", 15.5381, 2032.73, -33.15 },
64
{ "chloro" , 15.8333, 2477.07, -39.94 },
65
{ "acetone", 15.8737, 2911.32, -56.51 },
66
{ "hexane" , 15.3866, 2697.55, -46.78 },
67
{ "", 0.0, 0.0 , 0.0 }
70
struct KVALUES_problem {
78
static struct KVALUES_problem *CreateProblem(void)
80
struct KVALUES_problem *result;
81
result = (struct KVALUES_problem *)malloc(sizeof(struct KVALUES_problem));
83
result->components = NULL;
84
result->ninputs = result->noutputs = 0;
89
static int LookupData(struct Vpdata *vp)
91
/* char *component; */
94
while (strcmp(VpTable[c].component,"")!=0) {
95
if (strcmp(VpTable[c].component,vp->component)==0) {
108
The 2nd. argument is the array of mole fractions.
109
the length of this list is then the number of components.
111
static int GetNumberOfComponents(struct gl_list_t *arglist)
114
struct gl_list_t *mole_fracs;
115
mole_fracs = (struct gl_list_t *)gl_fetch(arglist,2L);
117
ncomps = (int)gl_length(mole_fracs);
121
return 0; /* error */
126
The following code takes a data instance and tries to decode it
127
to determine the names of the components used in the model. It will
128
then create an array of these names and attach it to the problem.
129
The data is expected to be an instance of a model of the form:
134
components[1..ncomps] IS_A symbol;
136
components[1] := 'a';
137
components[2] := 'b';
138
components[3] := 'c';
142
static int GetComponentData(
143
struct Instance *data,
144
struct KVALUES_problem *problem
146
struct InstanceName name;
147
struct Instance *child;
151
symchar *s_component = NULL;
153
s_component = AddSymbol("components");
154
SetInstanceNameStrPtr(name,s_component);
155
SetInstanceNameType(name,StrName);
158
FPRINTF(stderr,"Error: expecting a data instance to be provided\n");
161
pos = ChildSearch(data,&name); /* find array head */
163
FPRINTF(stderr,"Error: cannot find instance \"components\"\n");
166
child = InstanceChild(data,pos);
167
if (InstanceKind(child)!= ARRAY_INT_INST) {
168
FPRINTF(stderr,"Error: expecting components to be an array\n");
171
nch = NumberChildren(child);
172
if ((nch==0) || (nch!=problem->ncomps)) {
173
FPRINTF(stderr,"Error: Inconsistent component definitions\n");
176
if (InstanceKind(InstanceChild(child,1))!=SYMBOL_ATOM_INST) {
177
FPRINTF(stderr,"Error: Expecting an array of symbols\n");
181
problem->components = (char **)malloc((int)nch*sizeof(char *));
182
for (c=1;c<=nch;c++) {
183
component = (char *)GetSymbolAtomValue(InstanceChild(child,c));
184
problem->components[c-1] = component; /* just peek at it; dont copy it */
190
static int CheckArgsOK(struct BBoxInterp *interp
191
, struct Instance *data
192
, struct gl_list_t *arglist
193
, struct KVALUES_problem *problem
195
unsigned long len,ninputs,noutputs;
201
FPRINTF(stderr,"External function argument list does not exist\n");
204
len = gl_length(arglist);
206
FPRINTF(stderr,"No arguments to external function statement\n");
209
if ((len!=(N_INPUT_ARGS+N_OUTPUT_ARGS))) {
210
FPRINTF(stderr,"Number of arguments does not match\n");
211
FPRINTF(stderr,"external function prototype\n");
215
ninputs = CountNumberOfArgs(arglist,1,N_INPUT_ARGS);
216
noutputs = CountNumberOfArgs(arglist,N_INPUT_ARGS+1,
217
N_INPUT_ARGS+N_OUTPUT_ARGS);
218
n_components = GetNumberOfComponents(arglist);
220
problem->ninputs = (int)ninputs;
221
problem->noutputs = (int)noutputs;
222
problem->ncomps = n_components;
223
result = GetComponentData(data,problem); /* get the component names */
231
static void kvalues_final( struct BBoxInterp *interp){
232
struct KVALUES_problem *problem;
233
if (interp && interp->user_data) {
234
problem = (struct KVALUES_problem *)interp->user_data;
235
if (problem->components) free((char *)problem->components);
236
if (problem->x) free((char *)problem->x);
237
if (problem->x) free((char *)problem);
239
interp->user_data = NULL;
243
This function is one of the registered functions. It operates in
244
one modes first_call, and
245
creates a KVALUES_problem and calls a number of routines to check
246
the arguments (data and arglist) and to cache the information
247
processed away in the KVALUES_problem structure. We then attach
250
In last_call mode, which should never be seen,
251
we delegate to final where we cleanup the problem structure:
252
the array of compononent string pointers (we dont own the strings).
253
the array of doubles.
254
the problem structure itself.
256
int kvalues_preslv(struct BBoxInterp *interp,
257
struct Instance *data,
258
struct gl_list_t *arglist
261
struct KVALUES_problem *problem;
263
/*struct Instance *arg;
267
if (interp->task == bb_first_call) {
268
if (interp->user_data!=NULL) { /* we have been called before */
269
return 0; /* the problem structure exists */
272
problem = CreateProblem();
273
if(CheckArgsOK(interp,data,arglist,problem)) {
276
workspace = /* T, x[1..n], P, y[1..n], satp[1..n] */
277
problem->ninputs + problem->noutputs +
279
problem->x = (double *)calloc(workspace, sizeof(double));
280
interp->user_data = (void *)problem;
284
if (interp->task == bb_last_call) {
285
kvalues_final(interp);
292
This function provides support to kvalues_fex which is one of the
293
registered functions. The input variables are T,x[1..ncomps],P.
294
The output variables are y[1..n]. We also load up the x vector
295
(our copy) with satP[1..ncomps] as proof of concept that we can
296
do (re)initialization.
300
The name field will be field in vp before the call.
301
The rest of the data will be filled the structure
302
provided that there are no errors.
304
static int GetCoefficients(struct Vpdata *vp){
305
if (LookupData(vp)==0)
308
return 1; /* error in name lookup */
312
static int DoCalculation(struct BBoxInterp *interp,
313
int ninputs, int noutputs,
317
struct KVALUES_problem *problem;
321
double *liq_frac = NULL;
322
double *vap_frac = NULL;
328
problem = (struct KVALUES_problem *)interp->user_data;
329
ncomps = problem->ncomps;
330
assert(ninputs == ncomps+2);
331
assert(noutputs == ncomps);
332
liq_frac = (double *)calloc(ncomps,sizeof(double));
333
vap_frac = (double *)calloc(ncomps,sizeof(double));
334
SatP = (double *)calloc(ncomps,sizeof(double));
336
T = inputs[0]; offset = 1;
337
for(c=0;c<ncomps;c++) {
338
liq_frac[c] = inputs[c+offset];
341
TotP = inputs[offset];
343
for (c=0;c<ncomps;c++) {
344
vp.component = problem->components[c]; /* get component name */
345
result = GetCoefficients(&vp); /* get antoines coeffs */
346
SatP[c] = exp(vp.a - vp.b/(T + vp.c)); /* calc satP */
347
vap_frac[c] = SatP[c] * liq_frac[c] / TotP;
351
FPRINTF(stdout,"Temperature T = %12.8f\n",T);
352
FPRINTF(stdout,"TotalPressure P = %12.8f\n",TotP);
353
for(c=0;c<ncomps;c++) {
354
FPRINTF(stdout,"x[%d] = %12.8g\n",c,liq_frac[c]);
356
for (c=0;c<ncomps;c++) {
357
FPRINTF(stdout,"y[%d] = %20.8g\n",c,vap_frac[c]);
359
#endif /* KVALUES_DEBUG */
362
* Save values, copy the information to the output vector
365
tmp = problem->x; /* save the input data */
367
for (c=0;c<ncomps;c++) {
373
for (c=0;c<ncomps;c++) { /* save the output data */
374
*tmp = outputs[c] = vap_frac[c]; /* load up the output vector also */
378
for (c=0;c<ncomps;c++) { /* save the internal data */
383
free((char *)liq_frac);
384
free((char *)vap_frac);
386
interp->status = calc_all_ok;
390
int kvalues_fex(struct BBoxInterp *interp,
391
int ninputs, int noutputs,
392
double *inputs, double *outputs,
397
nok = DoCalculation(interp, ninputs, noutputs, inputs, outputs);
405
Registration function
407
int kvalues_register(void){
409
double epsilon = 1.0e-14;
411
char kvalues_help[] = "This function does a bubble point calculation\
412
given the mole fractions in the feed, a T and P.";
414
result = CreateUserFunctionBlackBox("bubblepnt", kvalues_preslv, kvalues_fex,
415
NULL,NULL,kvalues_final,
416
N_INPUT_ARGS,N_OUTPUT_ARGS,
417
kvalues_help,epsilon);