/[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 150 - (hide annotations)
Thu Sep 15 03:44:45 2005 UTC (14 years, 1 month ago) by jgs
Original Path: trunk/esys2/escript/py_src/modelframe.py
File MIME type: text/x-python
File size: 28294 byte(s)
Merge of development branch dev-02 back to main trunk on 2005-09-15

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