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

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

Parent Directory Parent Directory | Revision Log Revision Log


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