1 |
#!/usr/bin/python |
2 |
|
3 |
# $Id$ |
4 |
|
5 |
import unittest |
6 |
from esys.escript.modelframe import Model,Link,Simulation,ParameterSet,parse |
7 |
import math |
8 |
from cStringIO import StringIO |
9 |
from xml.dom import minidom |
10 |
|
11 |
class XMLDocumentTestCase(unittest.TestCase): |
12 |
|
13 |
def setUp(self): |
14 |
|
15 |
o1=ODETEST(debug=False) |
16 |
o1.u=10 |
17 |
o2=ODETEST(debug=False) |
18 |
o2.u=-10. |
19 |
o1.f=Link(o2,"u") |
20 |
o2.f=Link(o1,"u") |
21 |
m=Messenger() |
22 |
o1.dt=0.01 |
23 |
m.message=Link(o1) |
24 |
s=Simulation([o1,o2,m],debug=False) |
25 |
s.run() |
26 |
output = StringIO() |
27 |
s.writeXML(output) |
28 |
output.reset() |
29 |
outputList = output.readlines() |
30 |
self.xmlList = outputList |
31 |
|
32 |
def testFirstLine(self): |
33 |
firstLine = self.xmlList[0] |
34 |
self.assertEqual('<?xml version="1.0" ?>\n', firstLine) |
35 |
|
36 |
def testEsysHeader(self): |
37 |
header = self.xmlList[1] |
38 |
self.assertEqual('<ESys>\n', header) |
39 |
|
40 |
def testEsysFooter(self): |
41 |
footer = self.xmlList[-1] |
42 |
self.assertEqual('</ESys>\n', footer) |
43 |
|
44 |
def testSimulationHeader(self): |
45 |
pass |
46 |
|
47 |
def testSimulationFooter(self): |
48 |
pass |
49 |
|
50 |
class SimulationTestCase(unittest.TestCase): |
51 |
def setUp(self): |
52 |
o1=ODETEST(debug=False) |
53 |
o1.u=10 |
54 |
o2=ODETEST(debug=False) |
55 |
o2.u=-10. |
56 |
o1.f=Link(o2,"u") |
57 |
o2.f=Link(o1,"u") |
58 |
m=Messenger() |
59 |
o1.dt=0.01 |
60 |
m.message=Link(o1) |
61 |
self.s=Simulation([o1,o2,m],debug=False) |
62 |
self.s.run() |
63 |
output = StringIO() |
64 |
self.s.writeXML(output) |
65 |
output.reset() |
66 |
self.xml = output.read() |
67 |
|
68 |
def testSimulation(self): |
69 |
assert "<Simulation" in self.xml, "I should see a Simulation" |
70 |
|
71 |
def testParseAndInstanceOfSimulation(self): |
72 |
|
73 |
newSim = parse(self.xml) |
74 |
assert (isinstance (newSim, Simulation)) |
75 |
newout = StringIO() |
76 |
newSim.writeXML(newout) |
77 |
newout.reset() |
78 |
xml = newout.read() |
79 |
assert '<Simulation' in xml, "Missing a Simulation! It should be in this!" |
80 |
|
81 |
|
82 |
|
83 |
|
84 |
class LinkTestCase(unittest.TestCase): |
85 |
|
86 |
|
87 |
def setUp(self): |
88 |
|
89 |
self.o1=ODETEST(debug=False) |
90 |
#self.o1.u=10 |
91 |
self.o2=ODETEST(debug=False) |
92 |
self.o2.u=-10. |
93 |
self.o1.f=Link(self.o2,"u") |
94 |
self.o2.f=Link(self.o1,"u") |
95 |
self.o2.declareParameter(child=self.o1) |
96 |
|
97 |
def testLinkCreation(self): |
98 |
self.o1.f=Link(self.o2,"u") |
99 |
assert self.o1.f |
100 |
|
101 |
|
102 |
def testLinkValue(self): |
103 |
self.assertEqual(self.o1.f, -10) |
104 |
|
105 |
def testLinkTarget(self): |
106 |
pass |
107 |
|
108 |
def testLinkDefaultAttribute(self): |
109 |
Link(self.o2) |
110 |
|
111 |
def testLinkXML(self): |
112 |
s = StringIO() |
113 |
self.o2.writeXML(s) |
114 |
s.reset() |
115 |
xmlout = s.read() |
116 |
assert '<Link' in xmlout |
117 |
|
118 |
def testLinkTargetXML(self): |
119 |
pass |
120 |
|
121 |
class ParamaterSetTestCase(unittest.TestCase): |
122 |
|
123 |
|
124 |
def setUp(self): |
125 |
self.p = ParameterSet() |
126 |
self.p.declareParameter(gamma1=1.,gamma2=2.,gamma3=3.) |
127 |
|
128 |
def testParameterSetCreation(self): |
129 |
self.assertEqual(self.p.gamma1, 1.) |
130 |
|
131 |
def testParameterSetXMLCreation(self): |
132 |
s = StringIO() |
133 |
self.p.writeXML(s) |
134 |
s.reset() |
135 |
xmlout = s.read() |
136 |
assert ("gamma1" in xmlout) |
137 |
assert ("gamma2" in xmlout) |
138 |
assert ("gamma3" in xmlout) |
139 |
parsable = parse(xmlout) |
140 |
assert (isinstance (parsable, ParameterSet)) |
141 |
assert (self._dom().getElementsByTagName("ParameterSet")) |
142 |
|
143 |
def testParameterSetFromXML(self): |
144 |
doc = self._class() |
145 |
pset = ParameterSet.fromDom(self._dom().getElementsByTagName("ParameterSet")[0]) |
146 |
assert (isinstance(pset, ParameterSet)) |
147 |
assert (isinstance(doc, ParameterSet)) |
148 |
self.assertEqual(self.p.gamma1,doc.gamma1) |
149 |
|
150 |
|
151 |
def testParameterSetWithChildrenFromXML(self): |
152 |
p2 = ParameterSet() |
153 |
p2.declareParameter(s="abc", f=3.) |
154 |
self.p.declareParameter(child=p2) |
155 |
doc = self._class() |
156 |
#pset = ParameterSet.fromDom(doc.getElementsByTagName("ParameterSet")[0]) |
157 |
self.assertEqual(self.p.child.f, doc.child.f) |
158 |
|
159 |
def testParameterSetChild(self): |
160 |
p2 = ParameterSet() |
161 |
p2.declareParameter(s="abc", f=3.) |
162 |
self.p.declareParameter(child=p2) |
163 |
self.assertEqual(self.p.child.s, "abc") |
164 |
self.assertEqual(self.p.child.f, 3.) |
165 |
|
166 |
def _dom(self): |
167 |
s = StringIO() |
168 |
self.p.writeXML(s) |
169 |
s.reset() |
170 |
xmlout = s.read() |
171 |
doc = minidom.parseString(xmlout) |
172 |
return doc |
173 |
|
174 |
def _class(self): |
175 |
s = StringIO() |
176 |
self.p.writeXML(s) |
177 |
s.reset() |
178 |
xmlout = s.read() |
179 |
doc = parse(xmlout) |
180 |
return doc |
181 |
|
182 |
class ModeltoDomTestCase(unittest.TestCase): |
183 |
|
184 |
def _class(self): |
185 |
# returns a modelframe class, generated from the xml |
186 |
s = StringIO() |
187 |
self.o1.writeXML(s) |
188 |
s.reset() |
189 |
self.xmlout = s.read() |
190 |
doc = parse(self.xmlout) |
191 |
return doc |
192 |
|
193 |
def _dom(self): |
194 |
# returns a minidom dom element, generated from the xml |
195 |
s = StringIO() |
196 |
self.o1.writeXML(s) |
197 |
s.reset() |
198 |
self.xmlout = s.read() |
199 |
doc = minidom.parseString(self.xmlout) |
200 |
return doc |
201 |
|
202 |
def setUp(self): |
203 |
self.o1=ODETEST(debug=False) |
204 |
self.o1.message='blah' |
205 |
|
206 |
def testModelExists(self): |
207 |
modeldoc = self._class() |
208 |
assert (isinstance, (modeldoc, Model)) |
209 |
assert self._dom().getElementsByTagName("Model") |
210 |
|
211 |
def testModelhasID(self): |
212 |
assert int(self._dom().getElementsByTagName("Model")[0].getAttribute("id"))>99 |
213 |
|
214 |
class ModeltoDomTestCase(unittest.TestCase): |
215 |
def _xml(self, modulename, modelname): |
216 |
# returns a modelframe class, generated from the xml |
217 |
return '''<?xml version="1.0" ?> |
218 |
<ESys> <Simulation type="Simulation"> <Component rank="0"> |
219 |
|
220 |
<Model id="127" module="%s" type="%s"> |
221 |
|
222 |
<Parameter type="float"> <Name> a </Name> <Value> 0.9 </Value> </Parameter> |
223 |
<Parameter type="Link"> <Name> f </Name> <Value> <Link> <Target> 128 </Target> |
224 |
<Attribute> u </Attribute> </Link> </Value> </Parameter> <Parameter |
225 |
type="float"> <Name> tend </Name> <Value> |
226 |
1.0 </Value> </Parameter> <Parameter type="int"> <Name> u </Name> <Value> 10 |
227 |
</Value> </Parameter> <Parameter type="float"> <Name> tol </Name> <Value> |
228 |
1e-08 </Value> </Parameter> <Parameter type="float"> <Name> dt </Name> |
229 |
<Value> |
230 |
0.01 </Value> </Parameter> <Parameter type="str"> <Name> message </Name> |
231 |
<Value> current error = 9.516258e-01 </Value> </Parameter> </Model> |
232 |
</Component> <Component rank="1"> <Model id="128" type="ODETEST"> <Parameter |
233 |
type="float"> <Name> a </Name> <Value> |
234 |
0.9 </Value> </Parameter> <Parameter type="Link"> <Name> f </Name> <Value> |
235 |
<Link> <Target> 127 </Target> <Attribute> u </Attribute> </Link> </Value> |
236 |
</Parameter> <Parameter type="float"> <Name> tend </Name> <Value> |
237 |
1.0 </Value> </Parameter> <Parameter type="float"> <Name> u </Name> <Value> |
238 |
-10.0 </Value> </Parameter> <Parameter type="float"> <Name> tol </Name> |
239 |
<Value> 1e-08 </Value> </Parameter> <Parameter type="float"> <Name> dt |
240 |
</Name> <Value> |
241 |
0.1 </Value> </Parameter> <Parameter type="str"> <Name> message </Name> <Value> |
242 |
current error = 1.904837e+01 </Value> </Parameter> </Model> </Component> |
243 |
<Component rank="2"> <Model id="129" type="Messenger"> <Parameter |
244 |
type="Link"> <Name> message </Name> <Value> <Link> <Target> 127 </Target> |
245 |
<Attribute> message </Attribute> </Link> </Value> </Parameter> </Model> |
246 |
</Component> </Simulation> <Model id="128" type="ODETEST"> <Parameter |
247 |
type="float"> <Name> a </Name> <Value> |
248 |
0.9 </Value> </Parameter> <Parameter type="Link"> <Name> f </Name> <Value> |
249 |
<Link> <Target> 127 </Target> <Attribute> u </Attribute> </Link> </Value> |
250 |
</Parameter> <Parameter type="float"> <Name> tend </Name> <Value> |
251 |
1.0 </Value> </Parameter> <Parameter type="float"> <Name> u </Name> <Value> |
252 |
-10.0 </Value> </Parameter> <Parameter type="float"> <Name> tol </Name> |
253 |
<Value> 1e-08 </Value> </Parameter> <Parameter type="float"> <Name> dt |
254 |
</Name> <Value> |
255 |
0.1 </Value> </Parameter> <Parameter type="str"> <Name> message </Name> <Value> |
256 |
current error = 1.904837e+01 </Value> </Parameter> </Model> <Model id="127" |
257 |
type="ODETEST"> <Parameter type="float"> <Name> a </Name> <Value> |
258 |
0.9 </Value> </Parameter> <Parameter type="Link"> <Name> f </Name> <Value> |
259 |
<Link> <Target> 128 </Target> <Attribute> u </Attribute> </Link> </Value> |
260 |
</Parameter> <Parameter type="float"> <Name> tend </Name> <Value> |
261 |
1.0 </Value> </Parameter> <Parameter type="int"> <Name> u </Name> <Value> 10 |
262 |
</Value> </Parameter> <Parameter type="float"> <Name> tol </Name> <Value> |
263 |
1e-08 </Value> </Parameter> <Parameter type="float"> <Name> dt </Name> |
264 |
<Value> |
265 |
0.01 </Value> </Parameter> <Parameter type="str"> <Name> message </Name> |
266 |
<Value> current error = 9.516258e-01 </Value> </Parameter> </Model> <Model |
267 |
id="127" type="ODETEST"> <Parameter type="float"> <Name> a </Name> <Value> |
268 |
0.9 </Value> </Parameter> <Parameter type="Link"> <Name> f </Name> <Value> |
269 |
<Link> <Target> 128 </Target> <Attribute> u </Attribute> </Link> </Value> |
270 |
</Parameter> <Parameter type="float"> <Name> tend </Name> <Value> |
271 |
1.0 </Value> </Parameter> <Parameter type="int"> <Name> u </Name> <Value> 10 |
272 |
</Value> </Parameter> <Parameter type="float"> <Name> tol </Name> <Value> |
273 |
1e-08 </Value> </Parameter> <Parameter type="float"> <Name> dt </Name> |
274 |
<Value> |
275 |
0.01 </Value> </Parameter> <Parameter type="str"> <Name> message </Name> |
276 |
<Value> current error = 9.516258e-01 </Value> </Parameter> </Model> </ESys> |
277 |
''' % (modulename, modelname) |
278 |
|
279 |
def testModuleAttribute(self): |
280 |
modeldoc = parse(self._xml('test_xml', 'ODETEST')) |
281 |
|
282 |
def testModuleAttributeFails(self): |
283 |
try: |
284 |
modeldoc = parse(self._xml('a', 'b')) |
285 |
except ImportError: |
286 |
return # correct |
287 |
|
288 |
assert False, "This test should have resulted in an ImportError" |
289 |
|
290 |
class Messenger(Model): |
291 |
def __init__(self, *args, **kwargs): |
292 |
Model.__init__(self, *args, **kwargs) |
293 |
self.declareParameter(message="none") |
294 |
|
295 |
def doInitialization(self): |
296 |
self.__t=0 |
297 |
#print "I start talking now!" |
298 |
|
299 |
def doStepPostprocessing(self,dt): |
300 |
self.__t+=dt |
301 |
#print "Message (time %e) : %s "%(self.__t,self.message) |
302 |
|
303 |
def doFinalization(self): |
304 |
#print "I have no more to say!" |
305 |
pass |
306 |
|
307 |
|
308 |
|
309 |
class ODETEST(Model): |
310 |
""" implements a solver for the ODE |
311 |
|
312 |
du/dt=a*u+f(t) |
313 |
|
314 |
we use a implicit euler scheme : |
315 |
|
316 |
u_n-u_{n-1}= dt*a u_n + st*f(t_n) |
317 |
|
318 |
to get u_n we run an iterative process |
319 |
|
320 |
u_{n.k}=u_{n-1}+dt*(a u_{n.i-1} + f(t_n)) |
321 |
|
322 |
|
323 |
input for this model are step size dt, end time tend and a value for |
324 |
a, f and initial value for u. we need also a tolerance tol for a |
325 |
stopping criterion. |
326 |
|
327 |
""" |
328 |
|
329 |
def __init__(self, *args, **kwargs): |
330 |
Model.__init__(self, *args, **kwargs) |
331 |
self.declareParameter(tend=1.,dt=0.1,a=0.9,u=10.,f=0.,message="",tol=1.e-8) |
332 |
|
333 |
def doInitialization(self): |
334 |
self.__tn=0 |
335 |
self.__iter=0 |
336 |
|
337 |
def doStepPreprocessing(self,dt): |
338 |
self.__iter=0 |
339 |
self.__u_last=self.u |
340 |
|
341 |
def doStep(self,dt): |
342 |
self.__iter+=1 |
343 |
self.__u_old=self.u |
344 |
self.u=self.__u_last+dt*(self.a*self.__u_old+self.f) |
345 |
|
346 |
def terminate(self): |
347 |
if self.__iter<1: |
348 |
return False |
349 |
else: |
350 |
return abs(self.__u_old-self.u)<self.tol*abs(self.u) |
351 |
|
352 |
def doStepPostprocessing(self,dt): |
353 |
self.__tn+=dt |
354 |
self.message="current error = %e"%abs(self.u-10.*math.exp((self.a-1.)*self.__tn)) |
355 |
|
356 |
def getSafeTimeStepSize(self,dt): |
357 |
return min(self.dt,1./(abs(self.a)+1.)) |
358 |
|
359 |
def finalize(self): |
360 |
return self.__tn>=self.tend |
361 |
|
362 |
|
363 |
|
364 |
if __name__ == "__main__": |
365 |
from test_xml import Messenger, ODETEST |
366 |
unittest.main() |
367 |
|