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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 614 - (show annotations)
Wed Mar 22 01:37:07 2006 UTC (13 years, 7 months ago) by elspeth
File MIME type: text/x-python
File size: 20089 byte(s)
Corrected spelling of 'license' in url so that the link actually points to the license.

1 # $Id$
2 """
3 A simple tool to handle parameters for a simulation in easy way.
4
5 The idea is that all parameters are stored in a single object in a
6 hierachical form and can accessed using python's attribute notation.
7 For instance::
8
9 parm.parm2.alpha=814.
10 parm.parm1.gamma=0.
11 parm.parm1.dim=2
12 parm.parm1.tol_v=0.001
13 parm.parm1.output_file="/tmp/u.%3.3d.dx"
14 parm.parm1.runFlag=True
15 parm.parm1.T=1.
16 parm.parm1.x1=[-1.,2]
17 parm.parm1.x2=(10.,11)
18 parm.parm1.x3=(-10.,)
19 parm.parm1.parm11.gamma1=1.
20 parm.parm1.parm11.gamma2=2.
21 parm.parm1.parm11.gamma3=3.
22
23 This structure can be stored/defined through an XML file parm.xml::
24
25 <?xml version="1.0"?>
26 <ESyS>
27 <Component type="Geodynamics">
28 <Name>parm1</Name>
29 <Description>
30 a few examples of parameters
31 </Description>
32 <Parameter><Item>gamma</Item><Value>0.</Value></Parameter>
33 <Parameter type="int"><Item>dim</Item><Value>2</Value></Parameter>
34 <Parameter type="real"><Item>tol_v</Item><Value>0.001</Value></Parameter>
35 <Parameter type="string"><Item>output_file</Item><Value>/tmp/u.%3.3d.dx</Value></Parameter>
36 <Parameter type="bool"><Item>runFlag</Item><Value>true</Value></Parameter>
37 <Parameter type="real" sequence="single"><Item>T</Item><Value>1.</Value><Value>2</Value></Parameter>
38 <Parameter type="real" sequence="list"><Item>x1</Item><Value>-1.</Value><Value>2</Value></Parameter>
39 <Parameter type="real" sequence="tuple"><Item>x2</Item><Value>10</Value><Value>11</Value></Parameter>
40 <Parameter sequence="tuple"><Item>x3</Item><Value>-10.</Value></Parameter>
41 <Component>
42 <Name>parm11</Name>
43 <Description>
44 a sub compoment
45 </Description>
46 <Parameter><Item>gamma1</Item><Value>1.</Value></Parameter>
47 <Parameter><Item>gamma2</Item><Value>2.</Value></Parameter>
48 <Parameter><Item>gamma3</Item><Value>3.</Value></Parameter>
49 </Component>
50 <Component type="Geodynamics">
51 <Name>parm2</Name>
52 <Description>
53 another component
54 </Description>
55 <Parameter><Item>alpha</Item><Value>0814</Value></Parameter>
56 </Component>
57 </ESyS>
58 """
59
60 __copyright__=""" Copyright (c) 2006 by ACcESS MNRF
61 http://www.access.edu.au
62 Primary Business: Queensland, Australia"""
63 __license__="""Licensed under the Open Software License version 3.0
64 http://www.opensource.org/licenses/osl-3.0.php"""
65
66 import types
67 from xml.dom import minidom
68 from string import atoi,atof
69
70 class ESySParameters:
71 """
72 Is an object to store simulation parameters in the form of a tree and
73 access their values in an easy form
74
75 Leaves of an ESySParameters object can be:
76
77 - a single real number or a list or tuple of real numbers
78 - a single integer number or a list or tuple of integer numbers
79 - a single strings or a list or tuple of strings
80 - a single boolean value or a list or tuple of boolean values
81 - a ESySParameters object
82 - any other object (not considered by writeESySXML and writeXML)
83
84 Example how to create an ESySParameters object::
85
86 parm=ESySParameters()
87 parm.parm1=ESySParameters()
88 parm.parm1.gamma=0.
89 parm.parm1.dim=2
90 parm.parm1.tol_v=0.001
91 parm.parm1.output_file="/tmp/u.%3.3d.dx"
92 parm.parm1.runFlag=True
93 parm.parm1.T=1.
94 parm.parm1.x1=[-1.,2]
95 parm.parm1.x2=(10.,11)
96 parm.parm1.x3=(-10.,)
97 parm.parm1.parm11=ESySParameters()
98 parm.parm1.parm11.gamma1=1.
99 parm.parm1.parm11.gamma2=2.
100 parm.parm1.parm11.gamma3=3.
101 parm.parm2=ESySParameters()
102 parm.parm2.alpha=814.
103
104 print parm
105
106 Output is::
107
108 (parm1=(dim=2,output_file=/tmp/u.%3.3d.dx,parm11=(gamma3=3.0,gamma2=2.0,gamma1=1.0),
109 tol_v=0.001,T=1.0,x2=(10,),x3=(-10,),runFlag=True,x1=[-1.0, 2.0],gamma=0.0),parm2=(alpha=814.0))
110
111 Notice that C{parm.parm1.x1} is now a list of two floats although it is
112 defined by a list of a float and an integer. ESySParameter is trying to
113 use the same type for all items in a list or a tuple.
114 """
115
116 def __init__(self,description="none",type=None):
117 self.setDescription(description)
118 self.setType(type)
119
120 def getTypeName(self):
121 if self.__type==None:
122 return None
123 else:
124 return self.__type.__str__()
125
126 def getDescription(self):
127 return self.__description
128
129 def setType(self,type=None):
130 self.__type=type
131
132 def setDescription(self,description="none"):
133 self.__description=description
134
135 def __str__(self):
136 """
137 Returns a string representation.
138 """
139 out=""
140 for name,value in self.__dict__.iteritems():
141 if name[0]!="_":
142 if out=="":
143 out=name+"="+str(value)
144 else:
145 out=out+","+name+"="+str(value)
146 return "("+out+")"
147
148 def __setattr__(self,name,value):
149 """
150 Defines attribute C{name} and assigns C{value}. If name does not start
151 with an underscore value has to be a valid Parameter.
152 """
153 name=name.replace(" ","_")
154 if name[0]!="_":
155 if value==None:
156 self.__dict__[name]=value
157 elif isinstance(value,ESySParameters):
158 self.__dict__[name]=value
159 elif isinstance(value,types.BooleanType):
160 self.__dict__[name]=value
161 elif isinstance(value,types.ListType):
162 self.__dict__[name]=_mkSameType(value)
163 elif isinstance(value,types.TupleType):
164 self.__dict__[name]=tuple(_mkSameType(value))
165 elif isinstance(value,types.BooleanType):
166 self.__dict__[name]=value
167 elif isinstance(value,types.IntType):
168 self.__dict__[name]=value
169 elif isinstance(value,types.FloatType):
170 self.__dict__[name]=value
171 elif isinstance(value,types.StringType) or isinstance(value,types.UnicodeType):
172 self.__dict__[name]=str(value)
173 else:
174 self.__dict__[name]=value
175 else:
176 self.__dict__[name]=value
177
178 def writeXML(self,iostream):
179 """
180 Writes the object as an XML object into an IO stream.
181 """
182 for name,value in self.__dict__.iteritems():
183 if name[0]!="_":
184 if isinstance(value,ESySParameters):
185 sequence=_PARAMETER_SEQUENCE_UNKNOWN
186 type=value.getTypeName()
187 iostream.write("<%s"%_COMPONENT)
188 if type!=None: iostream.write("%s=\"%s\""%(_COMPONENT_TYPE_ATTRIBUTE,type))
189 iostream.write(">\n<%s>%s</%s>\n<%s>%s</%s>\n"%(_NAME,name,_NAME,_DESCRIPTION,value.getDescription(),_DESCRIPTION))
190 value.writeXML(iostream)
191 iostream.write("</%s>"%_COMPONENT)
192 else:
193 if isinstance(value,types.ListType):
194 sequence=_PARAMETER_SEQUENCE_LIST
195 type=_getTypeNameOfList(value)
196 elif isinstance(value,types.TupleType):
197 sequence=_PARAMETER_SEQUENCE_TUPLE
198 type=_getTypeNameOfList(value)
199 else:
200 sequence=_PARAMETER_SEQUENCE_SINGLE
201 type=_getTypeName(value)
202 iostream.write("<%s %s=\"%s\" %s=\"%s\"><%s>%s</%s>\n"% \
203 (_PARAMETER,_PARAMETER_TYPE_ATTRIBUTE,type, \
204 _PARAMETER_SEQUENCE_ATTRIBUTE,sequence, \
205 _PARAMETER_ITEM,name,_PARAMETER_ITEM))
206 if type!=_PARAMETER_TYPE_UNKNOWN:
207 if sequence==_PARAMETER_SEQUENCE_LIST or sequence==_PARAMETER_SEQUENCE_TUPLE:
208 for i in value:
209 iostream.write("<%s>%s</%s>"%(_PARAMETER_VALUE,i.__str__(),_PARAMETER_VALUE))
210 elif sequence==_PARAMETER_SEQUENCE_SINGLE:
211 iostream.write("<%s>%s</%s>\n"%(_PARAMETER_VALUE,value.__str__(),_PARAMETER_VALUE))
212 iostream.write("</%s>\n"%_PARAMETER)
213
214
215 def writeProperties(self, iostream, nameSpace = None):
216 """
217 Writes the object as a property list to an IO stream.
218 """
219 if nameSpace != None and nameSpace != "":
220 nameSpace += ".";
221 for name,value in self.__dict__.iteritems():
222 if name[0]!="_":
223 if isinstance(value,ESySParameters):
224 value.writeProperties(iostream, name)
225 else:
226 if isinstance(value,types.ListType):
227 sequence=_PARAMETER_SEQUENCE_LIST
228 type=_getTypeNameOfList(value)
229 elif isinstance(value,types.TupleType):
230 sequence=_PARAMETER_SEQUENCE_TUPLE
231 type=_getTypeNameOfList(value)
232 else:
233 sequence=_PARAMETER_SEQUENCE_SINGLE
234 type=_getTypeName(value)
235 iostream.write("%s = %s\n" % (nameSpace + name, value.__str__()))
236
237 def writeESySXML(self,iostream):
238 """
239 Writes an ESyS XML file.
240 """
241 iostream.write("<?xml version=\"1.0\"?><ESyS>")
242 self.writeXML(iostream)
243 iostream.write("</ESyS>")
244
245 def readESySXMLFile(filename):
246 """
247 Reads an ESyS XML file and returns it as a ESySParameter object.
248 """
249 return _readParametersFromDOM(minidom.parse(filename).getElementsByTagName(_ESYS)[0])
250
251
252 _ESYS="ESyS"
253 _COMPONENT="Component"
254 _COMPONENT_TYPE_ATTRIBUTE="type"
255 _NAME="Name"
256 _DESCRIPTION="Description"
257 _PARAMETER="Parameter"
258 _PARAMETER_ITEM="Item"
259 _PARAMETER_VALUE="Value"
260 _PARAMETER_TYPE_ATTRIBUTE="type"
261 _PARAMETER_TYPE_REAL="real"
262 _PARAMETER_TYPE_INT="int"
263 _PARAMETER_TYPE_STRING="string"
264 _PARAMETER_TYPE_BOOL="bool"
265 _PARAMETER_TYPE_UNKNOWN="unknown"
266 _PARAMETER_SEQUENCE_ATTRIBUTE="sequence"
267 _PARAMETER_SEQUENCE_UNKNOWN="unknown"
268 _PARAMETER_SEQUENCE_SINGLE="single"
269 _PARAMETER_SEQUENCE_LIST="list"
270 _PARAMETER_SEQUENCE_TUPLE="tuple"
271
272
273 def _mkSameType(list):
274 """
275 Returns list where all items in the list have the same type.
276 """
277 out=[]
278 if len(list)>0:
279 type=0
280 for i in list:
281 if isinstance(i,types.BooleanType):
282 type=max(type,0)
283 elif isinstance(i,types.IntType):
284 type=max(type,1)
285 elif isinstance(i,types.FloatType):
286 type=max(type,2)
287 elif isinstance(i,types.StringType):
288 type=max(type,3)
289 else:
290 raise TypeError,"illegal item type"
291
292 for i in list:
293 if isinstance(i,types.BooleanType):
294 if type==0:
295 out.append(i)
296 elif type==1:
297 out.append(int(i))
298 elif type==2:
299 out.append(float(i))
300 else:
301 out.append(i.__str__())
302 elif isinstance(i,types.IntType):
303 if type==1:
304 out.append(i)
305 elif type==2:
306 out.append(float(i))
307 else:
308 out.append(i.__str__())
309 elif isinstance(i,types.FloatType):
310 if type==2:
311 out.append(i)
312 else:
313 out.append(i.__str__())
314 else:
315 out.append(i)
316 return out
317
318 def _getTypeNameOfList(values):
319 """
320 Returns the type of the parameters in list values.
321 """
322 if len(values)==0:
323 type=_PARAMETER_TYPE_UNKNOWN
324 else:
325 type=_getTypeName(values[0])
326 return type
327
328 def _getTypeName(value):
329 """
330 Returns the type of the parameter value.
331 """
332 if isinstance(value,types.FloatType):
333 type=_PARAMETER_TYPE_REAL
334 elif isinstance(value,types.BooleanType):
335 type=_PARAMETER_TYPE_BOOL
336 elif isinstance(value,types.IntType):
337 type=_PARAMETER_TYPE_INT
338 elif isinstance(value,types.StringType):
339 type=_PARAMETER_TYPE_STRING
340 else:
341 type=_PARAMETER_TYPE_UNKNOWN
342 return type
343
344
345 def _extractStrippedValue(dom):
346 """
347 Exracts a string from a DOM node.
348 """
349 out=""
350 for i in dom.childNodes:
351 s=i.nodeValue.strip()
352 if s!="\n": out+=s
353 return str(out)
354
355 def _readParametersFromDOM(dom):
356 out=ESySParameters()
357 for node in dom.childNodes:
358 if node.nodeType==node.ELEMENT_NODE:
359 if node.nodeName==_COMPONENT:
360 name=None
361 description="none"
362 type=None
363 if node.hasAttribute(_COMPONENT_TYPE_ATTRIBUTE): type=node.getAttribute(_COMPONENT_TYPE_ATTRIBUTE)
364 # find description and name:
365 for c_dom in node.childNodes:
366 if c_dom.nodeType==c_dom.ELEMENT_NODE:
367 if c_dom.tagName==_NAME: name=_extractStrippedValue(c_dom)
368 if c_dom.tagName==_DESCRIPTION: description=_extractStrippedValue(c_dom)
369 if name==None:
370 raise IOError,"name of component missing"
371 p=_readParametersFromDOM(node)
372 p.setDescription(description)
373 p.setType(type)
374 out.__setattr__(name,p)
375 elif node.nodeName==_PARAMETER:
376 if node.hasAttribute(_PARAMETER_TYPE_ATTRIBUTE):
377 type=node.getAttribute(_PARAMETER_TYPE_ATTRIBUTE)
378 if type==_PARAMETER_TYPE_UNKNOWN: type=_PARAMETER_TYPE_REAL
379 else:
380 type=_PARAMETER_TYPE_REAL
381 if node.hasAttribute(_PARAMETER_SEQUENCE_ATTRIBUTE):
382 sequence=node.getAttribute(_PARAMETER_SEQUENCE_ATTRIBUTE)
383 if sequence==_PARAMETER_SEQUENCE_UNKNOWN: sequence=_PARAMETER_SEQUENCE_SINGLE
384 else:
385 sequence=_PARAMETER_SEQUENCE_SINGLE
386 # get the name and values as list:
387 name=None
388 p=[]
389 for c_dom in node.childNodes:
390 if c_dom.nodeType==c_dom.ELEMENT_NODE:
391 if c_dom.nodeName==_PARAMETER_ITEM: name=_extractStrippedValue(c_dom)
392 if c_dom.nodeName==_PARAMETER_VALUE:
393 value=_extractStrippedValue(c_dom)
394 if type==_PARAMETER_TYPE_REAL:
395 p.append(atof(value))
396 elif type==_PARAMETER_TYPE_INT:
397 p.append(atoi(value))
398 elif type==_PARAMETER_TYPE_BOOL:
399 if value=="true" or value=="True" or value=="TRUE":
400 p.append(True)
401 elif value=="false" or value=="FALSE" or value=="False":
402 p.append(False)
403 else:
404 raise IOError,"cannot convert %s to bool"%value
405 elif type==_PARAMETER_TYPE_STRING:
406 p.append(value)
407 else:
408 raise IOError,"unknown parameter type %s"%type
409 if name==None: raise IOError,"Item tag missing"
410 if sequence==_PARAMETER_SEQUENCE_SINGLE:
411 if len(p)==0:
412 p=None
413 else:
414 p=p[0]
415 elif sequence==_PARAMETER_SEQUENCE_TUPLE:
416 if len(p)==0:
417 p=tuple()
418 else:
419 p=tuple(p)
420 elif sequence==_PARAMETER_SEQUENCE_LIST:
421 pass
422 else:
423 raise IOError,"unknown sequence attribute %s"%sequence
424 out.__setattr__(name,p)
425 return out
426
427 # test section:
428 if (__name__=="__main__"):
429 def test(parm):
430 if parm.parm1.gamma!=0. :
431 raise IOError,"unexpected value for parm.parm1.gamma"
432 if parm.parm1.dim!=2:
433 raise IOError,"unexpected value for parm.parm1.dim"
434 if parm.parm1.tol_v!=0.001:
435 raise IOError,"unexpected value for parm.parm1.tol_v"
436 if parm.parm1.output_file!="/tmp/u.%3.3d.dx":
437 raise IOError,"unexpected value for parm.parm1.output_file"
438 if parm.parm1.runFlag!=True:
439 raise IOError,"unexpected value for parm.parm1.runFlag"
440 if parm.parm1.T!=1.:
441 raise IOError,"unexpected value for parm.parm1.T"
442 if parm.parm1.x1[0]!=-1.:
443 raise IOError,"unexpected value for parm.parm1.x1[0]"
444 if parm.parm1.x1[1]!=2.:
445 raise IOError,"unexpected value for parm.parm1.x1[1]"
446 if parm.parm1.x2[0]!=10.:
447 raise IOError,"unexpected value for parm.parm1.x2[0]"
448 if parm.parm1.x2[1]!=11.:
449 raise IOError,"unexpected value for parm.parm1.x2[1]"
450 if parm.parm1.x3[0]!=-10:
451 raise IOError,"unexpected value for parm.parm1.x3[0]"
452 if parm.parm1.parm11.gamma1!=1.:
453 raise IOError,"unexpected value for parm.parm1.parm11.gamma1"
454 if parm.parm1.parm11.gamma2!=2.:
455 raise IOError,"unexpected value for parm.parm1.parm11.gamma2"
456 if parm.parm1.parm11.gamma3!=3.:
457 raise IOError,"unexpected value for parm.parm1.parm11.gamma3"
458 if parm.parm2.alpha!=814.:
459 raise IOError,"unexpected value for parm.parm2.alpha"
460
461 print "@@@ explicit construction"
462 parm=ESySParameters()
463 parm.parm1=ESySParameters()
464 parm.parm1.gamma=0.
465 parm.parm1.dim=2
466 parm.parm1.tol_v=0.001
467 parm.parm1.output_file="/tmp/u.%3.3d.dx"
468 parm.parm1.runFlag=True
469 parm.parm1.T=1.
470 parm.parm1.x1=[-1.,2]
471 parm.parm1.x2=(10,11.)
472 parm.parm1.x3=(-10.,)
473 parm.parm1.parm11=ESySParameters()
474 parm.parm1.parm11.gamma1=1.
475 parm.parm1.parm11.gamma2=2.
476 parm.parm1.parm11.gamma3=3.
477 parm.parm2=ESySParameters()
478 parm.parm2.alpha=814.
479 print parm
480 test(parm)
481 print "@@@ read and write:"
482 parm.writeESySXML(file("/tmp/test.xml",mode="w"))
483 parm.writeProperties(file("/tmp/test.dat",mode="w"))
484 parm2=readESySXMLFile("/tmp/test.xml")
485 print parm2
486 test(parm2)
487 print "@@@ file"
488 file("/tmp/test2.xml","w").write("""<?xml version="1.0"?>
489 <ESyS>
490 <Component type="Geodynamics">
491 <Name>parm1</Name>
492 <Description>
493 a few examples of parameters
494 </Description>
495 <Parameter><Item>gamma</Item><Value>0.</Value></Parameter>
496 <Parameter type="int"><Item>dim</Item><Value>2</Value></Parameter>
497 <Parameter type="real"><Item>tol_v</Item><Value>0.001</Value></Parameter>
498 <Parameter type="string"><Item>output_file</Item><Value>/tmp/u.%3.3d.dx</Value></Parameter>
499 <Parameter type="bool"><Item>runFlag</Item><Value>true</Value></Parameter>
500 <Parameter type="real" sequence="single"><Item>T</Item><Value>1.</Value><Value>2</Value></Parameter>
501 <Parameter type="real" sequence="list"><Item>x1</Item><Value>-1.</Value><Value>2</Value></Parameter>
502 <Parameter type="real" sequence="tuple"><Item>x2</Item><Value>10</Value><Value>11</Value></Parameter>
503 <Parameter sequence="tuple"><Item>x3</Item><Value>-10</Value></Parameter>
504 <Component>
505 <Name>parm11</Name>
506 <Description>
507 a sub compoment
508 </Description>
509 <Parameter><Item>gamma1</Item><Value>1.</Value></Parameter>
510 <Parameter><Item>gamma2</Item><Value>2.</Value></Parameter>
511 <Parameter><Item>gamma3</Item><Value>3.</Value></Parameter>
512 </Component>
513 </Component>
514 <Component type="Geodynamics">
515 <Name>parm2</Name>
516 <Description>
517 another component
518 </Description>
519 <Parameter><Item>alpha</Item><Value>0814</Value></Parameter>
520 </Component>
521 </ESyS>
522 """)
523 parm3=readESySXMLFile("/tmp/test2.xml")
524 print parm3
525 test(parm3)
526
527 # 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