1 |
# $Id$ |
2 |
from types import StringType |
3 |
|
4 |
class Link: |
5 |
""" """ |
6 |
def __init__(self,object,attribute=None): |
7 |
self.__object=object |
8 |
self.setAttributeName(attribute) |
9 |
|
10 |
def setAttributeName(self,name): |
11 |
if not name==None: |
12 |
if not hasattr(self.__object,name): |
13 |
raise AttributeError("Link: object %s has no attribute %s."%(self.__object,name)) |
14 |
self.__attribute=name |
15 |
|
16 |
def hasAttributeName(self): |
17 |
if self.__attribute==None: |
18 |
return False |
19 |
else: |
20 |
return True |
21 |
|
22 |
def __str__(self): |
23 |
if self.hasAttributeName(): |
24 |
return "reference to %s of %s"%(self.__attribute,self.__object) |
25 |
else: |
26 |
return "reference to object %s"%self.__object |
27 |
|
28 |
def getValue(self,name=None): |
29 |
if not self.hasAttributeName(): |
30 |
out=getattr(self.__object,name) |
31 |
else: |
32 |
out=getattr(self.__object,self.__attribute) |
33 |
if callable(out): |
34 |
return out() |
35 |
else: |
36 |
return out |
37 |
|
38 |
class Model: |
39 |
""" the Model class provides a framework to run a time-dependent simulation. A Model has a set of parameter which |
40 |
may be fixed or altered by the Model itself or other Models over time. |
41 |
|
42 |
The parameters of a models are declared at instantion, e.g. |
43 |
|
44 |
m=Model({"message" : "none" }) |
45 |
|
46 |
creates a Model with parameters p1 and p2 with inital values 1 and 2. Typically a particular model is defined as a subclass of Model: |
47 |
|
48 |
class Messenger(Model): |
49 |
def __init__(self): |
50 |
Model.__init__(self,parameters={"message" : "none" }) |
51 |
|
52 |
m=MyModel() |
53 |
|
54 |
There are various ways how model parameters can be changed: |
55 |
|
56 |
1) use object attributes: |
57 |
|
58 |
m.message="Hello World!" |
59 |
|
60 |
2) use setParamter method |
61 |
|
62 |
|
63 |
m.setParameters(message="Hello World!") |
64 |
|
65 |
3) or dictonaries |
66 |
|
67 |
d={ message : "Hello World!" } |
68 |
m.setParameters(**d) |
69 |
|
70 |
|
71 |
A model executed buy staring the run method of the model: |
72 |
|
73 |
m=Messenger() |
74 |
m.run() |
75 |
|
76 |
The run methods marches through time. It first calls the |
77 |
doInitialization() method of the Model to set up the process. In each time step the doStep() method is called |
78 |
to get from the current to the next time step. The step size is defined by calling the getSafeTimeStepSize() method. |
79 |
The time integration process is terminated when the finalize() methods return true. Final the doFinalization() method |
80 |
is called to finalize the process. To implement a particular model a subclass |
81 |
of the Model class is defined. The subclass overwrites the default methods of Model. |
82 |
|
83 |
The following class defines a messenger printing in the doStep method what ever the current value of its parameter message is: |
84 |
|
85 |
class Messenger(Model): |
86 |
def __init__(self): |
87 |
Model.__init__(self,parameters={"message" : "none" }) |
88 |
|
89 |
def doInitialization(self): |
90 |
print "I start talking now!" |
91 |
|
92 |
def doStep(self,t): |
93 |
print "Message (time %e) : %s "%(t,self.message) |
94 |
|
95 |
def doFinalization(self): |
96 |
print "I have no more to say!" |
97 |
|
98 |
If a instance of the Messenger class is run, it will print the initialization and finalization message only. |
99 |
This is because the default method for finalize() does always returns True and therefore the transition is |
100 |
terminated startcht away. |
101 |
|
102 |
Following example for solving the ODE using a forward euler scheme: |
103 |
|
104 |
u(t=0)=u0 |
105 |
u_t=a*u**2 for all 0<t<=ten |
106 |
|
107 |
exact solution is given by u(t)=1/(1/u0-a*t) |
108 |
|
109 |
class Ode1(Model): |
110 |
def __init__(self,**args): |
111 |
Model.__init__(self,parameters={"tend" : 1., "dt" : 0.0001 ,"a" : 0.1 ,"u" : 1. },name="test",debug=True) |
112 |
|
113 |
def doInitialization(self): |
114 |
self._tn=0 |
115 |
|
116 |
def doStep(self,t): |
117 |
self.u=self.u+(t-self._tn)*self.a*self.u**2 |
118 |
self._tn=t |
119 |
|
120 |
def doFinalization(self): |
121 |
print "all done final error = ",abs(self.u-1./(1./3.-self.a*self._tn)) |
122 |
|
123 |
def getSafeTimeStepSize(self): |
124 |
return self.dt |
125 |
|
126 |
def finalize(self): |
127 |
return self._tn>=self.tend |
128 |
|
129 |
In some cases at a given time step an iteration process has to be performed to get the state of the Model for the next time step. ` |
130 |
In this case the doStep() method is replaced by a sequance of methods which implements this iterative process. |
131 |
The method then will control the iteration process by initializing the iteration through calling the |
132 |
doIterationInitialization() method. The iteration is preformed by calling the doIterationStep() method until |
133 |
the terminate() method returns True. The doIterationFinalization() method is called to end the iteration. |
134 |
For a particular model these methods have to overwritten by a suitable subclass without touching the doStep() method. |
135 |
|
136 |
following example is a modification of the example above. Here an implicit euler scheme is used. in each time step the problem |
137 |
|
138 |
0= u_{n+1}-u_{n}+a*dt*u_{n+1}**2 |
139 |
|
140 |
has to be solved for u_{n+1}. The Newton scheme is used to solve this non-linear problem. |
141 |
|
142 |
|
143 |
class Ode2(Model): |
144 |
|
145 |
def __init__(self,**args): |
146 |
Model.__init__(self,{"tend" : 1., "dt" : 0.1 ,"a" : 10. ,"u" : 1. , "tol " : 1.e-8},"test","bla",None,True) |
147 |
|
148 |
def doInitialization(self): |
149 |
self.__tn=0 |
150 |
|
151 |
def doIterationInitialization(self,t): |
152 |
self.__iter=0 |
153 |
self.u_last=self.u |
154 |
self.current_dt=t-self.tn |
155 |
self.__tn=t |
156 |
|
157 |
def doIterationStep(self): |
158 |
self.__iter+=1 |
159 |
self.u_old=self.u |
160 |
self.u=(self.current_dt*self.a*self.u**2-self.u_last)/(2*self.current_dt*self.a*self.u-1.) |
161 |
|
162 |
def terminate(self): |
163 |
return abs(self.u_old-self.u)<self.tol*abs(self.u) |
164 |
|
165 |
def doIterationFinalization(self) |
166 |
print "all done" |
167 |
|
168 |
def getSafeTimeStepSize(self): |
169 |
return self.dt |
170 |
|
171 |
def finalize(self): |
172 |
return self.__tn>self.tend |
173 |
|
174 |
A model can be composed from submodels. Submodels are treated as model parameters. If a model parameter is set or a value of |
175 |
a model parameter is requested, the model will search for this parameter its submodels in the case the model does not have this |
176 |
parameter itself. The order in which the submodels are searched is critical. By default a Model initializes all its submodels, |
177 |
is finalized when all its submodels are finalized and finalizes all its submodels. In the case an iterative process is applied |
178 |
on a particular time step the iteration is initialized for all submodels, then the iteration step is performed for each submodel |
179 |
until all submodels indicate termination. Then the iteration is finalized for all submodels. Finally teh doStop() method for all |
180 |
submethods is called. |
181 |
|
182 |
Here we are creating a model which groups ab instantiation of the Ode2 and the Messenger Model |
183 |
|
184 |
o=Ode2() |
185 |
m=Messenger() |
186 |
om=Model(submodels=[o,m],debug=True) |
187 |
om.dt=0.01 |
188 |
om.u=1. |
189 |
m.message="it's me!" |
190 |
om.run() |
191 |
|
192 |
Notice that dt and u are parameters of class Ode2 and message is a parameter of the Messenger class. The Model formed from these models |
193 |
automatically hand the assignment of new values down to the submodel. om.run() starts this combined model where now the soStep() method |
194 |
of the Messenger object printing the value of its parameter message together with a time stamp is executed in each time step introduced |
195 |
by the Ode2 model. |
196 |
|
197 |
A parameter of a Model can be linked to an attribute of onother object, typically an parameter of another Model object. |
198 |
|
199 |
|
200 |
which is comprised by a set of submodels. |
201 |
The simulation is run through its run method which in the simplest case has the form: |
202 |
|
203 |
s=Model() |
204 |
s.run() |
205 |
|
206 |
The run has an initializion and finalization phase. The latter is called if all submodels are to be finalized. The |
207 |
simulation is processing in time through calling the stepForward methods which updates the observables of each submodel. |
208 |
A time steps size which is save for all submodel is choosen. |
209 |
|
210 |
At given time step an iterative process may be performed to make sure that all observables are consistent across all submodels. |
211 |
In this case, similar the time dependence, an initialization and finalization of the iteration is performed. |
212 |
|
213 |
A Model has input and output parameters where each input parameter can be constant, time dependent or may depend on an |
214 |
output parameter of another model or the model itself. To create a parameter name of a model and to |
215 |
assign a value to it one can use the statement |
216 |
|
217 |
model.name=object |
218 |
|
219 |
|
220 |
At any time the current value of the parameter name can be obtained by |
221 |
|
222 |
value=model.name |
223 |
|
224 |
If the object that has been assigned to the paramter/attribute name has the attribute/parameter name isself the current value of this |
225 |
attribute of the object is returned (e.g. for model.name=object where object has an attribute name, the statement value=model.name whould assign |
226 |
the value object.name to value.). If the name of the parameters of a model and an object don't match the setParameter method of model can be used. So |
227 |
|
228 |
model.setParameter(name,object,name_for_object) |
229 |
|
230 |
links the parameter name of model with the parameter name_for_object of object. |
231 |
|
232 |
The run method initiates checkpointing (it is not clear how to do this yet) |
233 |
===== |
234 |
|
235 |
""" |
236 |
# step size used in case of an undefined value for the step size |
237 |
UNDEF_DT=1.e300 |
238 |
|
239 |
def __init__(self,submodels=[],parameters={},name="model",description="none",check_pointing=None,debug=False): |
240 |
"""initiates a model from a list of submodels. """ |
241 |
self.setDebug(debug) |
242 |
self.__check_pointing=check_pointing |
243 |
self.__parameters={} |
244 |
self.setName(name) |
245 |
self.setDescription(description) |
246 |
self.declareParameter(**parameters) |
247 |
# get the models defined in parameters: |
248 |
self.__submodels=[] |
249 |
# submodels==None means no submodels used: |
250 |
if submodels==None: |
251 |
pass |
252 |
# no submodel list given means all submodels are used as defined by the parameters dictionary: |
253 |
elif len(submodels)==0: |
254 |
for i in parameters.keys(): |
255 |
if isinstance(parameters[i],Model): self.__submodels.append(i) |
256 |
# submodel list of strings and Models is given, submodels defines the order in which the |
257 |
# submodels are processed. if new models are found in the list they are added to the parameter dictionary. |
258 |
else: |
259 |
c=0 |
260 |
for i in submodels: |
261 |
if isinstance(i,StringType): |
262 |
m=self.getParameter(i) |
263 |
if not isinstance(m,Model): |
264 |
raise ValueError,"submodel %s is not a model."%i |
265 |
else: |
266 |
if not isinstance(i,Model): |
267 |
raise ValueError,"submodel list does contain item which is not a Model class object." |
268 |
m=i |
269 |
i="__submodel%d__"%c |
270 |
self.declareParameter(**{i : m}) |
271 |
c+=1 |
272 |
self.__submodels.append(i) |
273 |
if self.debug(): print "%s: model %s is added as parameter %s."%(self,m,i) |
274 |
if len(self.__submodels)>0 and self.debug(): print "%s: model ordering is %s"%(self,self.__submodels) |
275 |
def setSubmodelOrder(submodels=[]): |
276 |
"""sets a new ordering for submodels""" |
277 |
|
278 |
|
279 |
# |
280 |
# some basic fuctions: |
281 |
# |
282 |
def debugOn(self): |
283 |
"""sets debugging to on""" |
284 |
self.__debug=True |
285 |
def debugOff(self): |
286 |
"""sets debugging to off""" |
287 |
self.__debug=False |
288 |
def debug(self): |
289 |
"""returns True if debug mode is set to on""" |
290 |
return self.__debug |
291 |
def setDebug(self,flag=False): |
292 |
"""sets debugging to flag""" |
293 |
if flag: |
294 |
self.debugOn() |
295 |
else: |
296 |
self.debugOff() |
297 |
def setDebug(self,flag=False): |
298 |
"""sets debugging to flag""" |
299 |
if flag: |
300 |
self.debugOn() |
301 |
else: |
302 |
self.debugOff() |
303 |
# name and description handling |
304 |
def __str__(self): |
305 |
"""returns the name of the model""" |
306 |
return self.getName() |
307 |
|
308 |
def getName(self): |
309 |
"""returns the name of the model""" |
310 |
return self.__name |
311 |
|
312 |
def getFullName(self): |
313 |
"""returns the full name of the model including all the names of the submodels""" |
314 |
out=str(self)+"(" |
315 |
notfirst=False |
316 |
for i in self.__submodels: |
317 |
if notfirst: out=out+"," |
318 |
out=out+i.getFullName() |
319 |
notfirst=True |
320 |
return out+")" |
321 |
|
322 |
def setName(self,name): |
323 |
"""sets the name of the model""" |
324 |
self.__name=name |
325 |
|
326 |
def setDescription(self,description="none"): |
327 |
"""sets new description""" |
328 |
self.__description=description |
329 |
if self.debug(): print "%s: description is set to %s."%(self,description) |
330 |
def getDescription(self): |
331 |
"""returns the description of the model""" |
332 |
return self.__description |
333 |
# |
334 |
# parameter/attribute handling: |
335 |
# |
336 |
def declareParameter(self,**parameters): |
337 |
"""declares a new parameter and its inital value.""" |
338 |
for prm in parameters.keys(): |
339 |
if prm in self.__dict__.keys(): |
340 |
raise ValueError,"object attribute %s of %s cannot be used as a model parameter."%(prm,self) |
341 |
self.__parameters[prm]=parameters[prm] |
342 |
if self.debug(): print "%s: parameter %s has been declared."%(self,prm) |
343 |
|
344 |
|
345 |
|
346 |
def showParameters(self): |
347 |
"""returns a descrition of the parameters""" |
348 |
out="" |
349 |
notfirst=False |
350 |
for i in self.__parameters: |
351 |
if notfirst: out=out+"," |
352 |
notfirst=True |
353 |
out="%s%s=%s"%(out,i,self.__parameters[i]) |
354 |
return out |
355 |
|
356 |
|
357 |
def deleteParameter(self,name): |
358 |
"""removes parameter name from the model""" |
359 |
raise IllegalParameterError("Cannot delete parameter %s."%name) |
360 |
|
361 |
def getParameter(self,name): |
362 |
"""returns the value of parameter name. If the parameter is not declared in self, the submodels are searched. |
363 |
if the parameter is a Link, the current value of the obejective is returned.""" |
364 |
if self.__parameters.has_key(name): |
365 |
if isinstance(self.__parameters[name],Link): |
366 |
out=self.__parameters[name].getValue(name) |
367 |
else: |
368 |
out=self.__parameters[name] |
369 |
else: |
370 |
out=None |
371 |
for i in self.__submodels: |
372 |
try: |
373 |
out=self.__parameters[i].getParameter(name) |
374 |
except IllegalParameterError: |
375 |
pass |
376 |
if out==None: raise IllegalParameterError("Cannot find parameter %s."%name) |
377 |
return out |
378 |
|
379 |
def setParameter(self,**parameters): |
380 |
"""sets parameter name to value. If the initial value for the parameter is a Model, the new value has to be a Model.""" |
381 |
for name in parameters.keys(): |
382 |
if self.__parameters.has_key(name): |
383 |
if not isinstance(parameters[name],Model) and isinstance(self.__parameters[name],Model): |
384 |
raise ValueError,"%s: parameter %s can assigned to a Model object only."%(self,name) |
385 |
if isinstance(parameters[name],Model) and not isinstance(self.__parameters[name],Model): |
386 |
raise ValueError,"%s: parameter %s is not declared as a Model."%(self,name) |
387 |
self.__parameters[name]=parameters[name] |
388 |
if isinstance(self.__parameters[name],Link): |
389 |
if not self.__parameters[name].hasAttributeName(): self.__parameters[name].setAttributeName(name) |
390 |
if self.debug(): print "%s: parameter %s has now value %s"%(self,name,self.__parameters[name]) |
391 |
else: |
392 |
set=False |
393 |
for i in self.__submodels: |
394 |
try: |
395 |
self.__parameters[i].setParameter(**{name : parameters[name]}) |
396 |
set=True |
397 |
except IllegalParameterError: |
398 |
pass |
399 |
if not set: raise IllegalParameterError("%s: Attempt to set undeclared parameter %s."%(self,name)) |
400 |
|
401 |
def hasParameter(self,name): |
402 |
"""returns True if self or one of the submodels has parameter name""" |
403 |
if self.__parameters.has_key(name): |
404 |
out=True |
405 |
else: |
406 |
out=False |
407 |
for i in self.__submodels: out= out or self.__parameters[i].hasParameter(name) |
408 |
return out |
409 |
|
410 |
def checkParameter(self,name): |
411 |
"""checks if self has the parameter name. Otherewise ParameterError is thrown.""" |
412 |
if not self.hasParameter(name): |
413 |
raise ParameterError("%s has no parameter %s."%(str(self),name)) |
414 |
|
415 |
def __getattr__(self,name): |
416 |
"""returns the value for attribute name. If name is in the Link list, the corresponding attribute is returned.""" |
417 |
if self.__dict__.has_key(name): |
418 |
return self.__dict__[name] |
419 |
elif self.__dict__.has_key("_Model__parameters") and self.__dict__.has_key("_Model__submodels"): |
420 |
return self.getParameter(name) |
421 |
else: |
422 |
raise AttributeError,"No attribute %s."%name |
423 |
|
424 |
def __setattr__(self,name,value): |
425 |
"""returns the value for attribute name.""" |
426 |
if self.__dict__.has_key("_Model__parameters") and self.__dict__.has_key("_Model__submodels"): |
427 |
if self.hasParameter(name): |
428 |
self.setParameter(**{ name : value }) |
429 |
else: |
430 |
self.__dict__[name]=value |
431 |
else: |
432 |
self.__dict__[name]=value |
433 |
|
434 |
def __delattr__(self,name): |
435 |
"""removes the attribute name.""" |
436 |
if self.__dict__.has_key(name): |
437 |
del self.__dict__[name] |
438 |
elif self.__dict__.has_key("_Model__parameters"): |
439 |
self.deleteParameter(name) |
440 |
else: |
441 |
raise AttributeError,"No attribute %s."%name |
442 |
|
443 |
# |
444 |
# submodel handeling: |
445 |
# |
446 |
def doInitializationOfSubmodels(self): |
447 |
"""initializes the time stepping for all submodels.""" |
448 |
for i in self.__submodels: self.getParameter(i).doInitialization() |
449 |
|
450 |
def getSafeTimeStepSizeFromSubmodels(self): |
451 |
"""returns a time step size which can savely be used by all submodels. To avoid a big increase in the step size, |
452 |
the new step size is restricted to the double of the precious step size.""" |
453 |
out=None |
454 |
for i in self.__submodels: |
455 |
dt=self.getParameter(i).getSafeTimeStepSize() |
456 |
if not dt==None: |
457 |
if out==None: |
458 |
out=dt |
459 |
else: |
460 |
out=min(out,dt) |
461 |
return out |
462 |
|
463 |
def doStepOfSubmodels(self,t): |
464 |
"""executes the time step for each submodel""" |
465 |
for i in self.__submodels: self.getParameter(i).doStep(t) |
466 |
|
467 |
def finalizeAllSubmodels(self): |
468 |
"""returns True if all submodels can be finalized""" |
469 |
out=True |
470 |
for i in self.__submodels: out = out and self.getParameter(i).finalize() |
471 |
return out |
472 |
|
473 |
def doFinalizationOfSubmodels(self): |
474 |
"""finalalizes the time stepping for each of the submodels.""" |
475 |
for i in self.__submodels: self.getParameter(i).doFinalization() |
476 |
|
477 |
def doIterationInitializationOfSubmodels(self,t): |
478 |
"""initializes the iteration for each of the submodels.""" |
479 |
for i in self.__submodels: self.getParameter(i).doIterationInitialization(t) |
480 |
|
481 |
def doIterationStepOfSubmodels(self): |
482 |
"""executes the iteration step at time step for each submodel""" |
483 |
for i in self.__submodels: self.getParameter(i).doIterationStep() |
484 |
|
485 |
def terminateAllSubmodels(self): |
486 |
"""returns True if all iterations for all submodels are terminated.""" |
487 |
out=True |
488 |
for i in self.__submodels: out = out and self.getParameter(i).terminate() |
489 |
return out |
490 |
|
491 |
def doIterationFinalizationOfSubmodels(self): |
492 |
"""finalalizes the iteration process for each of the submodels.""" |
493 |
for i in self.__submodels: self.getParameter(i).doIterationFinalization() |
494 |
|
495 |
def checkPointSubmodels(self): |
496 |
"""performs check pointing for each submodel""" |
497 |
for i in self.__submodels: self.getParameter(i).checkPoint() |
498 |
|
499 |
# |
500 |
# these methods control the time stepping |
501 |
# |
502 |
def doInitialization(self): |
503 |
"""initializes the time stepping""" |
504 |
self.doInitializationOfSubmodels() |
505 |
|
506 |
def getSafeTimeStepSize(self): |
507 |
"""returns a time step size which can savely be used""" |
508 |
return self.getSafeTimeStepSizeFromSubmodels() |
509 |
|
510 |
def doStep(self,t): |
511 |
"""executes the time step by first iterating over time step t and then step forward""" |
512 |
# run iteration on simulation until terminated: |
513 |
self.doIterationInitialization(t) |
514 |
while not self.terminate(): self.doIterationStep() |
515 |
self.doIterationFinalization() |
516 |
self.doStepOfSubmodels(t) |
517 |
|
518 |
def finalize(self): |
519 |
"""returns True if all submodels are to be finalized""" |
520 |
return self.finalizeAllSubmodels() |
521 |
|
522 |
def doFinalization(self): |
523 |
"""finalizes the time stepping.""" |
524 |
self.doFinalizationOfSubmodels() |
525 |
# |
526 |
# methods deal with iterations: |
527 |
# |
528 |
def doIterationInitialization(self,t): |
529 |
"""initializes the iteration on a time step""" |
530 |
self.__iter=0 |
531 |
if self.debug(): print "%s: iteration starts"%self |
532 |
self.doIterationInitializationOfSubmodels(t) |
533 |
|
534 |
def doIterationStep(self): |
535 |
"""executes the iteration step""" |
536 |
self.__iter+=1 |
537 |
if self.debug(): print "%s: iteration step %d"%(self,self.__iter) |
538 |
try: |
539 |
self.doIterationStepOfSubmodels() |
540 |
except IterationDivergenceError,e: |
541 |
raise IterationDivergenceError("divergence at time step %s in iteration step %s by reason: \n%s."%(self.__n,self.__iter,e.value)) |
542 |
|
543 |
def terminate(self): |
544 |
"""returns True if time steping is terminated""" |
545 |
return self.terminateAllSubmodels() |
546 |
|
547 |
def doIterationFinalization(self): |
548 |
"""finalalizes the iteration process.""" |
549 |
self.doIterationFinalizationOfSubmodels() |
550 |
if self.debug(): print "%s: iteration finalized after %s step"%(self,self.__iter) |
551 |
# |
552 |
# sum other method: |
553 |
# |
554 |
def checkPoint(self): |
555 |
"""performs check pointing for each submodel""" |
556 |
if not self.__check_pointing==None: |
557 |
if self.__n%self.__check_pointing==0: self.checkPointsSubmodels() |
558 |
|
559 |
def run(self): |
560 |
"""After check_pointing time steps the model will start to create checkpoint files for each of the submodels""" |
561 |
self.__tn=0. |
562 |
self.__n=0 |
563 |
self.__dt=None |
564 |
self.doInitialization() |
565 |
while not self.finalize(): |
566 |
self.__n+=1 |
567 |
self.__dt=self.getSafeTimeStepSize() |
568 |
if self.__dt==None: self.__dt=self.UNDEF_DT |
569 |
if self.debug(): print "%s: %d. time step %e (step size %e.)"%(self,self.__n,self.__tn+self.__dt,self.__dt) |
570 |
endoftimestep=False |
571 |
while not endoftimestep: |
572 |
endoftimestep=True |
573 |
try: |
574 |
self.doStep(self.__tn+self.__dt) |
575 |
except FailedTimeStepError: |
576 |
self.__dt=self.getSafeTimeStepSize() |
577 |
if self.__dt==None: self.__dt=self.UNDEF_DT |
578 |
endoftimestep=False |
579 |
if self.debug(): print "%s: time step is repeated with new step size %e."%(self,self.__dt) |
580 |
except IterationDivergenceError: |
581 |
self.__dt*=0.5 |
582 |
endoftimestep=False |
583 |
if self.debug(): print "%s: iteration failes. time step is repeated with new step size %e."%(self,self.__dt) |
584 |
self.checkPoint() |
585 |
self.__tn+=self.__dt |
586 |
self.doFinalization() |
587 |
|
588 |
class IterationDivergenceError(Exception): |
589 |
"""excpetion which should be thrown if an iteration at a time step fails""" |
590 |
pass |
591 |
|
592 |
class FailedTimeStepError(Exception): |
593 |
"""excpetion which should be thrown if the time step fails because of a step size that have been choosen to be to large""" |
594 |
pass |
595 |
|
596 |
class IllegalParameterError(Exception): |
597 |
"""excpetion which is thrown if model has not the desired parameter""" |
598 |
pass |
599 |
|
600 |
|
601 |
if __name__=="__main__": |
602 |
class Messenger(Model): |
603 |
def __init__(self): |
604 |
Model.__init__(self,parameters={"message" : "none" },name="messenger") |
605 |
|
606 |
def doInitialization(self): |
607 |
print "I start talking now!" |
608 |
|
609 |
def doStep(self,t): |
610 |
print "Message (time %e) : %s "%(t,self.message) |
611 |
|
612 |
def doFinalization(self): |
613 |
print "I have no more to say!" |
614 |
|
615 |
# explicit scheme |
616 |
class Ode1(Model): |
617 |
def __init__(self,**args): |
618 |
Model.__init__(self,parameters={"tend" : 1., "dt" : 0.0001 ,"a" : 0.1 ,"u" : 1. , "message" : "none" },name="Ode1",debug=True) |
619 |
|
620 |
def doInitialization(self): |
621 |
self._tn=0 |
622 |
|
623 |
def doStep(self,t): |
624 |
self.u=self.u+(t-self._tn)*self.a*self.u**2 |
625 |
self._tn=t |
626 |
|
627 |
def doFinalization(self): |
628 |
self.message="current error = %e"%abs(self.u-1./(1./3.-self.a*self._tn)) |
629 |
print self.message |
630 |
|
631 |
def getSafeTimeStepSize(self): |
632 |
return self.dt |
633 |
|
634 |
def finalize(self): |
635 |
return self._tn>=self.tend |
636 |
# explicit scheme |
637 |
class Ode2(Model): |
638 |
|
639 |
def __init__(self,**args): |
640 |
Model.__init__(self,parameters={"tend" : 1., "dt" : 0.0001 ,"a" : 0.1 ,"u" : 10000. },name="Ode2",debug=True) |
641 |
self.declareParameter(tol=1.e-8,message="none") |
642 |
|
643 |
|
644 |
def doInitialization(self): |
645 |
self._tn=0 |
646 |
self._iter=0 |
647 |
|
648 |
def doIterationInitialization(self,t): |
649 |
self._iter=0 |
650 |
self._u_last=self.u |
651 |
self._dt=t-self._tn |
652 |
self._tn=t |
653 |
|
654 |
def doIterationStep(self): |
655 |
self._iter+=1 |
656 |
self._u_old=self.u |
657 |
self.u=(self._dt*self.a*self.u**2-self._u_last)/(2*self._dt*self.a*self.u-1.) |
658 |
|
659 |
def terminate(self): |
660 |
if self._iter<1: |
661 |
return False |
662 |
else: |
663 |
return abs(self._u_old-self.u)<self.tol*abs(self.u) |
664 |
|
665 |
def doIterationFinalization(self): |
666 |
self.message="current error = %e"%abs(self.u-1./(1-self.a*self._tn)) |
667 |
print self.message |
668 |
|
669 |
def getSafeTimeStepSize(self): |
670 |
return self.dt |
671 |
|
672 |
def finalize(self): |
673 |
return self._tn>=self.tend |
674 |
|
675 |
# a simple model with paramemter tend, dt, p1, p2, and p3 |
676 |
class Test1(Model): |
677 |
|
678 |
def __init__(self,**args): |
679 |
Model.__init__(self,{"tend" : 1., "dt" : 0.1 ,"p1" : 0 ,"p2" : 0 ,"p3" : 0 },"test","bla",None,True) |
680 |
self.setParameters(args) |
681 |
|
682 |
def doInitialization(self): |
683 |
self.__tn=0 |
684 |
self.__n=0 |
685 |
|
686 |
def doStep(self,t): |
687 |
self.p3=self.p1+t*self.p2 |
688 |
self.__tn=t |
689 |
print "test1 set the value out1 to ",self.p3 |
690 |
|
691 |
def doFinalization(self): |
692 |
pass |
693 |
|
694 |
def getSafeTimeStepSize(self): |
695 |
return self.dt |
696 |
|
697 |
def finalize(self): |
698 |
return self._tn>self.tend |
699 |
|
700 |
|
701 |
class Test2(Model): |
702 |
|
703 |
def __init__(self): |
704 |
Model.__init__(self,{"q1": None},"test2","",None,True) |
705 |
|
706 |
|
707 |
def doInitialization(self): |
708 |
print "the whole thing starts" |
709 |
|
710 |
def doStep(self,t): |
711 |
print "test2 things that out1 is now ",self.out1 |
712 |
|
713 |
def doFinalization(self): |
714 |
print "all done" |
715 |
|
716 |
def finalize(self): |
717 |
return True |
718 |
|
719 |
class Test12(Model): |
720 |
"""model build from two models in a transperent way""" |
721 |
def __init__(self): |
722 |
Model.__init__(self,{"sm1": None, a : 0, "sm2": None},"test2","",None,True) |
723 |
self.setExecutionOrder(["sm2","sm1"]) |
724 |
|
725 |
# test messenger |
726 |
m=Messenger() |
727 |
m.run() |
728 |
# ode1 |
729 |
o=Ode1() |
730 |
o.dt=0.001 |
731 |
o.u=3. |
732 |
o.run() |
733 |
# ode1 |
734 |
o=Ode2() |
735 |
o.dt=0.01 |
736 |
o.a=0.1 |
737 |
o.u=1. |
738 |
o.run() |
739 |
# and they are linked together: |
740 |
o=Ode2() |
741 |
m=Messenger() |
742 |
om=Model(submodels=[o,m],debug=True) |
743 |
om.dt=0.01 |
744 |
om.u=1. |
745 |
m.message=Link(o) |
746 |
om.run() |
747 |
print om.showParameters() |
748 |
1/0 |
749 |
|
750 |
t=Test1() |
751 |
t.tend=1. |
752 |
t.dt=0.25 |
753 |
t.in1=1. |
754 |
t.in2=3. |
755 |
t.run() |
756 |
# and a coupled problem: |
757 |
t2=Test2() |
758 |
t2.out1=Link(t) |
759 |
Model([t,t2],debug=True).run() |