/[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 282 - (hide annotations)
Wed Nov 30 09:18:38 2005 UTC (13 years, 10 months ago) by elspeth
File MIME type: text/x-python
File size: 28595 byte(s)
Fixed XML duplication in output bug.

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