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