/[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 614 - (hide annotations)
Wed Mar 22 01:37:07 2006 UTC (13 years, 1 month ago) by elspeth
File MIME type: text/x-python
File size: 28884 byte(s)
Corrected spelling of 'license' in url so that the link actually points to the license.

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

Properties

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

  ViewVC Help
Powered by ViewVC 1.1.26