/[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 266 - (hide annotations)
Wed Nov 30 00:21:51 2005 UTC (13 years, 10 months ago) by elspeth
File MIME type: text/x-python
File size: 28399 byte(s)
Added handling for NoneType

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 elspeth 266
491     def _nonefromValue(doc):
492     return None
493 jgs 126
494 jgs 123 # Mapping from text types in the xml to methods used to process trees of that type
495     ptypemap = {"Simulation": Simulation.fromDom,
496     "Model":Model.fromDom,
497     "ParameterSet":ParameterSet.fromDom,
498     "Link":Link.fromDom,
499     "float":_floatfromValue,
500 jgs 126 "int":_intfromValue,
501 jgs 123 "str":_stringfromValue,
502 jgs 126 "bool":_boolfromValue
503 elspeth 266 "NoneType":_nonefromValue,
504 jgs 123 }
505    
506 jgs 147 # print doc.toxml()
507    
508 jgs 123 parameters = {}
509     for node in _children(doc):
510     ptype = node.getAttribute("type")
511    
512     pname = pvalue = None
513     for childnode in _children(node):
514    
515     if childnode.tagName == "Name":
516     pname = childnode.firstChild.nodeValue.strip()
517    
518     if childnode.tagName == "Value":
519     nodes = _children(childnode)
520     pvalue = ptypemap[ptype](nodes[0])
521    
522     parameters[pname] = pvalue
523    
524     # Create the instance of ParameterSet
525     o = cls()
526     o.declareParameters(parameters)
527     registerLinkableObject(doc.getAttribute("id"), o)
528     return o
529    
530     fromDom = classmethod(fromDom)
531    
532     def writeXML(self,ostream=stdout):
533 jgs 149 """
534     Writes the object as an XML object into an output stream.
535     """
536 jgs 123 # ParameterSet(d) with d[Name]=Value
537     document, node = esysDoc()
538     self.toDom(document, node)
539     ostream.write(document.toprettyxml())
540    
541 jgs 147 class Model(ParameterSet):
542     """
543 jgs 149 A Model object represents a processess marching over time until a
544     finalizing condition is fullfilled. At each time step an iterative
545     process can be performed and the time step size can be controlled. A
546     Model has the following work flow::
547 jgs 121
548 jgs 147 doInitialization()
549     while not finalize():
550     dt=getSafeTimeStepSize(dt)
551     doStepPreprocessing(dt)
552     while not terminateIteration(): doStep(dt)
553     doStepPostprocessing(dt)
554     doFinalization()
555 jgs 121
556 jgs 149 where C{doInitialization}, C{finalize}, C{getSafeTimeStepSize},
557     C{doStepPreprocessing}, C{terminateIteration}, C{doStepPostprocessing},
558     C{doFinalization} are methods of the particular instance of a Model. The
559     default implementations of these methods have to be overwritten by the
560     subclass implementing a Model.
561 jgs 147 """
562 jgs 121
563 jgs 147 UNDEF_DT=1.e300
564 jgs 121
565 jgs 147 def __init__(self,parameters=[],**kwarg):
566 jgs 149 """
567     Creates a model.
568 jgs 121
569 jgs 149 Just calls the parent constructor.
570 jgs 147 """
571     ParameterSet.__init__(self, parameters=parameters,**kwarg)
572 jgs 121
573 jgs 147 def __str__(self):
574     return "<%s %d>"%(self.__class__,id(self))
575 jgs 121
576 jgs 147 def toDom(self, document, node):
577 jgs 149 """
578     C{toDom} method of Model class
579     """
580 jgs 147 pset = document.createElement('Model')
581     pset.setAttribute('type', self.__class__.__name__)
582 jgs 150 if not self.__class__.__module__.startswith('esys.escript'):
583     pset.setAttribute('module', self.__class__.__module__)
584 jgs 147 node.appendChild(pset)
585     self._parametersToDom(document, pset)
586 jgs 121
587 jgs 147 def doInitialization(self):
588 jgs 149 """
589     Initializes the time stepping scheme.
590    
591     This function may be overwritten.
592     """
593 jgs 147 pass
594    
595     def getSafeTimeStepSize(self,dt):
596 jgs 149 """
597     Returns a time step size which can safely be used.
598    
599     C{dt} gives the previously used step size.
600    
601     This function may be overwritten.
602     """
603 jgs 147 return self.UNDEF_DT
604    
605     def finalize(self):
606 jgs 149 """
607     Returns False if the time stepping is finalized.
608    
609     This function may be overwritten.
610     """
611 jgs 147 return False
612 jgs 123
613 jgs 147 def doFinalization(self):
614 jgs 149 """
615     Finalizes the time stepping.
616    
617     This function may be overwritten.
618     """
619 jgs 147 pass
620    
621     def doStepPreprocessing(self,dt):
622 jgs 149 """
623     Sets up a time step of step size dt.
624    
625     This function may be overwritten.
626     """
627 jgs 147 pass
628    
629     def doStep(self,dt):
630 jgs 149 """
631     Executes an iteration step at a time step.
632    
633     C{dt} is the currently used time step size.
634    
635     This function may be overwritten.
636     """
637 jgs 147 pass
638    
639     def terminateIteration(self):
640 jgs 149 """
641     Returns True if iteration on a time step is terminated.
642     """
643 jgs 147 return True
644    
645     def doStepPostprocessing(self,dt):
646 jgs 149 """
647     Finalalizes the time step.
648    
649     dt is the currently used time step size.
650    
651     This function may be overwritten.
652     """
653 jgs 147 pass
654    
655     def writeXML(self, ostream=stdout):
656     document, node = esysDoc()
657     self.toDom(document, node)
658     ostream.write(document.toprettyxml())
659    
660 jgs 121
661 jgs 147 class Simulation(Model):
662     """
663 jgs 149 A Simulation object is special Model which runs a sequence of Models.
664 jgs 121
665 jgs 149 The methods C{doInitialization}, C{finalize}, C{getSafeTimeStepSize},
666     C{doStepPreprocessing}, C{terminateIteration}, C{doStepPostprocessing},
667     C{doFinalization} are executing the corresponding methods of the models in
668     the simulation.
669 jgs 147 """
670    
671     FAILED_TIME_STEPS_MAX=20
672     MAX_ITER_STEPS=50
673    
674     def __init__(self, models=[], **kwargs):
675 jgs 149 """
676     Initiates a simulation from a list of models.
677     """
678 jgs 147 Model.__init__(self, **kwargs)
679     self.__models=[]
680 jgs 149
681 jgs 147 for i in range(len(models)):
682     self[i] = models[i]
683 jgs 149
684 jgs 121
685 jgs 147 def __repr__(self):
686     """
687 jgs 149 Returns a string representation of the Simulation.
688 jgs 147 """
689     return "<Simulation %r>" % self.__models
690 jgs 121
691 jgs 147 def __str__(self):
692     """
693 jgs 149 Returning Simulation as a string.
694 jgs 147 """
695     return "<Simulation %d>"%id(self)
696    
697     def iterModels(self):
698 jgs 149 """
699     Returns an iterator over the models.
700     """
701 jgs 147 return self.__models
702    
703     def __getitem__(self,i):
704 jgs 149 """
705     Returns the i-th model.
706     """
707 jgs 147 return self.__models[i]
708    
709     def __setitem__(self,i,value):
710 jgs 149 """
711     Sets the i-th model.
712     """
713 jgs 147 if not isinstance(value,Model):
714     raise ValueError("assigned value is not a Model")
715 jgs 149 for j in range(max(i-len(self.__models)+1,0)):
716     self.__models.append(None)
717 jgs 147 self.__models[i]=value
718    
719     def __len__(self):
720 jgs 149 """
721     Returns the number of models.
722     """
723 jgs 147 return len(self.__models)
724 jgs 121
725 jgs 147 def toDom(self, document, node):
726 jgs 149 """
727     C{toDom} method of Simulation class.
728     """
729 jgs 147 simulation = document.createElement('Simulation')
730     simulation.setAttribute('type', self.__class__.__name__)
731 jgs 121
732 jgs 147 for rank, sim in enumerate(self.iterModels()):
733     component = document.createElement('Component')
734     component.setAttribute('rank', str(rank))
735 jgs 121
736 jgs 147 sim.toDom(document, component)
737 jgs 121
738 jgs 147 simulation.appendChild(component)
739 jgs 121
740 jgs 147 node.appendChild(simulation)
741 jgs 121
742 jgs 147 def writeXML(self,ostream=stdout):
743 jgs 149 """
744     Writes the object as an XML object into an output stream.
745     """
746 jgs 147 document, rootnode = esysDoc()
747     self.toDom(document, rootnode)
748 jgs 149 targetsList = document.getElementsByTagName('Target')
749     for i in targetsList:
750     targetId = int(i.firstChild.nodeValue.strip())
751     targetObj = LinkableObjectRegistry[targetId]
752     targetObj.toDom(document, rootnode)
753 jgs 147 ostream.write(document.toprettyxml())
754    
755     def getSafeTimeStepSize(self,dt):
756 jgs 149 """
757     Returns a time step size which can safely be used by all models.
758    
759     This is the minimum over the time step sizes of all models.
760     """
761 jgs 147 out=min([o.getSafeTimeStepSize(dt) for o in self.iterModels()])
762 jgs 150 #print "%s: safe step size is %e."%(str(self),out)
763 jgs 147 return out
764    
765     def doInitialization(self):
766 jgs 149 """
767     Initializes all models.
768     """
769 jgs 147 self.n=0
770     self.tn=0.
771     for o in self.iterModels():
772     o.doInitialization()
773    
774     def finalize(self):
775 jgs 149 """
776     Returns True if any of the models is to be finalized.
777     """
778 jgs 147 return any([o.finalize() for o in self.iterModels()])
779 jgs 123
780 jgs 147 def doFinalization(self):
781 jgs 149 """
782     Finalalizes the time stepping for all models.
783     """
784 jgs 147 for i in self.iterModels(): i.doFinalization()
785     self.trace("end of time integation.")
786    
787     def doStepPreprocessing(self,dt):
788 jgs 149 """
789     Initializes the time step for all models.
790     """
791 jgs 147 for o in self.iterModels():
792     o.doStepPreprocessing(dt)
793    
794     def terminateIteration(self):
795 jgs 149 """
796     Returns True if all iterations for all models are terminated.
797     """
798 jgs 147 out=all([o.terminateIteration() for o in self.iterModels()])
799     return out
800 jgs 123
801 jgs 147 def doStepPostprocessing(self,dt):
802 jgs 149 """
803     Finalalizes the iteration process for all models.
804     """
805 jgs 147 for o in self.iterModels():
806     o.doStepPostprocessing(dt)
807     self.n+=1
808     self.tn+=dt
809    
810     def doStep(self,dt):
811     """
812 jgs 149 Executes the iteration step at a time step for all model::
813 jgs 147
814 jgs 149 self.doStepPreprocessing(dt)
815     while not self.terminateIteration():
816     for all models:
817     self.doStep(dt)
818     self.doStepPostprocessing(dt)
819 jgs 147 """
820     self.iter=0
821     while not self.terminateIteration():
822     if self.iter==0: self.trace("iteration at %d-th time step %e starts"%(self.n+1,self.tn+dt))
823     self.iter+=1
824     self.trace("iteration step %d"%(self.iter))
825     for o in self.iterModels():
826     o.doStep(dt)
827     if self.iter>0: self.trace("iteration at %d-th time step %e finalized."%(self.n+1,self.tn+dt))
828 jgs 121
829 jgs 147 def run(self,check_point=None):
830     """
831 jgs 149 Run the simulation by performing essentially::
832 jgs 123
833 jgs 149 self.doInitialization()
834     while not self.finalize():
835     dt=self.getSafeTimeStepSize()
836     self.doStep(dt)
837     if n%check_point==0:
838     self.writeXML()
839     self.doFinalization()
840 jgs 121
841 jgs 149 If one of the models in throws a C{FailedTimeStepError} exception a
842     new time step size is computed through getSafeTimeStepSize() and the
843     time step is repeated.
844 jgs 121
845 jgs 149 If one of the models in throws a C{IterationDivergenceError}
846     exception the time step size is halved and the time step is repeated.
847 jgs 121
848 jgs 149 In both cases the time integration is given up after
849     C{Simulation.FAILED_TIME_STEPS_MAX} attempts.
850 jgs 147 """
851     dt=self.UNDEF_DT
852     self.doInitialization()
853     while not self.finalize():
854     step_fail_counter=0
855     iteration_fail_counter=0
856     dt_new=self.getSafeTimeStepSize(dt)
857     self.trace("%d. time step %e (step size %e.)" % (self.n+1,self.tn+dt_new,dt_new))
858     end_of_step=False
859     while not end_of_step:
860     end_of_step=True
861     if not dt_new>0:
862     raise NonPositiveStepSizeError("non-positive step size in step %d",self.n+1)
863     try:
864     self.doStepPreprocessing(dt_new)
865     self.doStep(dt_new)
866     self.doStepPostprocessing(dt_new)
867     except IterationDivergenceError:
868     dt_new*=0.5
869     end_of_step=False
870     iteration_fail_counter+=1
871     if iteration_fail_counter>self.FAILED_TIME_STEPS_MAX:
872     raise SimulationBreakDownError("reduction of time step to achieve convergence failed.")
873     self.trace("iteration fails. time step is repeated with new step size.")
874     except FailedTimeStepError:
875     dt_new=self.getSafeTimeStepSize(dt)
876     end_of_step=False
877     step_fail_counter+=1
878     self.trace("time step is repeated.")
879     if step_fail_counter>self.FAILED_TIME_STEPS_MAX:
880     raise SimulationBreakDownError("time integration is given up after %d attempts."%step_fail_counter)
881     dt=dt_new
882     if not check_point==None:
883     if n%check_point==0:
884     self.trace("check point is created.")
885     self.writeXML()
886     self.doFinalization()
887 jgs 121
888 jgs 147 def fromDom(cls, doc):
889     sims = []
890     for node in doc.childNodes:
891     if isinstance(node, minidom.Text):
892     continue
893 jgs 121
894 jgs 147 sims.append(getComponent(node))
895 jgs 121
896 jgs 147 return cls(sims)
897 jgs 121
898 jgs 147 fromDom = classmethod(fromDom)
899 jgs 121
900    
901 jgs 147 class IterationDivergenceError(Exception):
902     """
903 jgs 149 Exception which is thrown if there is no convergence of the iteration
904     process at a time step.
905 jgs 121
906 jgs 149 But there is a chance that a smaller step could help to reach convergence.
907 jgs 147 """
908     pass
909 jgs 121
910 jgs 147 class FailedTimeStepError(Exception):
911 jgs 149 """
912     Exception which is thrown if the time step fails because of a step
913     size that have been choosen to be too large.
914     """
915 jgs 147 pass
916 jgs 121
917 jgs 147 class SimulationBreakDownError(Exception):
918 jgs 149 """
919     Exception which is thrown if the simulation does not manage to
920     progress in time.
921     """
922 jgs 147 pass
923 jgs 121
924 jgs 147 class NonPositiveStepSizeError(Exception):
925 jgs 149 """
926     Exception which is thrown if the step size is not positive.
927     """
928 jgs 147 pass
929 jgs 149
930     # 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