/[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 912 - (show annotations)
Wed Dec 6 03:29:49 2006 UTC (11 years, 5 months ago) by gross
File MIME type: text/x-python
File size: 34601 byte(s)
modellib.WriteVTK has been rewritten. Instead of only three data objects scalar,
vector, tensor it takes now up to 20 data objects data0 ... data19 and writes it into a 
single VTK file. There is also the possibilty to define individiual name tags name0,..., name19.
If no name is given the corresponding attribute name of the Link target is used. 
This simplifies the usage and increases efficiency.



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