/[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 875 - (hide annotations)
Tue Oct 17 12:42:47 2006 UTC (13 years ago) by elspeth
File MIME type: text/x-python
File size: 32700 byte(s)
DataSources added to modelframe/EsysXML, and tests to run_xml.py. Currently does not actually handle data 
sources, 
just references. Functionality is in progress. 

EsysXML format (URI can be a local file reference, or a remote reference such as an ftp site, fileformat 
is currently any string descriptor, such as finleyMesh or gmtdata):
 <Parameter type="DataSource">
                        <Name>
                                uritest
                        </Name>
                        <Value>
                                <DataSource>
                                        <URI>
                                                somelocalfile.txt
                                        </URI>
                                        <FileFormat>
                                                text
                                        </FileFormat>
                                </DataSource>
                        </Value>
                </Parameter>


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