/[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 912 - (hide annotations)
Wed Dec 6 03:29:49 2006 UTC (12 years, 4 months ago) by gross
File MIME type: text/x-python
File size: 34601 byte(s)
modellib.WriteVTK has been rewritten. Instead of only three data objects scalar,
vector, tensor it takes now up to 20 data objects data0 ... data19 and writes it into a 
single VTK file. There is also the possibilty to define individiual name tags name0,..., name19.
If no name is given the corresponding attribute name of the Link target is used. 
This simplifies the usage and increases efficiency.



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