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