1 |
jgs |
121 |
# $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() |