/[escript]/trunk/escript/py_src/modelframe.py
ViewVC logotype

Contents of /trunk/escript/py_src/modelframe.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 614 - (show annotations)
Wed Mar 22 01:37:07 2006 UTC (13 years ago) by elspeth
File MIME type: text/x-python
File size: 28884 byte(s)
Corrected spelling of 'license' in url so that the link actually points to the license.

1 # $Id$
2
3 __copyright__=""" Copyright (c) 2006 by ACcESS MNRF
4 http://www.access.edu.au
5 Primary Business: Queensland, Australia"""
6 __license__="""Licensed under the Open Software License version 3.0
7 http://www.opensource.org/licenses/osl-3.0.php"""
8
9 from types import StringType,IntType,FloatType,BooleanType,ListType,DictType
10 from sys import stdout
11 import itertools
12 # import modellib temporarily removed!!!
13
14 # import the 'set' module if it's not defined (python2.3/2.4 difference)
15 try:
16 set
17 except NameError:
18 from sets import Set as set
19
20 from xml.dom import minidom
21
22 def dataNode(document, tagName, data):
23 """
24 C{dataNode}s are the building blocks of the xml documents constructed in
25 this module.
26
27 @param document: the current xml document
28 @param tagName: the associated xml tag
29 @param data: the values in the tag
30 """
31 t = document.createTextNode(str(data))
32 n = document.createElement(tagName)
33 n.appendChild(t)
34 return n
35
36 def esysDoc():
37 """
38 Global method for creating an instance of an EsysXML document.
39 """
40 doc = minidom.Document()
41 esys = doc.createElement('ESys')
42 doc.appendChild(esys)
43 return doc, esys
44
45 def all(seq):
46 for x in seq:
47 if not x:
48 return False
49 return True
50
51 def any(seq):
52 for x in seq:
53 if x:
54 return True
55 return False
56
57 LinkableObjectRegistry = {}
58
59 def registerLinkableObject(obj_id, o):
60 LinkableObjectRegistry[obj_id] = o
61
62 LinkRegistry = []
63
64 def registerLink(obj_id, l):
65 LinkRegistry.append((obj_id,l))
66
67 def parse(xml):
68 """
69 Generic parse method for EsysXML. Without this, Links don't work.
70 """
71 global LinkRegistry, LinkableObjectRegistry
72 LinkRegistry = []
73 LinkableObjectRegistry = {}
74
75 doc = minidom.parseString(xml)
76 sim = getComponent(doc.firstChild)
77 for obj_id, link in LinkRegistry:
78 link.target = LinkableObjectRegistry[obj_id]
79
80 return sim
81
82 def importName(modulename, name):
83 """ Import a named object from a module in the context of this function,
84 which means you should use fully qualified module paths.
85
86 Return None on failure.
87
88 This function from: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52241
89 """
90 module = __import__(modulename, globals(), locals(), [name])
91
92 try:
93 return vars(module)[name]
94 except KeyError:
95 raise ImportError("Could not import %s from %s" % (name, modulename))
96
97 def getComponent(doc):
98 """
99 Used to get components of Simualtions, Models.
100 """
101 for node in doc.childNodes:
102
103 if isinstance(node, minidom.Element):
104 if node.tagName == 'Simulation':
105 if node.getAttribute("type") == 'Simulation':
106 return Simulation.fromDom(node)
107 if node.tagName == 'Model':
108 if (node.getAttribute("module")):
109 model_module = node.getAttribute("module")
110 model_type = node.getAttribute("type")
111 return importName(model_module, model_type).fromDom(node)
112 else:
113 model_type = node.getAttribute("type")
114 model_subclasses = Model.__subclasses__()
115 for model in model_subclasses:
116 if model_type == model.__name__:
117 return Model.fromDom(node)
118 if node.tagName == 'ParameterSet':
119 parameter_type = node.getAttribute("type")
120 return ParameterSet.fromDom(node)
121 raise "Invalid simulation type, %r" % node.getAttribute("type")
122
123
124 raise ValueError("No Simulation Found")
125
126
127 class Link:
128 """
129 A Link makes an attribute of an object callable::
130
131 o.object()
132 o.a=8
133 l=Link(o,"a")
134 assert l()==8
135 """
136
137 def __init__(self,target,attribute=None):
138 """
139 Creates a link to the object target. If attribute is given, the link is
140 establised to this attribute of the target. Otherwise the attribute is
141 undefined.
142 """
143 self.target = target
144 self.attribute = None
145 self.setAttributeName(attribute)
146
147 def setAttributeName(self,attribute):
148 """
149 Set a new attribute name to be collected from the target object. The
150 target object must have the attribute with name attribute.
151 """
152 if attribute and self.target:
153 if isinstance(self.target,LinkableObject):
154 if not self.target.hasAttribute(attribute):
155 raise AttributeError("%s: target %s has no attribute %s."%(self, self.target, attribute))
156 else:
157 if not hasattr(self.target,attribute):
158 raise AttributeError("%s: target %s has no attribute %s."%(self, self.target, attribute))
159 self.attribute = attribute
160
161 def hasDefinedAttributeName(self):
162 """
163 Returns true if an attribute name is set.
164 """
165 return self.attribute != None
166
167 def __repr__(self):
168 """
169 Returns a string representation of the link.
170 """
171 if self.hasDefinedAttributeName():
172 return "<Link to attribute %s of %s>" % (self.attribute, self.target)
173 else:
174 return "<Link to target %s>" % self.target
175
176 def __call__(self,name=None):
177 """
178 Returns the value of the attribute of the target object. If the
179 atrribute is callable then the return value of the call is returned.
180 """
181 if name:
182 out=getattr(self.target, name)
183 else:
184 out=getattr(self.target, self.attribute)
185
186 if callable(out):
187 return out()
188 else:
189 return out
190
191 def toDom(self, document, node):
192 """
193 C{toDom} method of Link. Creates a Link node and appends it to the
194 current XML document.
195 """
196 link = document.createElement('Link')
197 assert (self.target != None), ("Target was none, name was %r" % self.attribute)
198 link.appendChild(dataNode(document, 'Target', self.target.id))
199 # this use of id will not work for purposes of being able to retrieve the intended
200 # target from the xml later. I need a better unique identifier.
201 assert self.attribute, "You can't xmlify a Link without a target attribute"
202 link.appendChild(dataNode(document, 'Attribute', self.attribute))
203 node.appendChild(link)
204
205 def fromDom(cls, doc):
206 targetid = doc.getElementsByTagName("Target")[0].firstChild.nodeValue.strip()
207 attribute = doc.getElementsByTagName("Attribute")[0].firstChild.nodeValue.strip()
208 l = cls(None, attribute)
209 registerLink(targetid, l)
210 return l
211
212 fromDom = classmethod(fromDom)
213
214 def writeXML(self,ostream=stdout):
215 """
216 Writes an XML representation of self to the output stream ostream.
217 If ostream is nor present the standart output stream is used. If
218 esysheader==True the esys XML header is written
219 """
220 print 'I got to the Link writeXML method'
221 document, rootnode = esysDoc()
222 self.toDom(document, rootnode)
223
224 ostream.write(document.toprettyxml())
225
226 class LinkableObject(object):
227 """
228 An object that allows to link its attributes to attributes of other objects
229 via a Link object. For instance::
230
231 p = LinkableObject()
232 p.x = Link(o,"name")
233 print p.x
234
235 links attribute C{x} of C{p} to the attribute name of object C{o}.
236
237 C{p.x} will contain the current value of attribute C{name} of object
238 C{o}.
239
240 If the value of C{getattr(o, "name")} is callable, C{p.x} will return
241 the return value of the call.
242 """
243
244 number_sequence = itertools.count(100)
245
246 def __init__(self, debug=False):
247 """
248 Initializes LinkableObject so that we can operate on Links
249 """
250 self.debug = debug
251 self.__linked_attributes={}
252 self.id = self.number_sequence.next()
253 registerLinkableObject(self.id, self)
254
255 def trace(self, msg):
256 """
257 If debugging is on, print the message, otherwise do nothing
258 """
259 if self.debug:
260 print "%s: %s"%(str(self),msg)
261
262 def __getattr__(self,name):
263 """
264 Returns the value of attribute name. If the value is a Link object the
265 object is called and the return value is returned.
266 """
267 out = self.getAttributeObject(name)
268 if isinstance(out,Link):
269 return out()
270 else:
271 return out
272
273 def getAttributeObject(self,name):
274 """
275 Return the object stored for attribute name.
276 """
277
278 if self.__dict__.has_key(name):
279 return self.__dict__[name]
280
281 if self.__linked_attributes.has_key(name):
282 return self.__linked_attributes[name]
283
284 if self.__class__.__dict__.has_key(name):
285 return self.__class.__dict__[name]
286
287 raise AttributeError,"No attribute %s."%name
288
289 def hasAttribute(self,name):
290 """
291 Returns True if self as attribute name.
292 """
293 return self.__dict__.has_key(name) or self.__linked_attributes.has_key(name) or self.__class__.__dict__.has_key(name)
294
295 def __setattr__(self,name,value):
296 """
297 Sets the value for attribute name. If value is a Link the target
298 attribute is set to name if no attribute has been specified.
299 """
300
301 if self.__dict__.has_key(name):
302 del self.__dict__[name]
303
304 if isinstance(value,Link):
305 if not value.hasDefinedAttributeName():
306 value.setAttributeName(name)
307 self.__linked_attributes[name] = value
308
309 self.trace("attribute %s is now linked by %s."%(name,value))
310 else:
311 self.__dict__[name] = value
312
313 def __delattr__(self,name):
314 """
315 Removes the attribute name.
316 """
317
318 if self.__linked_attributes.has_key[name]:
319 del self.__linked_attributes[name]
320 elif self.__dict__.has_key(name):
321 del self.__dict__[name]
322 else:
323 raise AttributeError,"No attribute %s."%name
324
325 class _ParameterIterator:
326 def __init__(self,parameterset):
327
328 self.__set=parameterset
329 self.__iter=iter(parameterset.parameters)
330
331 def next(self):
332 o=self.__iter.next()
333 return (o,self.__set.getAttributeObject(o))
334
335 def __iter__(self):
336 return self
337
338 class ParameterSet(LinkableObject):
339 """
340 A class which allows to emphazise attributes to be written and read to XML
341
342 Leaves of an ESySParameters object can be:
343
344 - a real number
345 - a integer number
346 - a string
347 - a boolean value
348 - a ParameterSet object
349 - a Simulation object
350 - a Model object
351 - any other object (not considered by writeESySXML and writeXML)
352
353 Example how to create an ESySParameters object::
354
355 p11=ParameterSet(gamma1=1.,gamma2=2.,gamma3=3.)
356 p1=ParameterSet(dim=2,tol_v=0.001,output_file="/tmp/u.%3.3d.dx",runFlag=True,parm11=p11)
357 parm=ParameterSet(parm1=p1,parm2=ParameterSet(alpha=Link(p11,"gamma1")))
358
359 This can be accessed as::
360
361 parm.parm1.gamma=0.
362 parm.parm1.dim=2
363 parm.parm1.tol_v=0.001
364 parm.parm1.output_file="/tmp/u.%3.3d.dx"
365 parm.parm1.runFlag=True
366 parm.parm1.parm11.gamma1=1.
367 parm.parm1.parm11.gamma2=2.
368 parm.parm1.parm11.gamma3=3.
369 parm.parm2.alpha=1. (value of parm.parm1.parm11.gamma1)
370 """
371 def __init__(self, parameters=[], **kwargs):
372 """
373 Creates a ParameterSet with parameters parameters.
374 """
375 LinkableObject.__init__(self, **kwargs)
376 self.parameters = set()
377 self.declareParameters(parameters)
378
379 def __repr__(self):
380 return "<%s %r>" % (self.__class__.__name__,
381 [(p, getattr(self, p, None)) for p in self.parameters])
382
383 def declareParameter(self,**parameters):
384 """
385 Declares a new parameter(s) and its (their) initial value.
386 """
387 self.declareParameters(parameters)
388
389 def declareParameters(self,parameters):
390 """
391 Declares a set of parameters. parameters can be a list, a dictionary
392 or a ParameterSet.
393 """
394 if isinstance(parameters,ListType):
395 parameters = zip(parameters, itertools.repeat(None))
396 if isinstance(parameters,DictType):
397 parameters = parameters.iteritems()
398
399 for prm, value in parameters:
400 setattr(self,prm,value)
401 self.parameters.add(prm)
402
403 self.trace("parameter %s has been declared."%prm)
404
405 def releaseParameters(self,name):
406 """
407 Removes parameter name from the paramameters.
408 """
409 if self.isParameter(name):
410 self.parameters.remove(name)
411 self.trace("parameter %s has been removed."%name)
412
413 def __iter__(self):
414 """
415 Creates an iterator over the parameter and their values.
416 """
417 return _ParameterIterator(self)
418
419 def showParameters(self):
420 """
421 Returns a descrition of the parameters.
422 """
423 out="{"
424 notfirst=False
425 for i,v in self:
426 if notfirst: out=out+","
427 notfirst=True
428 if isinstance(v,ParameterSet):
429 out="%s\"%s\" : %s"%(out,i,v.showParameters())
430 else:
431 out="%s\"%s\" : %s"%(out,i,v)
432 return out+"}"
433
434 def __delattr__(self,name):
435 """
436 Removes the attribute name.
437 """
438 LinkableObject.__delattr__(self,name)
439 try:
440 self.releaseParameter(name)
441 except:
442 pass
443
444 def toDom(self, document, node):
445 """
446 C{toDom} method of ParameterSet class.
447 """
448 pset = document.createElement('ParameterSet')
449 node.appendChild(pset)
450 self._parametersToDom(document, pset)
451
452 def _parametersToDom(self, document, node):
453 node.setAttribute('id', str(self.id))
454 node.setIdAttribute("id")
455 for name,value in self:
456 param = document.createElement('Parameter')
457 param.setAttribute('type', value.__class__.__name__)
458
459 param.appendChild(dataNode(document, 'Name', name))
460
461 val = document.createElement('Value')
462
463 if isinstance(value,ParameterSet):
464 value.toDom(document, val)
465 param.appendChild(val)
466 elif isinstance(value, Link):
467 value.toDom(document, val)
468 param.appendChild(val)
469 elif isinstance(value,StringType):
470 param.appendChild(dataNode(document, 'Value', value))
471 else:
472 param.appendChild(dataNode(document, 'Value', str(value)))
473
474 node.appendChild(param)
475
476 def fromDom(cls, doc):
477
478 # Define a host of helper functions to assist us.
479 def _children(node):
480 """
481 Remove the empty nodes from the children of this node.
482 """
483 return [x for x in node.childNodes
484 if not isinstance(x, minidom.Text) or x.nodeValue.strip()]
485
486 def _floatfromValue(doc):
487 return float(doc.nodeValue.strip())
488
489 def _stringfromValue(doc):
490 return str(doc.nodeValue.strip())
491
492 def _intfromValue(doc):
493 return int(doc.nodeValue.strip())
494
495 def _boolfromValue(doc):
496 return bool(doc.nodeValue.strip())
497
498 def _nonefromValue(doc):
499 return None
500
501 # Mapping from text types in the xml to methods used to process trees of that type
502 ptypemap = {"Simulation": Simulation.fromDom,
503 "Model":Model.fromDom,
504 "ParameterSet":ParameterSet.fromDom,
505 "Link":Link.fromDom,
506 "float":_floatfromValue,
507 "int":_intfromValue,
508 "str":_stringfromValue,
509 "bool":_boolfromValue,
510 "NoneType":_nonefromValue
511 }
512
513 # print doc.toxml()
514
515 parameters = {}
516 for node in _children(doc):
517 ptype = node.getAttribute("type")
518
519 pname = pvalue = None
520 for childnode in _children(node):
521
522 if childnode.tagName == "Name":
523 pname = childnode.firstChild.nodeValue.strip()
524
525 if childnode.tagName == "Value":
526 nodes = _children(childnode)
527 pvalue = ptypemap[ptype](nodes[0])
528
529 parameters[pname] = pvalue
530
531 # Create the instance of ParameterSet
532 o = cls()
533 o.declareParameters(parameters)
534 registerLinkableObject(doc.getAttribute("id"), o)
535 return o
536
537 fromDom = classmethod(fromDom)
538
539 def writeXML(self,ostream=stdout):
540 """
541 Writes the object as an XML object into an output stream.
542 """
543 # ParameterSet(d) with d[Name]=Value
544 document, node = esysDoc()
545 self.toDom(document, node)
546 ostream.write(document.toprettyxml())
547
548 class Model(ParameterSet):
549 """
550 A Model object represents a processess marching over time until a
551 finalizing condition is fullfilled. At each time step an iterative
552 process can be performed and the time step size can be controlled. A
553 Model has the following work flow::
554
555 doInitialization()
556 while not finalize():
557 dt=getSafeTimeStepSize(dt)
558 doStepPreprocessing(dt)
559 while not terminateIteration(): doStep(dt)
560 doStepPostprocessing(dt)
561 doFinalization()
562
563 where C{doInitialization}, C{finalize}, C{getSafeTimeStepSize},
564 C{doStepPreprocessing}, C{terminateIteration}, C{doStepPostprocessing},
565 C{doFinalization} are methods of the particular instance of a Model. The
566 default implementations of these methods have to be overwritten by the
567 subclass implementing a Model.
568 """
569
570 UNDEF_DT=1.e300
571
572 def __init__(self,parameters=[],**kwarg):
573 """
574 Creates a model.
575
576 Just calls the parent constructor.
577 """
578 ParameterSet.__init__(self, parameters=parameters,**kwarg)
579
580 def __str__(self):
581 return "<%s %d>"%(self.__class__,id(self))
582
583 def toDom(self, document, node):
584 """
585 C{toDom} method of Model class
586 """
587 pset = document.createElement('Model')
588 pset.setAttribute('type', self.__class__.__name__)
589 if not self.__class__.__module__.startswith('esys.escript'):
590 pset.setAttribute('module', self.__class__.__module__)
591 node.appendChild(pset)
592 self._parametersToDom(document, pset)
593
594 def doInitialization(self):
595 """
596 Initializes the time stepping scheme.
597
598 This function may be overwritten.
599 """
600 pass
601
602 def getSafeTimeStepSize(self,dt):
603 """
604 Returns a time step size which can safely be used.
605
606 C{dt} gives the previously used step size.
607
608 This function may be overwritten.
609 """
610 return self.UNDEF_DT
611
612 def finalize(self):
613 """
614 Returns False if the time stepping is finalized.
615
616 This function may be overwritten.
617 """
618 return False
619
620 def doFinalization(self):
621 """
622 Finalizes the time stepping.
623
624 This function may be overwritten.
625 """
626 pass
627
628 def doStepPreprocessing(self,dt):
629 """
630 Sets up a time step of step size dt.
631
632 This function may be overwritten.
633 """
634 pass
635
636 def doStep(self,dt):
637 """
638 Executes an iteration step at a time step.
639
640 C{dt} is the currently used time step size.
641
642 This function may be overwritten.
643 """
644 pass
645
646 def terminateIteration(self):
647 """
648 Returns True if iteration on a time step is terminated.
649 """
650 return True
651
652 def doStepPostprocessing(self,dt):
653 """
654 Finalalizes the time step.
655
656 dt is the currently used time step size.
657
658 This function may be overwritten.
659 """
660 pass
661
662 def writeXML(self, ostream=stdout):
663 document, node = esysDoc()
664 self.toDom(document, node)
665 ostream.write(document.toprettyxml())
666
667
668 class Simulation(Model):
669 """
670 A Simulation object is special Model which runs a sequence of Models.
671
672 The methods C{doInitialization}, C{finalize}, C{getSafeTimeStepSize},
673 C{doStepPreprocessing}, C{terminateIteration}, C{doStepPostprocessing},
674 C{doFinalization} are executing the corresponding methods of the models in
675 the simulation.
676 """
677
678 FAILED_TIME_STEPS_MAX=20
679 MAX_ITER_STEPS=50
680
681 def __init__(self, models=[], **kwargs):
682 """
683 Initiates a simulation from a list of models.
684 """
685 Model.__init__(self, **kwargs)
686 self.__models=[]
687
688 for i in range(len(models)):
689 self[i] = models[i]
690
691
692 def __repr__(self):
693 """
694 Returns a string representation of the Simulation.
695 """
696 return "<Simulation %r>" % self.__models
697
698 def __str__(self):
699 """
700 Returning Simulation as a string.
701 """
702 return "<Simulation %d>"%id(self)
703
704 def iterModels(self):
705 """
706 Returns an iterator over the models.
707 """
708 return self.__models
709
710 def __getitem__(self,i):
711 """
712 Returns the i-th model.
713 """
714 return self.__models[i]
715
716 def __setitem__(self,i,value):
717 """
718 Sets the i-th model.
719 """
720 if not isinstance(value,Model):
721 raise ValueError("assigned value is not a Model, Model was:", i, " an instance of: ", value.__class__.__name__)
722 for j in range(max(i-len(self.__models)+1,0)):
723 self.__models.append(None)
724 self.__models[i]=value
725
726 def __len__(self):
727 """
728 Returns the number of models.
729 """
730 return len(self.__models)
731
732 def toDom(self, document, node):
733 """
734 C{toDom} method of Simulation class.
735 """
736 simulation = document.createElement('Simulation')
737 simulation.setAttribute('type', self.__class__.__name__)
738
739 for rank, sim in enumerate(self.iterModels()):
740 component = document.createElement('Component')
741 component.setAttribute('rank', str(rank))
742
743 sim.toDom(document, component)
744
745 simulation.appendChild(component)
746
747 node.appendChild(simulation)
748
749 def writeXML(self,ostream=stdout):
750 """
751 Writes the object as an XML object into an output stream.
752 """
753 document, rootnode = esysDoc()
754 self.toDom(document, rootnode)
755 targetsList = document.getElementsByTagName('Target')
756
757 for element in targetsList:
758 targetId = int(element.firstChild.nodeValue.strip())
759 if document.getElementById(str(targetId)):
760 continue
761 targetObj = LinkableObjectRegistry[targetId]
762 targetObj.toDom(document, rootnode)
763 ostream.write(document.toprettyxml())
764
765 def getSafeTimeStepSize(self,dt):
766 """
767 Returns a time step size which can safely be used by all models.
768
769 This is the minimum over the time step sizes of all models.
770 """
771 out=min([o.getSafeTimeStepSize(dt) for o in self.iterModels()])
772 #print "%s: safe step size is %e."%(str(self),out)
773 return out
774
775 def doInitialization(self):
776 """
777 Initializes all models.
778 """
779 self.n=0
780 self.tn=0.
781 for o in self.iterModels():
782 o.doInitialization()
783
784 def finalize(self):
785 """
786 Returns True if any of the models is to be finalized.
787 """
788 return any([o.finalize() for o in self.iterModels()])
789
790 def doFinalization(self):
791 """
792 Finalalizes the time stepping for all models.
793 """
794 for i in self.iterModels(): i.doFinalization()
795 self.trace("end of time integation.")
796
797 def doStepPreprocessing(self,dt):
798 """
799 Initializes the time step for all models.
800 """
801 for o in self.iterModels():
802 o.doStepPreprocessing(dt)
803
804 def terminateIteration(self):
805 """
806 Returns True if all iterations for all models are terminated.
807 """
808 out=all([o.terminateIteration() for o in self.iterModels()])
809 return out
810
811 def doStepPostprocessing(self,dt):
812 """
813 Finalalizes the iteration process for all models.
814 """
815 for o in self.iterModels():
816 o.doStepPostprocessing(dt)
817 self.n+=1
818 self.tn+=dt
819
820 def doStep(self,dt):
821 """
822 Executes the iteration step at a time step for all model::
823
824 self.doStepPreprocessing(dt)
825 while not self.terminateIteration():
826 for all models:
827 self.doStep(dt)
828 self.doStepPostprocessing(dt)
829 """
830 self.iter=0
831 while not self.terminateIteration():
832 if self.iter==0: self.trace("iteration at %d-th time step %e starts"%(self.n+1,self.tn+dt))
833 self.iter+=1
834 self.trace("iteration step %d"%(self.iter))
835 for o in self.iterModels():
836 o.doStep(dt)
837 if self.iter>0: self.trace("iteration at %d-th time step %e finalized."%(self.n+1,self.tn+dt))
838
839 def run(self,check_point=None):
840 """
841 Run the simulation by performing essentially::
842
843 self.doInitialization()
844 while not self.finalize():
845 dt=self.getSafeTimeStepSize()
846 self.doStep(dt)
847 if n%check_point==0:
848 self.writeXML()
849 self.doFinalization()
850
851 If one of the models in throws a C{FailedTimeStepError} exception a
852 new time step size is computed through getSafeTimeStepSize() and the
853 time step is repeated.
854
855 If one of the models in throws a C{IterationDivergenceError}
856 exception the time step size is halved and the time step is repeated.
857
858 In both cases the time integration is given up after
859 C{Simulation.FAILED_TIME_STEPS_MAX} attempts.
860 """
861 dt=self.UNDEF_DT
862 self.doInitialization()
863 while not self.finalize():
864 step_fail_counter=0
865 iteration_fail_counter=0
866 dt_new=self.getSafeTimeStepSize(dt)
867 self.trace("%d. time step %e (step size %e.)" % (self.n+1,self.tn+dt_new,dt_new))
868 end_of_step=False
869 while not end_of_step:
870 end_of_step=True
871 if not dt_new>0:
872 raise NonPositiveStepSizeError("non-positive step size in step %d",self.n+1)
873 try:
874 self.doStepPreprocessing(dt_new)
875 self.doStep(dt_new)
876 self.doStepPostprocessing(dt_new)
877 except IterationDivergenceError:
878 dt_new*=0.5
879 end_of_step=False
880 iteration_fail_counter+=1
881 if iteration_fail_counter>self.FAILED_TIME_STEPS_MAX:
882 raise SimulationBreakDownError("reduction of time step to achieve convergence failed.")
883 self.trace("iteration fails. time step is repeated with new step size.")
884 except FailedTimeStepError:
885 dt_new=self.getSafeTimeStepSize(dt)
886 end_of_step=False
887 step_fail_counter+=1
888 self.trace("time step is repeated.")
889 if step_fail_counter>self.FAILED_TIME_STEPS_MAX:
890 raise SimulationBreakDownError("time integration is given up after %d attempts."%step_fail_counter)
891 dt=dt_new
892 if not check_point==None:
893 if n%check_point==0:
894 self.trace("check point is created.")
895 self.writeXML()
896 self.doFinalization()
897
898 def fromDom(cls, doc):
899 sims = []
900 for node in doc.childNodes:
901 if isinstance(node, minidom.Text):
902 continue
903
904 sims.append(getComponent(node))
905
906 return cls(sims)
907
908 fromDom = classmethod(fromDom)
909
910
911 class IterationDivergenceError(Exception):
912 """
913 Exception which is thrown if there is no convergence of the iteration
914 process at a time step.
915
916 But there is a chance that a smaller step could help to reach convergence.
917 """
918 pass
919
920 class FailedTimeStepError(Exception):
921 """
922 Exception which is thrown if the time step fails because of a step
923 size that have been choosen to be too large.
924 """
925 pass
926
927 class SimulationBreakDownError(Exception):
928 """
929 Exception which is thrown if the simulation does not manage to
930 progress in time.
931 """
932 pass
933
934 class NonPositiveStepSizeError(Exception):
935 """
936 Exception which is thrown if the step size is not positive.
937 """
938 pass
939
940 # vim: expandtab shiftwidth=4:

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

  ViewVC Help
Powered by ViewVC 1.1.26