/[escript]/trunk/escript/py_src/modelframe.py
ViewVC logotype

Contents of /trunk/escript/py_src/modelframe.py

Parent Directory Parent Directory | Revision Log Revision Log


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