-
Notifications
You must be signed in to change notification settings - Fork 0
/
ELAFish.base.msl
415 lines (331 loc) · 13.8 KB
/
ELAFish.base.msl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
// -----------------------------------------------------------------------
// HEMMIS - Ghent University, BIOMATH - Université Laval, modelEAU
// Implementation: Hans Vangheluwe, Peter Vanrolleghem, Henk Vanhooren,
// Jurgen Meirlaen,Frederik Decouttere, Youri Amerlinck
// Frederik De Laender, Ludiwine Clouzot.
// Description: MSL-USER/ELAFish/Base definitions
// -----------------------------------------------------------------------
#ifndef ELAFISH_BASE
#define ELAFISH_BASE
CLASS WWTPAtomicModel
"
A generic atomic WWTP model.
Only specifies mass balances (mass variation is
sum of biological mass fluxes (bioflux, with incoming =
positive sign, outgoing = negative sign) and a generic
conversion term (only declared here. Has to be specified
later).
"
SPECIALISES PhysicalDAEModelType :=
{:
parameters <-
{
// Due to the shape of the equations we use,
// it is more appropriate to work with Specific Volume =
// 1/Density (thus, we deal with specific volume = 0 rather than
// with density = infinity) than with density.
// The density (and hence specific volume) of different components
// seems to be global information (i.e., not model instance specific).
// There are however two reasons for NOT declaring
// WWTPSpecificVolume information as a global object.
// 1. WWTPSpecificVolume is a vector of size NrOfComponents.
// Obvioulsy, filling in values in this vector can only
// be done once we know which components are used.
// Example: referring to WWTPSpecificVolume[S_S] if the
// component S_S is not used is pointless.
// Thus, it seems more reasonable to put WWTPSpecificVolume
// in the parameter section of a (generic) model.
// 2. Once MSL-EXEC code is generated, the user
// currently only has access (from the Experiment Environment)
// to variables and parameters. Global variables (the logical
// C equivalent of global MSL objects) are not accessible
// (and currently not even generated for that matter).
// We thus HAVE to put WWTPSpecificVolume with the parameters.
// When it is put there, the user will be able to see(including
// symbolic information) and even change (though that may not be needed)
// Specific Volume data.
// Later, it may be meaningful to include a global
// constants/parameters section in MSL-EXEC.
// We only declare WWTPSpecificVolume here.
// Actual values will be given by the user in the equations of a model.
// except for WWTPSpecificVolume[H2O] := 0.000001
// declared in the initial section
OBJ WWTPSpecificVolume (* hidden = "1" *)
"Vector containing the specific volume (= 1/density) for all the components"
: SpecificVolumeVector;
//
// Indexing is done by means of the symbolic indices from the
// enumerated type Components.
//
// WWTPSpecificVolume[H2O] := 0.000001;
//
// By default, if no explicit assignment is done, the value is zero.
// Thus, with the assumption that density of H2O = 1 and all the
// other densities are infinite, WWTPSpecificVolume[S_S] = 0;
// etc. must not be written.
};
initial <-
{
parameters.WWTPSpecificVolume[H2O] := 0.000001;
};
independent <- { OBJ t "Time" : Time; };
state <-
{
OBJ M "Vector containing masses for all the components" : MassVector;
OBJ FluxPerComponent (* hidden = "1" *) "Vector containing fluxes for all the components, the sum of all incoming and outgoing fluxes" : MassFluxVector;
OBJ InFluxPerComponent (* hidden = "1" *) "Vector containing incoming fluxes for all the components": MassFluxVector;
OBJ ConversionTermPerComponent (* hidden = "1" *) "Vector containing conversionterms for all the components": MassFluxVector;
OBJ Q_In "Influent flow rate" : FlowRate ;
};
equations <-
{
// The FluxPerComponent is the sum of all
// incoming (positive) and outgoing (negative) fluxes
{FOREACH Comp_Index IN {1 .. NrOfComponents}:
state.FluxPerComponent[Comp_Index] =
// If not only WWTPTerminal type terminals are present in the interface
// (e.g., also ControlTerminal), we have to select only
// those terminals from the interface which are of
// WWTPTerminal type (or any SUBtype such as InWWTPTerminal of it)
// as those are the only ones for which the mass balance law holds.
(SUMOVER In_Terminal IN {SelectByType(interface,InWWTPTerminal)}:
In_Terminal[Comp_Index])+
(SUMOVER Out_Terminal IN {SelectByType(interface,OutWWTPTerminal)}:
Out_Terminal[Comp_Index]);};
// The mass balance equations.
// These are composed of a term due to incoming and
// outgoing fluxes and of a term due to biochemical
// interactions between components.
{FOREACH Comp_Index IN {1 .. NrOfComponents}:
DERIV(state.M[Comp_Index],[independent.t]) =
state.FluxPerComponent[Comp_Index]
+state.ConversionTermPerComponent[Comp_Index];};
// for efficiency and because most models need it anyway
// we calculate Q_In here
{FOREACH Comp_Index IN {1 .. NrOfComponents}:
state.InFluxPerComponent[Comp_Index] =
SUMOVER In_Terminal IN {SelectByType(interface,InWWTPTerminal)}:
(In_Terminal[Comp_Index]);
};
{state.Q_In = (parameters.WWTPSpecificVolume[H2O]
* state.InFluxPerComponent[H2O]);
};
// Less general Q_In calculation to avoid algebraic loops in the
// modelling of WWTP's (Algebraic loops for S_I -> X_ND induced
// by Q_In !!!)
};
:};
//===================================================================
//==============================WWTPAtomicModelWithoutVolume=========
//===================================================================
// BE CAREFUL
// IS NOT A SPECIALIZATION OF WWTPATOMICMODEL !!!
// FOR EFFICIENCY REASONS
CLASS WWTPAtomicModelWithoutVolume
SPECIALISES PhysicalDAEModelType :=
{:
parameters <-
{
OBJ WWTPSpecificVolume (* hidden = "1" *)
"Vector containing the specific volume (= 1/density) for all the components"
: SpecificVolumeVector;
};
initial <-
{
parameters.WWTPSpecificVolume[H2O] := 0.000001;
};
independent <- { OBJ t "Time" : Time; };
state <-
{
OBJ InFluxPerComponent (* hidden = "1" *) "Vector containing incoming fluxes for all components" : MassFluxVector;
OBJ Q_In "Influent flow rate" : FlowRate ;
};
equations <-
{
{ FOREACH Comp_Index IN {1 .. NrOfComponents}:
state.InFluxPerComponent[Comp_Index] =
SUMOVER In_Terminal IN {SelectByType(interface,InWWTPTerminal)}:
(In_Terminal[Comp_Index]);
};
{state.Q_In = (parameters.WWTPSpecificVolume[H2O]
* state.InFluxPerComponent[H2O]);
};
};
:};
//=================================================================
//===============================WWTPAtomicModelWithVolume=========
//=================================================================
CLASS WWTPAtomicModelWithVolume EXTENDS WWTPAtomicModel WITH
{:
state <-
{
OBJ V "Volume" : Volume;
OBJ C "Vector containing concentrations for all the components" : ConcentrationVector;
};
equations <-
{
// volume and conc equations are calculated
// specific to fixed or variable volume
};
:};
//======================================================================
//===========================WWTPAtomicModelWithVariableVolume==========
//======================================================================
CLASS WWTPAtomicModelWithVariableVolume
EXTENDS WWTPAtomicModelWithVolume WITH
{:
interface <-
{
OBJ Inflow (* terminal = "in_1" *) "Inflow" :
InWWTPTerminal := {: causality <- "CIN" :};
OBJ Outflow (* terminal = "out_1" *)"Outflow" :
OutWWTPTerminal := {: causality <- "COUT" :};
};
parameters <-
{
OBJ N "Number of weirs on a tank" : PhysicalQuantityType :=
{: value <- 100 ;
interval <- {:lowerBound <- 0; upperBound <- PLUS_INF; :}
:} ;
OBJ A "Surface area of the tank" : Area := {: value <- 200; :} ;
OBJ alfa "Parameter, function of the weir type or width"
: PhysicalQuantityType := {: value <- 1 :};
OBJ beta "Parameter, depends on the weir design"
: PhysicalQuantityType := {: value <- 1 :};
OBJ V_Const "Constant tank volume beneath the lowest point of the weir"
: Volume := {: value <- 1900 :};
};
state <-
{
OBJ Q_Out "Effluent flow rate" : FlowRate ;
};
equations <-
{
// Q_Out is stated variable and declared as
// Q_Out = N*alfa*(V/A^beta)
// for an explanation of these parameters
// see the parameter section above
state.Q_Out = IF (state.V > parameters.V_Const)
THEN
parameters.N * parameters.alfa
* pow((state.V - parameters.V_Const)/parameters.A, parameters.beta)
ELSE 0;
// The total volume is the sum of the volumes of each
// of the components. The volume of each component
// is determined by multiplying its mass by its
// specific volume.
state.V = SUMOVER Comp_Index IN {1 .. NrOfComponents}:
(parameters.WWTPSpecificVolume[Comp_Index]*state.M[Comp_Index]);
// The concentration of each component is just the mass
// of that component divided by the total volume
{FOREACH Comp_Index IN {1 .. NrOfComponents}:
state.C[Comp_Index] = IF (state.V == 0)
THEN 0
ELSE state.M[Comp_Index]/state.V;
};
{FOREACH Comp_Index IN {1 .. NrOfComponents}:
interface.Outflow[Comp_Index] =
- state.C[Comp_Index] * state.Q_Out ;};
};
:};
// Below is where we start putting user-specific information
// This will later be put in a separate file
// Add the Specific Volume (=1/density) information to the equations
//======================================================================
//===========================WWTPAtomicModelVariablePumpedVolume========
//======================================================================
CLASS WWTPAtomicModelWithPumpedVolume
EXTENDS WWTPAtomicModelWithVolume WITH
{:
interface <-
{
OBJ Inflow (* terminal = "in_1" *) "Inflow" :
InWWTPTerminal := {: causality <- "CIN" :};
OBJ Outflow (* terminal = "out_1" *) "Outflow" :
OutWWTPTerminal := {: causality <- "COUT" :};
};
parameters <-
{
OBJ Q_Pump "Desired effluent flow rate" : FlowRate ;
OBJ V_Max "Maximum volume of the tank" : Volume ;
OBJ V_Min "Minimum volume of the tank" : Volume ;
};
state <-
{
OBJ Q_Out "Actual effluent flow rate" : FlowRate ;
};
equations <-
{
state.V = SUMOVER Comp_Index IN {1 .. NrOfComponents}:
(parameters.WWTPSpecificVolume[Comp_Index]*state.M[Comp_Index]);
// The concentration of each component is just the mass
// of that component divided by the total volume
{FOREACH Comp_Index IN {1 .. NrOfComponents}:
state.C[Comp_Index] = IF (state.V == 0)
THEN 0
ELSE state.M[Comp_Index]/state.V;
};
state.Q_Out = IF (state.V < parameters.V_Min &&
parameters.Q_Pump > state.Q_In)
THEN state.Q_In
ELSE
IF (state.V < parameters.V_Max)
THEN parameters.Q_Pump
ELSE
IF (state.Q_In < parameters.Q_Pump)
THEN parameters.Q_Pump
ELSE state.Q_In ;
{FOREACH Comp_Index IN {1 .. NrOfComponents}:
interface.Outflow[Comp_Index] =
- state.C[Comp_Index] * state.Q_Out ;};
};
:};
//====================================================================================
//=========================WWTPAtomicModelWithFixedVolume=============================
//====================================================================================
CLASS WWTPAtomicModelWithFixedVolume EXTENDS WWTPAtomicModelWithVolume WITH
{:
interface <-
{
OBJ Inflow (* terminal = "in_1" *) "Inflow" :
InWWTPTerminal := {: causality <- "CIN" :};
OBJ Outflow (* terminal = "out_1" *)"Outflow" :
OutWWTPTerminal := {: causality <- "COUT" :};
};
state <-
{
// OBJ Q_Out "Effluent flow rate" : FlowRate ;
};
equations <-
{
// because of a fixed volume ...
// state.Q_Out = state.Q_In; anyway
// so skip it
// The total volume is the sum of the volumes of each
// of the components. The volume of each component
// is determined by multiplying its mass by its
// specific volume.
state.V = SUMOVER Comp_Index IN {1 .. NrOfComponents}:
(parameters.WWTPSpecificVolume[Comp_Index]*state.M[Comp_Index]);
// The concentration of each component is just the mass
// of that component divided by the total volume
{FOREACH Comp_Index IN {1 .. NrOfComponents}:
state.C[Comp_Index] = IF (state.V == 0)
THEN 0
ELSE state.M[Comp_Index]/state.V;
};
{FOREACH Comp_Index IN {1 .. NrOfComponents}:
interface.Outflow[Comp_Index] =
- state.C[Comp_Index] * state.Q_In ;};
};
:};
// Below is where we start putting user-specific information
// This will later be put in a separate file
// Add the Specific Volume (=1/density) information to the equations
//=========================================================================
//==================End of WWTPAtomicModel hierarchy=======================
//=========================================================================
//
// End of WWTPAtomicModel hierarchy
//
#endif // ELAFISH_BASE