/[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 269 - (hide annotations)
Wed Nov 30 01:59:55 2005 UTC (13 years, 10 months ago) by elspeth
File MIME type: text/x-python
File size: 28509 byte(s)
Fixed typos and import problems

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 elspeth 269 "bool":_boolfromValue,
503     "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 elspeth 269 print "The model we got up to: ", i
683 jgs 147 self[i] = models[i]
684 jgs 149
685 jgs 121
686 jgs 147 def __repr__(self):
687     """
688 jgs 149 Returns a string representation of the Simulation.
689 jgs 147 """
690     return "<Simulation %r>" % self.__models
691 jgs 121
692 jgs 147 def __str__(self):
693     """
694 jgs 149 Returning Simulation as a string.
695 jgs 147 """
696     return "<Simulation %d>"%id(self)
697    
698     def iterModels(self):
699 jgs 149 """
700     Returns an iterator over the models.
701     """
702 jgs 147 return self.__models
703    
704     def __getitem__(self,i):
705 jgs 149 """
706     Returns the i-th model.
707     """
708 jgs 147 return self.__models[i]
709    
710     def __setitem__(self,i,value):
711 jgs 149 """
712     Sets the i-th model.
713     """
714 jgs 147 if not isinstance(value,Model):
715 elspeth 269 raise ValueError("assigned value is not a Model, Model was:", i, " an instance of: ", value.__class__.__name__)
716 jgs 149 for j in range(max(i-len(self.__models)+1,0)):
717     self.__models.append(None)
718 jgs 147 self.__models[i]=value
719    
720     def __len__(self):
721 jgs 149 """
722     Returns the number of models.
723     """
724 jgs 147 return len(self.__models)
725 jgs 121
726 jgs 147 def toDom(self, document, node):
727 jgs 149 """
728     C{toDom} method of Simulation class.
729     """
730 jgs 147 simulation = document.createElement('Simulation')
731     simulation.setAttribute('type', self.__class__.__name__)
732 jgs 121
733 jgs 147 for rank, sim in enumerate(self.iterModels()):
734     component = document.createElement('Component')
735     component.setAttribute('rank', str(rank))
736 jgs 121
737 jgs 147 sim.toDom(document, component)
738 jgs 121
739 jgs 147 simulation.appendChild(component)
740 jgs 121
741 jgs 147 node.appendChild(simulation)
742 jgs 121
743 jgs 147 def writeXML(self,ostream=stdout):
744 jgs 149 """
745     Writes the object as an XML object into an output stream.
746     """
747 jgs 147 document, rootnode = esysDoc()
748     self.toDom(document, rootnode)
749 jgs 149 targetsList = document.getElementsByTagName('Target')
750     for i in targetsList:
751     targetId = int(i.firstChild.nodeValue.strip())
752     targetObj = LinkableObjectRegistry[targetId]
753     targetObj.toDom(document, rootnode)
754 jgs 147 ostream.write(document.toprettyxml())
755    
756     def getSafeTimeStepSize(self,dt):
757 jgs 149 """
758     Returns a time step size which can safely be used by all models.
759    
760     This is the minimum over the time step sizes of all models.
761     """
762 jgs 147 out=min([o.getSafeTimeStepSize(dt) for o in self.iterModels()])
763 jgs 150 #print "%s: safe step size is %e."%(str(self),out)
764 jgs 147 return out
765    
766     def doInitialization(self):
767 jgs 149 """
768     Initializes all models.
769     """
770 jgs 147 self.n=0
771     self.tn=0.
772     for o in self.iterModels():
773     o.doInitialization()
774    
775     def finalize(self):
776 jgs 149 """
777     Returns True if any of the models is to be finalized.
778     """
779 jgs 147 return any([o.finalize() for o in self.iterModels()])
780 jgs 123
781 jgs 147 def doFinalization(self):
782 jgs 149 """
783     Finalalizes the time stepping for all models.
784     """
785 jgs 147 for i in self.iterModels(): i.doFinalization()
786     self.trace("end of time integation.")
787    
788     def doStepPreprocessing(self,dt):
789 jgs 149 """
790     Initializes the time step for all models.
791     """
792 jgs 147 for o in self.iterModels():
793     o.doStepPreprocessing(dt)
794    
795     def terminateIteration(self):
796 jgs 149 """
797     Returns True if all iterations for all models are terminated.
798     """
799 jgs 147 out=all([o.terminateIteration() for o in self.iterModels()])
800     return out
801 jgs 123
802 jgs 147 def doStepPostprocessing(self,dt):
803 jgs 149 """
804     Finalalizes the iteration process for all models.
805     """
806 jgs 147 for o in self.iterModels():
807     o.doStepPostprocessing(dt)
808     self.n+=1
809     self.tn+=dt
810    
811     def doStep(self,dt):
812     """
813 jgs 149 Executes the iteration step at a time step for all model::
814 jgs 147
815 jgs 149 self.doStepPreprocessing(dt)
816     while not self.terminateIteration():
817     for all models:
818     self.doStep(dt)
819     self.doStepPostprocessing(dt)
820 jgs 147 """
821     self.iter=0
822     while not self.terminateIteration():
823     if self.iter==0: self.trace("iteration at %d-th time step %e starts"%(self.n+1,self.tn+dt))
824     self.iter+=1
825     self.trace("iteration step %d"%(self.iter))
826     for o in self.iterModels():
827     o.doStep(dt)
828     if self.iter>0: self.trace("iteration at %d-th time step %e finalized."%(self.n+1,self.tn+dt))
829 jgs 121
830 jgs 147 def run(self,check_point=None):
831     """
832 jgs 149 Run the simulation by performing essentially::
833 jgs 123
834 jgs 149 self.doInitialization()
835     while not self.finalize():
836     dt=self.getSafeTimeStepSize()
837     self.doStep(dt)
838     if n%check_point==0:
839     self.writeXML()
840     self.doFinalization()
841 jgs 121
842 jgs 149 If one of the models in throws a C{FailedTimeStepError} exception a
843     new time step size is computed through getSafeTimeStepSize() and the
844     time step is repeated.
845 jgs 121
846 jgs 149 If one of the models in throws a C{IterationDivergenceError}
847     exception the time step size is halved and the time step is repeated.
848 jgs 121
849 jgs 149 In both cases the time integration is given up after
850     C{Simulation.FAILED_TIME_STEPS_MAX} attempts.
851 jgs 147 """
852     dt=self.UNDEF_DT
853     self.doInitialization()
854     while not self.finalize():
855     step_fail_counter=0
856     iteration_fail_counter=0
857     dt_new=self.getSafeTimeStepSize(dt)
858     self.trace("%d. time step %e (step size %e.)" % (self.n+1,self.tn+dt_new,dt_new))
859     end_of_step=False
860     while not end_of_step:
861     end_of_step=True
862     if not dt_new>0:
863     raise NonPositiveStepSizeError("non-positive step size in step %d",self.n+1)
864     try:
865     self.doStepPreprocessing(dt_new)
866     self.doStep(dt_new)
867     self.doStepPostprocessing(dt_new)
868     except IterationDivergenceError:
869     dt_new*=0.5
870     end_of_step=False
871     iteration_fail_counter+=1
872     if iteration_fail_counter>self.FAILED_TIME_STEPS_MAX:
873     raise SimulationBreakDownError("reduction of time step to achieve convergence failed.")
874     self.trace("iteration fails. time step is repeated with new step size.")
875     except FailedTimeStepError:
876     dt_new=self.getSafeTimeStepSize(dt)
877     end_of_step=False
878     step_fail_counter+=1
879     self.trace("time step is repeated.")
880     if step_fail_counter>self.FAILED_TIME_STEPS_MAX:
881     raise SimulationBreakDownError("time integration is given up after %d attempts."%step_fail_counter)
882     dt=dt_new
883     if not check_point==None:
884     if n%check_point==0:
885     self.trace("check point is created.")
886     self.writeXML()
887     self.doFinalization()
888 jgs 121
889 jgs 147 def fromDom(cls, doc):
890     sims = []
891     for node in doc.childNodes:
892     if isinstance(node, minidom.Text):
893     continue
894 jgs 121
895 jgs 147 sims.append(getComponent(node))
896 jgs 121
897 jgs 147 return cls(sims)
898 jgs 121
899 jgs 147 fromDom = classmethod(fromDom)
900 jgs 121
901    
902 jgs 147 class IterationDivergenceError(Exception):
903     """
904 jgs 149 Exception which is thrown if there is no convergence of the iteration
905     process at a time step.
906 jgs 121
907 jgs 149 But there is a chance that a smaller step could help to reach convergence.
908 jgs 147 """
909     pass
910 jgs 121
911 jgs 147 class FailedTimeStepError(Exception):
912 jgs 149 """
913     Exception which is thrown if the time step fails because of a step
914     size that have been choosen to be too large.
915     """
916 jgs 147 pass
917 jgs 121
918 jgs 147 class SimulationBreakDownError(Exception):
919 jgs 149 """
920     Exception which is thrown if the simulation does not manage to
921     progress in time.
922     """
923 jgs 147 pass
924 jgs 121
925 jgs 147 class NonPositiveStepSizeError(Exception):
926 jgs 149 """
927     Exception which is thrown if the step size is not positive.
928     """
929 jgs 147 pass
930 jgs 149
931     # 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