--- trunk/esys2/escript/py_src/modelframe.py 2005/09/01 03:31:39 149 +++ trunk/escript/py_src/modelframe.py 2006/10/17 12:06:11 874 @@ -1,7 +1,31 @@ # $Id$ +""" +Environment for implementing models in escript + +@var __author__: name of author +@var __copyright__: copyrights +@var __license__: licence agreement +@var __url__: url entry point on documentation +@var __version__: version +@var __date__: date of the version +""" + +__author__="Lutz Gross, l.gross@uq.edu.au" +__copyright__=""" Copyright (c) 2006 by ACcESS MNRF + http://www.access.edu.au + Primary Business: Queensland, Australia""" +__license__="""Licensed under the Open Software License version 3.0 + http://www.opensource.org/licenses/osl-3.0.php""" +__url__="http://www.iservo.edu.au/esys" +__version__="$Revision$" +__date__="$Date$" + + from types import StringType,IntType,FloatType,BooleanType,ListType,DictType from sys import stdout +import numarray +import operator import itertools # import modellib temporarily removed!!! @@ -73,6 +97,21 @@ return sim +def importName(modulename, name): + """ Import a named object from a module in the context of this function, + which means you should use fully qualified module paths. + + Return None on failure. + + This function from: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52241 + """ + module = __import__(modulename, globals(), locals(), [name]) + + try: + return vars(module)[name] + except KeyError: + raise ImportError("Could not import %s from %s" % (name, modulename)) + def getComponent(doc): """ Used to get components of Simualtions, Models. @@ -84,11 +123,16 @@ if node.getAttribute("type") == 'Simulation': return Simulation.fromDom(node) if node.tagName == 'Model': - model_type = node.getAttribute("type") - model_subclasses = Model.__subclasses__() - for model in model_subclasses: - if model_type == model.__name__: - return Model.fromDom(node) + if (node.getAttribute("module")): + model_module = node.getAttribute("module") + model_type = node.getAttribute("type") + return importName(model_module, model_type).fromDom(node) + else: + model_type = node.getAttribute("type") + model_subclasses = Model.__subclasses__() + for model in model_subclasses: + if model_type == model.__name__: + return Model.fromDom(node) if node.tagName == 'ParameterSet': parameter_type = node.getAttribute("type") return ParameterSet.fromDom(node) @@ -322,7 +366,9 @@ - a ParameterSet object - a Simulation object - a Model object - - any other object (not considered by writeESySXML and writeXML) + - a numarray object + - a list of booleans + - any other object (not considered by writeESySXML and writeXML) Example how to create an ESySParameters object:: @@ -424,7 +470,8 @@ self._parametersToDom(document, pset) def _parametersToDom(self, document, node): - node.setAttribute ('id', str(self.id)) + node.setAttribute('id', str(self.id)) + node.setIdAttribute("id") for name,value in self: param = document.createElement('Parameter') param.setAttribute('type', value.__class__.__name__) @@ -433,14 +480,30 @@ val = document.createElement('Value') - if isinstance(value,ParameterSet): + if isinstance(value,(ParameterSet,Link)): value.toDom(document, val) param.appendChild(val) - elif isinstance(value, Link): - value.toDom(document, val) + elif isinstance(value, numarray.NumArray): + shape = value.getshape() + if isinstance(shape, tuple): + size = reduce(operator.mul, shape) + shape = ' '.join(map(str, shape)) + else: + size = shape + shape = str(shape) + + arraytype = value.type() + numarrayElement = document.createElement('NumArray') + numarrayElement.appendChild(dataNode(document, 'ArrayType', str(arraytype))) + numarrayElement.appendChild(dataNode(document, 'Shape', shape)) + numarrayElement.appendChild(dataNode(document, 'Data', ' '.join( + [str(x) for x in numarray.reshape(value, size)]))) + val.appendChild(numarrayElement) param.appendChild(val) - elif isinstance(value,StringType): - param.appendChild(dataNode(document, 'Value', value)) + elif isinstance (value, list): + param.appendChild(dataNode(document, 'Value', ' '.join( + [str(x) for x in value]) + )) else: param.appendChild(dataNode(document, 'Value', str(value))) @@ -453,8 +516,14 @@ """ Remove the empty nodes from the children of this node. """ - return [x for x in node.childNodes - if not isinstance(x, minidom.Text) or x.nodeValue.strip()] + ret = [] + for x in node.childNodes: + if isinstance(x, minidom.Text): + if x.nodeValue.strip(): + ret.append(x) + else: + ret.append(x) + return ret def _floatfromValue(doc): return float(doc.nodeValue.strip()) @@ -466,8 +535,33 @@ return int(doc.nodeValue.strip()) def _boolfromValue(doc): - return bool(doc.nodeValue.strip()) - + return _boolfromstring(doc.nodeValue.strip()) + + def _nonefromValue(doc): + return None + + def _numarrayfromValue(doc): + for node in _children(doc): + if node.tagName == 'ArrayType': + arraytype = node.firstChild.nodeValue.strip() + if node.tagName == 'Shape': + shape = node.firstChild.nodeValue.strip() + shape = [int(x) for x in shape.split()] + if node.tagName == 'Data': + data = node.firstChild.nodeValue.strip() + data = [float(x) for x in data.split()] + return numarray.reshape(numarray.array(data, type=getattr(numarray, arraytype)), + shape) + + def _listfromValue(doc): + return [_boolfromstring(x) for x in doc.nodeValue.split()] + + + def _boolfromstring(s): + if s == 'True': + return True + else: + return False # Mapping from text types in the xml to methods used to process trees of that type ptypemap = {"Simulation": Simulation.fromDom, "Model":Model.fromDom, @@ -476,7 +570,10 @@ "float":_floatfromValue, "int":_intfromValue, "str":_stringfromValue, - "bool":_boolfromValue + "bool":_boolfromValue, + "list":_listfromValue, + "NumArray":_numarrayfromValue, + "NoneType":_nonefromValue, } # print doc.toxml() @@ -493,6 +590,9 @@ if childnode.tagName == "Value": nodes = _children(childnode) + # if ptype == 'NumArray': + # pvalue = _numarrayfromValue(nodes) + # else: pvalue = ptypemap[ptype](nodes[0]) parameters[pname] = pvalue @@ -555,6 +655,8 @@ """ pset = document.createElement('Model') pset.setAttribute('type', self.__class__.__name__) + if not self.__class__.__module__.startswith('esys.escript'): + pset.setAttribute('module', self.__class__.__module__) node.appendChild(pset) self._parametersToDom(document, pset) @@ -644,6 +746,7 @@ FAILED_TIME_STEPS_MAX=20 MAX_ITER_STEPS=50 + MAX_CHANGE_OF_DT=2. def __init__(self, models=[], **kwargs): """ @@ -685,7 +788,7 @@ Sets the i-th model. """ if not isinstance(value,Model): - raise ValueError("assigned value is not a Model") + raise ValueError,"assigned value is not a Model but instance of %s"%(value.__class__.__name__,) for j in range(max(i-len(self.__models)+1,0)): self.__models.append(None) self.__models[i]=value @@ -720,8 +823,11 @@ document, rootnode = esysDoc() self.toDom(document, rootnode) targetsList = document.getElementsByTagName('Target') - for i in targetsList: - targetId = int(i.firstChild.nodeValue.strip()) + + for element in targetsList: + targetId = int(element.firstChild.nodeValue.strip()) + if document.getElementById(str(targetId)): + continue targetObj = LinkableObjectRegistry[targetId] targetObj.toDom(document, rootnode) ostream.write(document.toprettyxml()) @@ -733,7 +839,7 @@ This is the minimum over the time step sizes of all models. """ out=min([o.getSafeTimeStepSize(dt) for o in self.iterModels()]) - print "%s: safe step size is %e."%(str(self),out) + #print "%s: safe step size is %e."%(str(self),out) return out def doInitialization(self): @@ -827,13 +933,16 @@ while not self.finalize(): step_fail_counter=0 iteration_fail_counter=0 - dt_new=self.getSafeTimeStepSize(dt) + if self.n==0: + dt_new=self.getSafeTimeStepSize(dt) + else: + dt_new=min(max(self.getSafeTimeStepSize(dt),dt/self.MAX_CHANGE_OF_DT),dt*self.MAX_CHANGE_OF_DT) self.trace("%d. time step %e (step size %e.)" % (self.n+1,self.tn+dt_new,dt_new)) end_of_step=False while not end_of_step: end_of_step=True if not dt_new>0: - raise NonPositiveStepSizeError("non-positive step size in step %d",self.n+1) + raise NonPositiveStepSizeError("non-positive step size in step %d"%(self.n+1)) try: self.doStepPreprocessing(dt_new) self.doStep(dt_new) @@ -843,15 +952,15 @@ end_of_step=False iteration_fail_counter+=1 if iteration_fail_counter>self.FAILED_TIME_STEPS_MAX: - raise SimulationBreakDownError("reduction of time step to achieve convergence failed.") - self.trace("iteration fails. time step is repeated with new step size.") + raise SimulationBreakDownError("reduction of time step to achieve convergence failed after %s steps."%self.FAILED_TIME_STEPS_MAX) + self.trace("Iteration failed. Time step is repeated with new step size %s."%dt_new) except FailedTimeStepError: dt_new=self.getSafeTimeStepSize(dt) end_of_step=False step_fail_counter+=1 - self.trace("time step is repeated.") + self.trace("Time step is repeated with new time step size %s."%dt_new) if step_fail_counter>self.FAILED_TIME_STEPS_MAX: - raise SimulationBreakDownError("time integration is given up after %d attempts."%step_fail_counter) + raise SimulationBreakDownError("Time integration is given up after %d attempts."%step_fail_counter) dt=dt_new if not check_point==None: if n%check_point==0: