1 |
(* ASCEND modelling environment |
2 |
Copyright (C) 1998, 2007 Carnegie Mellon University |
3 |
|
4 |
This program is free software; you can redistribute it and/or modify |
5 |
it under the terms of the GNU General Public License as published by |
6 |
the Free Software Foundation; either version 2, or (at your option) |
7 |
any later version. |
8 |
|
9 |
This program is distributed in the hope that it will be useful, |
10 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 |
GNU General Public License for more details. |
13 |
|
14 |
You should have received a copy of the GNU General Public License |
15 |
along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 |
*) |
17 |
PROVIDE "basemodel.a4l"; |
18 |
(* |
19 |
basemodel.a4l, by Benjamin A. Allan 03/98 - Original Code |
20 |
|
21 |
Basic definitions cmu libraries and standard methods. |
22 |
This file is necessary for all other CMU authored ASCEND models to work |
23 |
in ASCEND IV. |
24 |
*) |
25 |
|
26 |
MODEL catch_Word_model (* Bill Gates sacrificial goat *); |
27 |
(* This MODEL does nothing. |
28 |
* Normally catch_Word_model just gets parsed and ignored. |
29 |
* |
30 |
* If the user has tried to read a Microsoft Word binary file, Tcl file, |
31 |
* or some other piece of junk as if it were an ASCEND MODEL |
32 |
* source file, then catch_Word_model will die on an unknown |
33 |
* syntax error. |
34 |
* While catch_Word_model is dying the parser returns a good |
35 |
* starting condition. |
36 |
* |
37 |
* Here is the message of recovery when this MODEL fails: |
38 |
Asc-Error: Model definition "catch_Word_model" abandoned due to syntax errors. |
39 |
Asc-Error: Rejected "catch_Word_model" at line basemodel.a4l:62. |
40 |
|
41 |
@TODO document how this works |
42 |
*) |
43 |
END catch_Word_model; |
44 |
|
45 |
(* First define the standard methods, or stand-ins which will tell |
46 |
* us when a standard method has not been written. |
47 |
*) |
48 |
ADD METHODS IN DEFINITION MODEL; |
49 |
|
50 |
METHOD ClearAll; |
51 |
|
52 |
NOTES 'purpose' SELF { |
53 |
This method finds anything that is a solver_var and changes |
54 |
the .fixed flag on the var to FALSE. |
55 |
|
56 |
This method does not change .included flags on relations |
57 |
or return boolean, integer, or symbol variables to a |
58 |
default value. |
59 |
} END NOTES; |
60 |
|
61 |
EXTERNAL asc_free_all_variables(SELF); |
62 |
END ClearAll; |
63 |
|
64 |
(* |
65 |
* Geniuses make more mistakes than anyone else -- because they |
66 |
* try more things that anyone else. Part (perhaps a very large |
67 |
* part) of what makes a genius different from the rest of |
68 |
* humanity is that they quickly recognize their own mistakes |
69 |
* and move on to try something else before anyone notices |
70 |
* they screwed up! Solving a problem as far and as fast as you |
71 |
* can, then going back to criticize every aspect of the solution |
72 |
* with an eye to improving it is how you usually discover right answers. |
73 |
* |
74 |
* The authors of ASCEND (geniuses or not we'll |
75 |
* leave to our users to decide) have found that it is |
76 |
* best to do things such as writing mathematical MODELs and |
77 |
* writing mathematical modeling software in ways which |
78 |
* makes our mistakes (or your mistakes) very easy to detect. |
79 |
* |
80 |
* Below we describe a methodology (pun intended) which can |
81 |
* help make anyone who can solve a quadratic equation |
82 |
* a mathematical modeling expert. This methodology helps |
83 |
* you to avoid screwing up and to find out about it when you have. |
84 |
* |
85 |
* The ASCEND system will not force you to write standard |
86 |
* methods in your models. :-( METHODs of the sort we advocate |
87 |
* here make your MODELs much easier to use and |
88 |
* much more reliable. They pay off in the short run as well |
89 |
* as the long run. These are _guidelines_, not _laws_: real |
90 |
* genius requires knowing when to color outside the lines. :-) |
91 |
* |
92 |
* If you do not write the standard methods, your MODEL will |
93 |
* inherit the ones given here. The "ClearAll" and "reset" |
94 |
* methods here will work for you if you followed the guidelines. |
95 |
* The other methods contain STOP statements which will warn you |
96 |
* that you have skipped something important, should you accidentally |
97 |
* end up calling one of them. |
98 |
* |
99 |
* The following methods should be redefined by each |
100 |
* reusable library MODEL that REFINES this root MODEL. |
101 |
* Models that do not supply proper versions of these |
102 |
* (and possibly other) methods are very hard to reuse. |
103 |
* |
104 |
* The premise of this method design is that we can |
105 |
* write the _self methods incrementally, building on the |
106 |
* already tested methods of previous MODEL parts we are |
107 |
* reusing. In this way we never have to write a single huge method |
108 |
* that directly checks 100s of variables in a hierarchy. |
109 |
* |
110 |
* The _all methods are methods which simply "top off" the |
111 |
* _self methods. With an _all method, you can treat |
112 |
* just a part of a larger simulation already built |
113 |
* as a self-contained simulation. |
114 |
* |
115 |
*) |
116 |
|
117 |
(* |
118 |
* Usually discovery of the information you need to write the methods |
119 |
* proceeds in the order that they appear below: |
120 |
* check, default, specify, bound, scale. |
121 |
*) |
122 |
|
123 |
METHOD check_self; |
124 |
NOTES 'purpose' SELF { |
125 |
This method should be written first, though it is run |
126 |
last. Just like they taught you in elementary school, |
127 |
always check your work. Start by defining criteria for a |
128 |
successful solution that will not be included in the |
129 |
equations solved and then computing those in this method. |
130 |
As you develop your MODEL, you should expect to revise the |
131 |
check method from time to time, if you are learning |
132 |
anything about the MODEL. We frequently change our |
133 |
definition of success. |
134 |
|
135 |
When a mathematical MODEL is solved, the assumptions that |
136 |
went into writing (deriving) the equations should be |
137 |
checked. Usually there are redundant equations available |
138 |
(more than one way to state the physical MODEL |
139 |
mathematically). These should be used to check the |
140 |
particularly tricky bits of the MODEL. |
141 |
|
142 |
Check that the physical or intuitive (qualitative) |
143 |
relationships among variables ch you expect to hold are |
144 |
TRUE, especially if you have not written such relationships |
145 |
in terms of inequalities in the MODEL equations. |
146 |
|
147 |
In some models, checking the variable values against |
148 |
absolute physical limits (temperature > 0{K} and |
149 |
temperature < Tcritical for example) may be all that is |
150 |
necessary or possible. Do not check variable values against |
151 |
their .lower_bound or .upper_bound, as any decent algebraic |
152 |
solver or modeling system will do this for you. |
153 |
|
154 |
If a check fails, use a STOP or ERROR statement to notify |
155 |
yourself (or you MODEL using customer) that the solution |
156 |
may be bogus. |
157 |
|
158 |
Currently only STOP is implemented. |
159 |
STOP raises an error signal and issues an error message; |
160 |
STOP normally also stops further execution of the method |
161 |
and returns control to a higher level, though there are |
162 |
interactive tools to force method execution to continue. |
163 |
STOP does not crash the ASCEND system. |
164 |
|
165 |
} END NOTES; |
166 |
|
167 |
(* STOP {Error! Standard method "check_self" called but not written in MODEL.}; *) |
168 |
|
169 |
END check_self; |
170 |
|
171 |
METHOD check_all; |
172 |
|
173 |
NOTES 'purpose' SELF { |
174 |
When solving only a part of a simulation, it is necessary to check |
175 |
the models and variables passed into the part as well as the |
176 |
locally defined parts and variables. This method should check |
177 |
all the received models and variables, then check the local |
178 |
stuff. |
179 |
} END NOTES; |
180 |
|
181 |
(* STOP {Error! Standard method "check_all" called but not written in MODEL.}; *) |
182 |
RUN check_self; (* intentionally _second_ *) |
183 |
|
184 |
END check_all; |
185 |
|
186 |
METHOD defaults; |
187 |
(* |
188 |
* This is a kluge for interfaces that still think of |
189 |
* 'defaults' as the standard method. |
190 |
*) |
191 |
RUN default_self; |
192 |
STOP {GUI (or somebody) called non-standard method defaults. Call forwarded to default_self before stopping here.}; |
193 |
END defaults; |
194 |
|
195 |
METHOD on_load; |
196 |
NOTES 'purpose' SELF { |
197 |
This method adds improved ability to perform stuff when a model is first loaded. |
198 |
By default, just 'default_self' will be run (this was the previous behaviour). |
199 |
Any model that has an on_load method can override this behaviour however. |
200 |
Note that this behaviour applies only in the C++/python interface at this stage. |
201 |
} END NOTES; |
202 |
RUN default_all; |
203 |
END on_load; |
204 |
|
205 |
METHOD default; |
206 |
NOTES 'purpose' SELF { |
207 |
This method exists for the purpose ofOVERRIDING atom defaults in the local |
208 |
MODEL. Hopefully this approach can replace the current practise of writing |
209 |
'default_self' methods for most MODELs. It should be superior, since using |
210 |
'default' instead of 'default_self' will always result in ALL variables in a |
211 |
model being reset to default values, rather than only those explicitly stated |
212 |
by the modeller. |
213 |
} END NOTES; |
214 |
(*STOP {it works!};*) |
215 |
(* nothing here *) |
216 |
END default; |
217 |
|
218 |
METHOD default_self; |
219 |
NOTES 'purpose' SELF { |
220 |
This method should set default values for any variables |
221 |
declared locally (IS_A) to the MODEL. It should run |
222 |
default_self on _all_ the models that are declared locally |
223 |
(with IS_A) in the MODEL also. If the atoms you use to |
224 |
define your variables have a suitable default already, then |
225 |
you do not need to assign them a default in this method. |
226 |
|
227 |
This method should not run any methods on MODEL parts that |
228 |
come via WILL_BE in the definition's parameter list. This |
229 |
method also should not change the values of variables that |
230 |
are passed in through the parameter list. |
231 |
|
232 |
Sometimes there will be nothing for this method to do. |
233 |
Define it anyway, leaving it empty. |
234 |
|
235 |
When a top-level simulation is built by the compiler, this |
236 |
method will be run at the end of compilation by the |
237 |
compiler. See notes in on_load method for new behaviour in |
238 |
the PyGTK GUI. |
239 |
} END NOTES; |
240 |
EXTERNAL defaultself_visit_childatoms(SELF); |
241 |
EXTERNAL defaultself_visit_submodels(SELF); (* overwrite ATOM defaults explicit nested code if needed *) |
242 |
RUN default; (* local overrides *) |
243 |
END default_self; |
244 |
|
245 |
METHOD default_all; |
246 |
NOTES 'purpose' SELF { |
247 |
This method assumes that the arguments to the MODEL |
248 |
instance have not been properly initialized, as is |
249 |
frequently the case in one-off modeling efforts. This |
250 |
method should run the default_self method on each of the |
251 |
parts received through the parameter list and should give |
252 |
appropriate default values to any variables received |
253 |
through the parameter list. After these have been done, it |
254 |
should then call default_self to take care of all locally |
255 |
declared default needs. |
256 |
} END NOTES; |
257 |
(* INITIALISATION OF PARAMETERS IS NOT IMPLEMENTED YET *) |
258 |
RUN default_self; |
259 |
END default_all; |
260 |
|
261 |
METHOD specify; |
262 |
NOTES 'purpose' SELF { |
263 |
* Assuming ClearAll has been run on the MODEL, this method |
264 |
* should get the MODEL to a condition called 'square': |
265 |
* the case where there are as many variables with .fixed == FALSE |
266 |
* as there equations available to compute them. |
267 |
* This is one of the hardest tasks ever invented by mathematicians |
268 |
* if you go about it in the wrong way. We think we know the right way. |
269 |
* |
270 |
* Actually, 'square' is a bit trickier to achieve |
271 |
* than simply counting equations and variables. |
272 |
* Solver, such as QRSlv in ASCEND, may help greatly with the bookkeeping. |
273 |
* |
274 |
The general approach is to: |
275 |
|
276 |
(1) Run "specify" for all the parts (both passed in and locally defined) |
277 |
that are not passed on into other parts. |
278 |
|
279 |
(2) Fix up (by tweaking .fixed flags on variables) any difficulties |
280 |
that arise when parts compete to calculate the same variable. |
281 |
|
282 |
(3) Use the remaining new local variables to take care of any leftover |
283 |
equations among the parts and any new equations written locally. |
284 |
|
285 |
At all steps 1-3 |
286 |
Pay special attention to indexed variables used in |
287 |
indexed equations; frequently you must fix or free N or |
288 |
N-1 variables of a set sized N, if there are N matching equations. |
289 |
In general, if you think you have specify correctly written, change |
290 |
the sizes of all the sets in your MODEL by one and then by two |
291 |
members. If your specify method still works, you are using sets |
292 |
correctly. |
293 |
|
294 |
When writing models that combine parts which do not share |
295 |
very well, or which both try to compute the same variable |
296 |
in different ways, it may even be necessary to write a WHEN |
297 |
statement to selectively TURN OFF the conflicting equations |
298 |
or MODEL fragments. An object or equation USEd in a WHEN |
299 |
statement is turned off by default and becomes a part of |
300 |
the solved MODEL only when the conditions of some CASE |
301 |
which refers to that object are matched. |
302 |
|
303 |
The setting of boolean, integer, and symbol variables which |
304 |
are controlling conditions of WHEN and SWITCH statements |
305 |
should be taken care of in the specify method. |
306 |
|
307 |
There is no 'one perfect "specify"' for all purposes. This |
308 |
routine should merely define a reasonably useful base |
309 |
configuration of the MODEL. |
310 |
|
311 |
Other specify_whatElseYouWant methods can (should) also be |
312 |
written. |
313 |
|
314 |
The name of a method is a communication tool. Please use |
315 |
meaningful names as long as necessary to tell what the |
316 |
method does. Avoid cryptic abbreviations and hyper- |
317 |
specialized jargon known only to you and your three friends |
318 |
when you are naming methods; however, do not shy away from |
319 |
technical terms common to the engineering domain in which |
320 |
you are modeling. |
321 |
|
322 |
} END NOTES; |
323 |
|
324 |
(* STOP {Error! Standard method "specify" called but not written in MODEL.}; *) |
325 |
|
326 |
END specify; |
327 |
|
328 |
METHOD reset; |
329 |
NOTES 'purpose' SELF { |
330 |
This method gets the MODEL to some standard starting state, |
331 |
though not necessarily the most useful starting state for a |
332 |
particular application. In Chem. Eng. terms, this method |
333 |
establishes a base case. |
334 |
|
335 |
There is no 'one perfect "reset"' for all purposes. This |
336 |
routine should merely define a reasonably useful base |
337 |
configuration of the MODEL. |
338 |
|
339 |
Other reset_whatElseYouWant methods can (should) also be |
340 |
written. |
341 |
|
342 |
Normally you do not need to write this method: your models |
343 |
will inherit this one unless you override it (redefine it) |
344 |
in your MODEL. |
345 |
} |
346 |
END NOTES; |
347 |
|
348 |
RUN ClearAll; |
349 |
RUN specify; |
350 |
|
351 |
END reset; |
352 |
|
353 |
METHOD values; |
354 |
END values; |
355 |
|
356 |
METHOD bound_self; |
357 |
NOTES 'purpose' SELF { |
358 |
Much of the art of nonlinear physical modeling is in |
359 |
bounding the solution. |
360 |
|
361 |
This method should update the bounds on _locally_ defined |
362 |
(IS_A) variables and IS_A defined MODEL parts. Updating |
363 |
bounds requires some care. For example, the bounds on |
364 |
fractions frequently don't need updating. |
365 |
|
366 |
A common formula for updating bounds is to define a region |
367 |
around the current value of the variable. A linear region |
368 |
size formula, as an example, would be: |
369 |
|
370 |
v.upper_bound := v + boundwidth * v.nominal; |
371 |
v.lower_bound := v - boundwidth * v.nominal; |
372 |
|
373 |
Care must be taken that such a formula does not move the |
374 |
bounds (particularly lower bounds) out so far as to allow |
375 |
non-physical solutions. Logarithmic bounding regions are |
376 |
also simple to calculate. |
377 |
|
378 |
Here boundwidth IS_A bound_width; |
379 |
boundwidth is a real variable (but not a solver_var) or a |
380 |
value you can use to determine how much "wiggle-room" you |
381 |
want to give a solver. Small powers of 4 and 10 are usually |
382 |
good values of boundwidth. |
383 |
|
384 |
Too small a boundwidth can cut off the portion of number |
385 |
space where the solution is found. Too large a bound width |
386 |
can allow solvers to wander for great distances in |
387 |
uninteresting regions of the number space. |
388 |
|
389 |
This method should not bound variables passed into the |
390 |
MODEL definition or parts passed into the definition. |
391 |
} END NOTES; |
392 |
|
393 |
(* STOP {Error! Standard method "bound_self" called but not written in MODEL.}; *) |
394 |
END bound_self; |
395 |
|
396 |
METHOD bound_all; |
397 |
NOTES 'purpose' SELF { |
398 |
This method should be like bound_self except that it bounds the |
399 |
passed in variables and calls bound_self on the passed in parts. |
400 |
It should then call bound_self. |
401 |
} END NOTES; |
402 |
|
403 |
(* STOP {Error! Standard method "bound_all" called but not written in MODEL.}; *) |
404 |
RUN bound_self; |
405 |
END bound_all; |
406 |
|
407 |
METHOD scale_self; |
408 |
NOTES 'purpose' SELF { |
409 |
Most nonlinear (and many linear) models cannot be solved without |
410 |
proper scaling of the variables. |
411 |
|
412 |
This method should reset the .nominal value on every real |
413 |
variable in need of scaling. It should then call the |
414 |
scale_self method on all the locally defined (IS_A) parts |
415 |
of the MODEL. 0.0 is the worst possible nominal value. A |
416 |
proper nominal is one such that you expect at the solution |
417 |
the quantity |
418 |
|
419 |
abs(variable/(variable.nominal)) |
420 |
|
421 |
to be around 1 (in the range of [0.1..10] or [0.01..100]). |
422 |
|
423 |
Variables (like fractions) bounded such that they cannot be |
424 |
too far away from 1.0 in magnitude probably don't need scaling |
425 |
most of the time if they are also bounded away from 0.0. |
426 |
|
427 |
Some solvers, but not all, will attempt to scale the |
428 |
equations and variables by heuristic matrix-based methods. |
429 |
This works, but inconsistently; user-defined scaling is |
430 |
generaly much superior. |
431 |
|
432 |
ASCEND makes it easy to do. You scale the variables, which |
433 |
can only be done well by knowing something about where the |
434 |
solution is going to be found (by being an engineer, for |
435 |
example.) Then ASCEND can calculate an appropriate |
436 |
equation-scaling by efficient symbolic methods. |
437 |
|
438 |
This method should not change the scaling of models and |
439 |
variables that are received through the parameter list of |
440 |
the MODEL. |
441 |
} END NOTES; |
442 |
|
443 |
(* STOP {Error! Standard method "scale_self" called but not written in MODEL.}; *) |
444 |
END scale_self; |
445 |
|
446 |
METHOD scale_all; |
447 |
NOTES 'purpose' SELF { |
448 |
This method should be like scale_self above except that it also |
449 |
should scale the variables and models received through the |
450 |
parameter list. It should then call scale_self to take care of |
451 |
the local variables and models. |
452 |
} END NOTES; |
453 |
|
454 |
(* STOP {Error! Standard method "scale_all" called but not written in MODEL.}; *) |
455 |
RUN scale_self; |
456 |
END scale_all; |
457 |
END METHODS; |
458 |
|
459 |
MODEL cmumodel(); |
460 |
NOTES |
461 |
'purpose' SELF { |
462 |
This MODEL does nothing except provide a root |
463 |
for a collection of loosely related models. |
464 |
If it happens to reveal a few bugs in the software, |
465 |
and perhaps masks others, well, what me worry? |
466 |
BAA, 8/97. |
467 |
} |
468 |
'methods' SELF { |
469 |
This MODEL also provides a hook to put in candidates for |
470 |
becoming ascBuiltin global methods. Global methods may be |
471 |
overridden by local definitions. |
472 |
BAA, 3/98. |
473 |
} |
474 |
END NOTES; |
475 |
|
476 |
END cmumodel; |
477 |
|
478 |
MODEL testcmumodel(); |
479 |
(* |
480 |
* All CMU test models, of whatever sort should ultimately be |
481 |
* rooted here or be a final refinement of a reusable MODEL. |
482 |
*) |
483 |
METHODS |
484 |
METHOD values; |
485 |
(* |
486 |
* In a final application MODEL, you should record at least one set of |
487 |
* input values (values of the fixed variables and guesses of key |
488 |
* solved-for variables) that leads to a good solution. |
489 |
* Do this so noone need reinvent that set the next time |
490 |
* you use the MODEL or someone picks the MODEL up after you. |
491 |
*) |
492 |
(* STOP {Error! Standard method "values" called but not written in MODEL.}; *) |
493 |
END values; |
494 |
|
495 |
METHOD specify; |
496 |
(* STOP {Error! Standard method "specify" called but not written in test MODEL.}; *) |
497 |
END specify; |
498 |
|
499 |
METHOD ClearAll; |
500 |
EXTERNAL asc_free_all_variables(SELF); |
501 |
END ClearAll; |
502 |
|
503 |
METHOD reset; |
504 |
(* This method gets the MODEL to some standard starting state, |
505 |
* though not necessarily the most useful starting state for |
506 |
* a particular application. In Chem. Eng. terms, this method |
507 |
* establishes a base case. |
508 |
* There is no 'one perfect "reset"' for all purposes. This |
509 |
* routine should merely define a reasonably useful base configuration |
510 |
* of the MODEL. |
511 |
* Other reset_whatElseYouWant methods can (should) also be |
512 |
* written. |
513 |
* |
514 |
* Normally you do not need to write this method: your models |
515 |
* will inherit this one unless you override it (redefine it) |
516 |
* in your MODEL. |
517 |
*) |
518 |
RUN ClearAll; |
519 |
RUN specify; |
520 |
END reset; |
521 |
END testcmumodel; |
522 |
|
523 |
MODEL your_site_models(); |
524 |
(* if you create a library to share with the net which is |
525 |
* not just an end application of Carnegie Mellon models, |
526 |
* please create an empy root MODEL such as this and use |
527 |
* it as the origin of your library in the same way that |
528 |
* we use cmumodel as the origin of our libraries. |
529 |
* Thank you. |
530 |
*) |
531 |
END your_site_models; |