[ba1d1e9] | 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 |
---|
[a2c1196] | 20 | self.canvas = None |
---|
| 21 | self.ana = None |
---|
[ba1d1e9] | 22 | self.create() |
---|
| 23 | |
---|
| 24 | def create(self): |
---|
| 25 | pass |
---|
| 26 | |
---|
[a2c1196] | 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 | |
---|
[ba1d1e9] | 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 | |
---|
[a2c1196] | 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 | |
---|
[ba1d1e9] | 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) |
---|
[f980d4a] | 111 | self.ana.setParam('cyl_theta', math.pi/2.0) |
---|
| 112 | self.ana.setParam('cyl_phi', math.pi/2.0) |
---|
[ba1d1e9] | 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) |
---|
[f980d4a] | 145 | |
---|
| 146 | # Default orientation is there=1.57, phi=0 |
---|
| 147 | # Radius_a is along the x direction |
---|
[ba1d1e9] | 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 | |
---|
[a2c1196] | 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 | |
---|
[ba1d1e9] | 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__': |
---|
[a2c1196] | 316 | |
---|
| 317 | # 2D: Density=5, 71.2 secs for 50 points |
---|
[f980d4a] | 318 | #vali = CoreShellValidator(radius = 15, thickness=5, density = 5.0) |
---|
[a2c1196] | 319 | #validate_model(vali, q_min=0.001, q_max=1, n_q=50) |
---|
[f980d4a] | 320 | #validate_model_2D(vali, q_min=0.001, q_max=1, phi=1.0, n_q=50) |
---|
[ba1d1e9] | 321 | |
---|
[a2c1196] | 322 | # 2D: Density=2, 11.1 secs for 25 points |
---|
[ba1d1e9] | 323 | #vali = SphereValidator(radius = 20, density = 0.02) |
---|
[a2c1196] | 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) |
---|
[ba1d1e9] | 327 | |
---|
[a2c1196] | 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) |
---|
[f980d4a] | 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) |
---|
[ba1d1e9] | 334 | |
---|
[a2c1196] | 335 | # 2D: Density=0.5, 2.26 secs for 25 points |
---|
[ba1d1e9] | 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) |
---|
[a2c1196] | 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) |
---|
[ba1d1e9] | 340 | |
---|
| 341 | #vali = HelixValidator(density = 0.05) |
---|
| 342 | #validate_model(vali, q_min=0.001, q_max=0.5, n_q=25) |
---|
| 343 | |
---|
| 344 | |
---|