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