1 | """ |
---|
2 | Validation tests for real-space simulation of I(q) |
---|
3 | |
---|
4 | @copyright: University of Tennessee, 2007 |
---|
5 | @license: This software is provided as part of the DANSE project |
---|
6 | """ |
---|
7 | import math, time, pylab |
---|
8 | |
---|
9 | try: |
---|
10 | import VolumeCanvas |
---|
11 | print "Testing local version" |
---|
12 | except: |
---|
13 | print "Testing installed version" |
---|
14 | import sans.realspace.VolumeCanvas as VolumeCanvas |
---|
15 | |
---|
16 | class Validator: |
---|
17 | |
---|
18 | def __init__(self): |
---|
19 | self.density = 0.1 |
---|
20 | self.canvas = None |
---|
21 | self.ana = None |
---|
22 | self.create() |
---|
23 | |
---|
24 | def create(self): |
---|
25 | pass |
---|
26 | |
---|
27 | def run_sim2D(self, qx, qy, density=None): |
---|
28 | """ |
---|
29 | Calculate the mean and error of the simulation |
---|
30 | @param q: q-value to calculate at |
---|
31 | @param density: point density of simulation |
---|
32 | #return: mean, error |
---|
33 | """ |
---|
34 | if not density == None: |
---|
35 | self.density = density |
---|
36 | self.create() |
---|
37 | |
---|
38 | return self.canvas.getIq2DError(qx, qy) |
---|
39 | |
---|
40 | def run_sim(self, q, density=None): |
---|
41 | """ |
---|
42 | Calculate the mean and error of the simulation |
---|
43 | @param q: q-value to calculate at |
---|
44 | @param density: point density of simulation |
---|
45 | #return: mean, error |
---|
46 | """ |
---|
47 | if not density == None: |
---|
48 | self.density = density |
---|
49 | self.create() |
---|
50 | |
---|
51 | return self.canvas.getIqError(q) |
---|
52 | |
---|
53 | def run_ana2D(self, qx, qy): |
---|
54 | """ |
---|
55 | Return analytical value |
---|
56 | @param q: q-value to evaluate at [float] |
---|
57 | @return: analytical output [float] |
---|
58 | """ |
---|
59 | return self.ana.runXY([qx, qy]) |
---|
60 | |
---|
61 | def run_ana(self, q): |
---|
62 | """ |
---|
63 | Return analytical value |
---|
64 | @param q: q-value to evaluate at [float] |
---|
65 | @return: analytical output [float] |
---|
66 | """ |
---|
67 | return self.ana.run(q) |
---|
68 | |
---|
69 | class SphereValidator(Validator): |
---|
70 | |
---|
71 | def __init__(self, radius=15, density = 0.01): |
---|
72 | from sans.models.SphereModel import SphereModel |
---|
73 | |
---|
74 | self.name = 'sphere' |
---|
75 | self.radius = radius |
---|
76 | self.density = density |
---|
77 | |
---|
78 | self.ana = SphereModel() |
---|
79 | self.ana.setParam('scale', 1.0) |
---|
80 | self.ana.setParam('contrast', 1.0) |
---|
81 | self.ana.setParam('background', 0.0) |
---|
82 | self.ana.setParam('radius', radius) |
---|
83 | self.create() |
---|
84 | |
---|
85 | def create(self): |
---|
86 | canvas = VolumeCanvas.VolumeCanvas() |
---|
87 | canvas.setParam('lores_density', self.density) |
---|
88 | handle = canvas.add('sphere') |
---|
89 | canvas.setParam('%s.radius' % handle, self.radius) |
---|
90 | canvas.setParam('scale' , 1.0) |
---|
91 | canvas.setParam('%s.contrast' % handle, 1.0) |
---|
92 | canvas.setParam('background' , 0.0) |
---|
93 | self.canvas = canvas |
---|
94 | |
---|
95 | class CylinderValidator(Validator): |
---|
96 | |
---|
97 | def __init__(self, radius=15, length=100, density = 0.01): |
---|
98 | from sans.models.CylinderModel import CylinderModel |
---|
99 | |
---|
100 | self.name = 'cylinder' |
---|
101 | self.radius = radius |
---|
102 | self.length = length |
---|
103 | self.density = density |
---|
104 | |
---|
105 | self.ana = CylinderModel() |
---|
106 | self.ana.setParam('scale', 1.0) |
---|
107 | self.ana.setParam('contrast', 1.0) |
---|
108 | self.ana.setParam('background', 0.0) |
---|
109 | self.ana.setParam('radius', radius) |
---|
110 | self.ana.setParam('length', length) |
---|
111 | self.ana.setParam('cyl_theta', math.pi/2.0) |
---|
112 | self.ana.setParam('cyl_phi', math.pi/2.0) |
---|
113 | self.create() |
---|
114 | |
---|
115 | def create(self): |
---|
116 | canvas = VolumeCanvas.VolumeCanvas() |
---|
117 | canvas.setParam('lores_density', self.density) |
---|
118 | handle = canvas.add('cylinder') |
---|
119 | canvas.setParam('%s.radius' % handle, self.radius) |
---|
120 | canvas.setParam('%s.length' % handle, self.length) |
---|
121 | canvas.setParam('scale' , 1.0) |
---|
122 | canvas.setParam('%s.contrast' % handle, 1.0) |
---|
123 | canvas.setParam('background' , 0.0) |
---|
124 | self.canvas = canvas |
---|
125 | |
---|
126 | class EllipsoidValidator(Validator): |
---|
127 | |
---|
128 | def __init__(self, radius_a=60, radius_b=10, density = 0.01): |
---|
129 | from sans.models.EllipsoidModel import EllipsoidModel |
---|
130 | #from sans.models.SphereModel import SphereModel |
---|
131 | |
---|
132 | self.name = 'ellipsoid' |
---|
133 | self.radius_a = radius_a |
---|
134 | self.radius_b = radius_b |
---|
135 | self.density = density |
---|
136 | |
---|
137 | self.ana = EllipsoidModel() |
---|
138 | #self.ana = SphereModel() |
---|
139 | self.ana.setParam('scale', 1.0) |
---|
140 | self.ana.setParam('contrast', 1.0) |
---|
141 | self.ana.setParam('background', 0.0) |
---|
142 | self.ana.setParam('radius_a', radius_a) |
---|
143 | self.ana.setParam('radius_b', radius_b) |
---|
144 | #self.ana.setParam('radius', radius_a) |
---|
145 | |
---|
146 | # Default orientation is there=1.57, phi=0 |
---|
147 | # Radius_a is along the x direction |
---|
148 | |
---|
149 | self.create() |
---|
150 | |
---|
151 | def create(self): |
---|
152 | canvas = VolumeCanvas.VolumeCanvas() |
---|
153 | canvas.setParam('lores_density', self.density) |
---|
154 | handle = canvas.add('ellipsoid') |
---|
155 | canvas.setParam('%s.radius_x' % handle, self.radius_a) |
---|
156 | canvas.setParam('%s.radius_y' % handle, self.radius_b) |
---|
157 | canvas.setParam('%s.radius_z' % handle, self.radius_b) |
---|
158 | canvas.setParam('scale' , 1.0) |
---|
159 | canvas.setParam('%s.contrast' % handle, 1.0) |
---|
160 | canvas.setParam('background' , 0.0) |
---|
161 | self.canvas = canvas |
---|
162 | |
---|
163 | class HelixValidator(Validator): |
---|
164 | |
---|
165 | def __init__(self, density = 0.01): |
---|
166 | self.name = 'helix' |
---|
167 | self.density = density |
---|
168 | self.create() |
---|
169 | |
---|
170 | def create(self): |
---|
171 | canvas = VolumeCanvas.VolumeCanvas() |
---|
172 | canvas.setParam('lores_density', self.density) |
---|
173 | handle = canvas.add('singlehelix') |
---|
174 | canvas.setParam('scale' , 1.0) |
---|
175 | canvas.setParam('%s.contrast' % handle, 1.0) |
---|
176 | canvas.setParam('background' , 0.0) |
---|
177 | self.canvas = canvas |
---|
178 | # just to write the parameters to the output file |
---|
179 | self.ana = canvas |
---|
180 | |
---|
181 | def run_ana(self, q): |
---|
182 | return 1 |
---|
183 | |
---|
184 | |
---|
185 | class CoreShellValidator(Validator): |
---|
186 | |
---|
187 | def __init__(self, radius=15, thickness=5, density = 0.01): |
---|
188 | from sans.models.CoreShellModel import CoreShellModel |
---|
189 | |
---|
190 | self.name = 'coreshell' |
---|
191 | self.radius = radius |
---|
192 | |
---|
193 | core_vol = 4.0/3.0*math.pi*radius*radius*radius |
---|
194 | self.outer_radius = radius+thickness |
---|
195 | shell_vol = 4.0/3.0*math.pi*self.outer_radius*self.outer_radius*self.outer_radius - core_vol |
---|
196 | self.shell_sld = -1.0*core_vol/shell_vol |
---|
197 | |
---|
198 | self.density = density |
---|
199 | |
---|
200 | # Core-shell |
---|
201 | sphere = CoreShellModel() |
---|
202 | # Core radius |
---|
203 | sphere.setParam('radius', self.radius) |
---|
204 | # Shell thickness |
---|
205 | sphere.setParam('thickness', thickness) |
---|
206 | sphere.setParam('core_sld', 1.0) |
---|
207 | sphere.setParam('shell_sld', self.shell_sld) |
---|
208 | sphere.setParam('solvent_sld', 0.0) |
---|
209 | sphere.setParam('background', 0.0) |
---|
210 | sphere.setParam('scale', 1.0) |
---|
211 | self.ana = sphere |
---|
212 | self.create() |
---|
213 | |
---|
214 | def create(self): |
---|
215 | canvas = VolumeCanvas.VolumeCanvas() |
---|
216 | canvas.setParam('lores_density', self.density) |
---|
217 | |
---|
218 | handle = canvas.add('sphere') |
---|
219 | canvas.setParam('%s.radius' % handle, self.outer_radius) |
---|
220 | canvas.setParam('%s.contrast' % handle, self.shell_sld) |
---|
221 | |
---|
222 | handle2 = canvas.add('sphere') |
---|
223 | canvas.setParam('%s.radius' % handle2, self.radius) |
---|
224 | canvas.setParam('%s.contrast' % handle2, 1.0) |
---|
225 | |
---|
226 | canvas.setParam('scale' , 1.0) |
---|
227 | canvas.setParam('background' , 0.0) |
---|
228 | self.canvas = canvas |
---|
229 | |
---|
230 | def validate_model(validator, q_min, q_max, n_q): |
---|
231 | """ |
---|
232 | Validate a model |
---|
233 | An output file containing a comparison between |
---|
234 | simulation and the analytical solution will be |
---|
235 | produced. |
---|
236 | |
---|
237 | @param validator: validator object |
---|
238 | @param q_min: minimum q |
---|
239 | @param q_max: maximum q |
---|
240 | @param n_q: number of q points |
---|
241 | @param N: number of times to evaluate each simulation point |
---|
242 | """ |
---|
243 | |
---|
244 | q_list = pylab.arange(q_min, q_max*1.0001, (q_max-q_min)/(n_q-1)) |
---|
245 | |
---|
246 | output = open('%s_d=%g_Iq.txt' % (validator.name, validator.density), 'w') |
---|
247 | output.write("PARS: %s\n" % validator.ana.params) |
---|
248 | output.write("<q> <ana> <sim> <err>\n") |
---|
249 | for q in q_list: |
---|
250 | ana = validator.run_ana(q) |
---|
251 | sim, err = validator.run_sim(q) |
---|
252 | print "q=%-g ana=%-g sim=%-g err=%-g diff=%-g (%-g) %s" % (q, ana, sim, err, |
---|
253 | (sim-ana), sim/ana, str(math.fabs(sim-ana)>err)) |
---|
254 | output.write("%g %g %g %g\n" % (q, ana, sim, err)) |
---|
255 | output.close() |
---|
256 | |
---|
257 | def validate_model_2D(validator, q_min, q_max, phi, n_q): |
---|
258 | """ |
---|
259 | Validate a model |
---|
260 | An output file containing a comparison between |
---|
261 | simulation and the analytical solution will be |
---|
262 | produced. |
---|
263 | |
---|
264 | @param validator: validator object |
---|
265 | @param q_min: minimum q |
---|
266 | @param q_max: maximum q |
---|
267 | @param n_q: number of q points |
---|
268 | @param N: number of times to evaluate each simulation point |
---|
269 | """ |
---|
270 | |
---|
271 | q_list = pylab.arange(q_min, q_max*1.0001, (q_max-q_min)/(n_q-1)) |
---|
272 | |
---|
273 | output = open('%s_d=%g_Iq2D.txt' % (validator.name, validator.density), 'w') |
---|
274 | output.write("PARS: %s\n" % validator.ana.params) |
---|
275 | output.write("<q> <ana> <sim> <err>\n") |
---|
276 | t_0 = time.time() |
---|
277 | for q in q_list: |
---|
278 | ana = validator.run_ana2D(q*math.cos(phi), q*math.sin(phi)) |
---|
279 | sim, err = validator.run_sim2D(q*math.cos(phi), q*math.sin(phi)) |
---|
280 | print "q=%-g ana=%-g sim=%-g err=%-g diff=%-g (%-g) %s" % (q, ana, sim, err, |
---|
281 | (sim-ana), sim/ana, str(math.fabs(sim-ana)>err)) |
---|
282 | output.write("%g %g %g %g\n" % (q, ana, sim, err)) |
---|
283 | print "Time elapsed: ", time.time()-t_0 |
---|
284 | output.close() |
---|
285 | |
---|
286 | def check_density(validator, q, d_min, d_max, n_d): |
---|
287 | """ |
---|
288 | Check simulation output as a function of the density |
---|
289 | An output file containing a comparison between |
---|
290 | simulation and the analytical solution will be |
---|
291 | produced. |
---|
292 | |
---|
293 | @param validator: validator object |
---|
294 | @param q: q-value to evaluate at |
---|
295 | @param d_min: minimum density |
---|
296 | @param d_max: maximum density |
---|
297 | @param n_d: number of density points |
---|
298 | @param N: number of times to evaluate each simulation point |
---|
299 | """ |
---|
300 | d_list = pylab.arange(d_min, d_max*1.0001, (d_max-d_min)/(n_d-1.0)) |
---|
301 | |
---|
302 | output = open('%s_%g_density.txt' % (validator.name, q), 'w') |
---|
303 | output.write("PARS: %s\n" % validator.ana.params) |
---|
304 | output.write("<density> <ana_d> <sim_d> <err_d>\n") |
---|
305 | ana = validator.run_ana(q) |
---|
306 | for d in d_list: |
---|
307 | sim, err = validator.run_sim(q, density=d) |
---|
308 | print "d=%-g ana=%-g sim=%-g err=%-g diff=%-g (%g) %s" % \ |
---|
309 | (d, ana, sim, err, (sim-ana), (sim-ana)/ana, |
---|
310 | str(math.fabs(sim-ana)>err)) |
---|
311 | output.write("%g %g %g %g \n" % (d, ana, sim, err)) |
---|
312 | output.close() |
---|
313 | |
---|
314 | |
---|
315 | if __name__ == '__main__': |
---|
316 | |
---|
317 | # 2D: Density=5, 71.2 secs for 50 points |
---|
318 | #vali = CoreShellValidator(radius = 15, thickness=5, density = 5.0) |
---|
319 | #validate_model(vali, q_min=0.001, q_max=1, n_q=50) |
---|
320 | #validate_model_2D(vali, q_min=0.001, q_max=1, phi=1.0, n_q=50) |
---|
321 | |
---|
322 | # 2D: Density=2, 11.1 secs for 25 points |
---|
323 | #vali = SphereValidator(radius = 20, density = 0.02) |
---|
324 | #validate_model(vali, q_min=0.001, q_max=0.5, n_q=25) |
---|
325 | #vali = SphereValidator(radius = 20, density = 2.0) |
---|
326 | #validate_model_2D(vali, q_min=0.001, q_max=0.5, phi=1.0, n_q=25) |
---|
327 | |
---|
328 | # 2D: Density=1, 19.4 secs for 25 points |
---|
329 | # 2D: Density=0.5, 9.8 secs for 25 points |
---|
330 | #vali = CylinderValidator(radius = 20, length=100, density = 0.1) |
---|
331 | #validate_model(vali, q_min=0.001, q_max=0.5, n_q=25) |
---|
332 | vali = CylinderValidator(radius = 20, length=100, density = 0.5) |
---|
333 | validate_model_2D(vali, q_min=0.001, q_max=0.2, phi=1.0, n_q=25) |
---|
334 | |
---|
335 | # 2D: Density=0.5, 2.26 secs for 25 points |
---|
336 | #vali = EllipsoidValidator(radius_a = 20, radius_b=15, density = 0.05) |
---|
337 | #validate_model(vali, q_min=0.001, q_max=0.5, n_q=25) |
---|
338 | #vali = EllipsoidValidator(radius_a = 20, radius_b=15, density = 0.5) |
---|
339 | #validate_model_2D(vali, q_min=0.001, q_max=0.5, phi=1.0, n_q=25) |
---|
340 | |
---|
341 | #vali = HelixValidator(density = 0.05) |
---|
342 | #validate_model(vali, q_min=0.001, q_max=0.5, n_q=25) |
---|
343 | |
---|
344 | |
---|