source: sasmodels/compare-new.py @ 5d4777d

core_shell_microgelscostrafo411magnetic_modelrelease_v0.94release_v0.95ticket-1257-vesicle-productticket_1156ticket_1265_superballticket_822_more_unit_tests
Last change on this file since 5d4777d was 5d4777d, checked in by Paul Kienzle <pkienzle@…>, 10 years ago

reorganize, check and update models

  • Property mode set to 100755
File size: 11.4 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4import sys
5
6import numpy as np
7
8from sasmodels.bumps_model import BumpsModel, plot_data, tic
9from sasmodels import gpu, dll
10from sasmodels.convert import revert_model
11
12
13def sasview_model(modelname, **pars):
14    """
15    Load a sasview model given the model name.
16    """
17    modelname = modelname
18    sans = __import__('sans.models.'+modelname)
19    ModelClass = getattr(getattr(sans.models,modelname,None),modelname,None)
20    if ModelClass is None:
21        raise ValueError("could not find model %r in sans.models"%modelname)
22    model = ModelClass()
23
24    for k,v in pars.items():
25        if k.endswith("_pd"):
26            model.dispersion[k[:-3]]['width'] = v
27        elif k.endswith("_pd_n"):
28            model.dispersion[k[:-5]]['npts'] = v
29        elif k.endswith("_pd_nsigma"):
30            model.dispersion[k[:-10]]['nsigmas'] = v
31        elif k.endswith("_pd_type"):
32            model.dispersion[k[:-8]]['type'] = v
33        else:
34            model.setParam(k, v)
35    return model
36
37def load_opencl(modelname, dtype='single'):
38    sasmodels = __import__('sasmodels.models.'+modelname)
39    module = getattr(sasmodels.models, modelname, None)
40    kernel = gpu.load_model(module, dtype=dtype)
41    return kernel
42
43def load_dll(modelname, dtype='single'):
44    sasmodels = __import__('sasmodels.models.'+modelname)
45    module = getattr(sasmodels.models, modelname, None)
46    kernel = dll.load_model(module, dtype=dtype)
47    return kernel
48
49def randomize(p, v):
50    """
51    Randomizing pars using sasview names.
52    Guessing at angles and slds.
53    """
54    if any(p.endswith(s) for s in ('_pd_n','_pd_nsigmas','_pd_type')):
55        return v
56    if any(s in p for s in ('theta','phi','psi')):
57        return np.random.randint(0,90)
58    elif any(s in p for s in ('sld','Sld','SLD')):
59        return np.random.rand()*1e-5
60    else:
61        return np.random.rand()
62
63def parlist(pars):
64    return "\n".join("%s: %s"%(p,v) for p,v in sorted(pars.items()))
65
66def suppress_pd(pars):
67    """
68    Suppress theta_pd for now until the normalization is resolved.
69
70    May also suppress complete polydispersity of the model to test
71    models more quickly.
72    """
73    for p in pars:
74        if p.endswith("_pd"): pars[p] = 0
75
76def compare(gpuname, gpupars, Ncpu, Ngpu, opts):
77    #from sasmodels.core import load_data
78    #data = load_data('December/DEC07098.DAT')
79    qmax = 1.0 if '-highq' in opts else (0.2 if '-midq' in opts else 0.05)
80    if "-1d" in opts:
81        from sasmodels.bumps_model import empty_data1D
82        qmax = np.log10(qmax)
83        data = empty_data1D(np.logspace(qmax-3, qmax, 128))
84    else:
85        from sasmodels.bumps_model import empty_data2D, set_beam_stop
86        data = empty_data2D(np.linspace(-qmax, qmax, 128))
87        set_beam_stop(data, 0.004)
88    is2D = hasattr(data, 'qx_data')
89    dtype = 'double' if '-double' in opts else 'single'
90    cutoff_opts = [s for s in opts if s.startswith('-cutoff')]
91    cutoff = float(cutoff_opts[0].split('=')[1]) if cutoff_opts else 1e-5
92
93
94    if '-random' in opts:
95        gpupars = dict((p,randomize(p,v)) for p,v in gpupars.items())
96    if '-pars' in opts: print "pars",parlist(gpupars)
97    if '-mono' in opts: suppress_pd(gpupars)
98
99    cpuname, cpupars = revert_model(gpuname, gpupars)
100
101    try:
102        gpumodel = load_opencl(gpuname, dtype=dtype)
103    except Exception,exc:
104        print exc
105        print "... trying again with single precision"
106        gpumodel = load_opencl(gpuname, dtype='single')
107    model = BumpsModel(data, gpumodel, cutoff=cutoff, **gpupars)
108    if Ngpu > 0:
109        toc = tic()
110        for i in range(Ngpu):
111            #pars['scale'] = np.random.rand()
112            model.update()
113            gpu = model.theory()
114        gpu_time = toc()*1000./Ngpu
115        print "ocl t=%.1f ms, intensity=%f"%(gpu_time, sum(gpu[~np.isnan(gpu)]))
116        #print max(gpu), min(gpu)
117
118    comp = None
119    if Ncpu > 0 and "-dll" in opts:
120        dllmodel = load_dll(gpuname, dtype=dtype)
121        model = BumpsModel(data, dllmodel, cutoff=cutoff, **gpupars)
122        toc = tic()
123        for i in range(Ncpu):
124            model.update()
125            cpu = model.theory()
126        cpu_time = toc()*1000./Ncpu
127        comp = "dll"
128
129    elif 0: # Hack to check new vs old for GpuCylinder
130        from Models.code_cylinder_f import GpuCylinder as oldgpu
131        from sasmodel import SasModel
132        oldmodel = SasModel(data, oldgpu, dtype=dtype, **cpupars)
133        toc = tic()
134        for i in range(Ngpu):
135            oldmodel.update()
136            cpu = oldmodel.theory()
137        cpu_time = toc()*1000./Ngpu
138        comp = "old"
139
140    elif Ncpu > 0:
141        cpumodel = sasview_model(cpuname, **cpupars)
142        toc = tic()
143        if is2D:
144            for i in range(Ncpu):
145                cpu = cpumodel.evalDistribution([data.qx_data, data.qy_data])
146        else:
147            for i in range(Ncpu):
148                cpu = cpumodel.evalDistribution(data.x)
149        cpu_time = toc()*1000./Ncpu
150        comp = 'sasview'
151        #print "sasview t=%.1f ms, intensity=%.0f"%(cpu_time, sum(cpu[model.index]))
152
153    if comp:
154        print "%s t=%.1f ms, intensity=%f"%(comp, cpu_time, sum(cpu[model.index]))
155    if Ngpu > 0 and Ncpu > 0:
156        #print "speedup %.2g"%(cpu_time/gpu_time)
157        #print "max |gpu/cpu|", max(abs(gpu/cpu)), "%.15g"%max(abs(gpu)), "%.15g"%max(abs(cpu))
158        #cpu *= max(gpu/cpu)
159        resid, relerr = np.zeros_like(gpu), np.zeros_like(gpu)
160        resid[model.index] = (gpu - cpu)[model.index]
161        relerr[model.index] = resid[model.index]/cpu[model.index]
162        print "max(|ocl-%s|)"%comp, max(abs(resid[model.index]))
163        print "max(|(ocl-%s)/ocl|)"%comp, max(abs(relerr[model.index]))
164
165    if '-noplot' in opts: return
166
167    import matplotlib.pyplot as plt
168    if Ncpu > 0:
169        if Ngpu > 0: plt.subplot(131)
170        plot_data(data, cpu, scale='log')
171        plt.title("%s t=%.1f ms"%(comp,cpu_time))
172    if Ngpu > 0:
173        if Ncpu > 0: plt.subplot(132)
174        plot_data(data, gpu, scale='log')
175        plt.title("ocl t=%.1f ms"%gpu_time)
176    if Ncpu > 0 and Ngpu > 0:
177        plt.subplot(133)
178        err = resid if '-abs' in opts else relerr
179        plot_data(data, err, scale='linear')
180        plt.title("max rel err = %.3g"%max(abs(err[model.index])))
181        if is2D: plt.colorbar()
182    plt.show()
183
184# ===========================================================================
185#
186USAGE="""
187usage: compare.py model [Nopencl] [Nsasview] [options...] [key=val]
188
189Compare the speed and value for a model between the SasView original and the
190OpenCL rewrite.
191
192model is the name of the model to compare (see below).
193Nopencl is the number of times to run the OpenCL model (default=5)
194Nsasview is the number of times to run the Sasview model (default=1)
195
196Options (* for default):
197
198    -plot*/-noplot plots or suppress the plot of the model
199    -single/-double uses double precision for comparison
200    -lowq/-midq/-highq use q values up to 0.05, 0.2 or 1.0
201    -2d/-1d uses 1d or 2d random data
202    -preset/-random randomizes the parameters
203    -poly/-mono force monodisperse/polydisperse
204    -sasview/-dll whether cpu is tested using sasview or dll
205    -cutoff=1e-5/value cutoff for including a point in polydispersity
206    -nopars/-pars prints the parameter set or not
207    -rel/-abs plot relative or absolute error
208
209Key=value pairs allow you to set specific values to any of the model
210parameters.
211
212Available models:
213
214    %s
215"""
216
217def main():
218    opts = [arg for arg in sys.argv[1:] if arg.startswith('-')]
219    args = [arg for arg in sys.argv[1:] if not arg.startswith('-')]
220    models = "\n    ".join("%-7s: %s"%(k,v.__name__.replace('_',' '))
221                           for k,v in sorted(MODELS.items()))
222    if len(args) == 0:
223        print(USAGE%models)
224        sys.exit(1)
225    if args[0] not in MODELS:
226        print "Model %r not available. Use one of:\n    %s"%(args[0],models)
227        sys.exit(1)
228
229    name, pars = MODELS[args[0]]()
230    Nopencl = int(args[1]) if len(args) > 1 else 5
231    Nsasview = int(args[2]) if len(args) > 3 else 1
232
233    # Fill in default polydispersity parameters
234    pds = set(p.split('_pd')[0] for p in pars if p.endswith('_pd'))
235    for p in pds:
236        if p+"_pd_nsigma" not in pars: pars[p+"_pd_nsigma"] = 3
237        if p+"_pd_type" not in pars: pars[p+"_pd_type"] = "gaussian"
238
239    # Fill in parameters given on the command line
240    for arg in args[3:]:
241        k,v = arg.split('=')
242        if k not in pars:
243            # extract base name without distribution
244            # style may be either a.d or a_pd_d
245            s = set((p.split('_pd')[0]).split('.')[0] for p in pars)
246            print "%r invalid; parameters are: %s"%(k,", ".join(sorted(s)))
247            sys.exit(1)
248        pars[k] = float(v) if not v.endswith('type') else v
249
250    compare(name, pars, Nsasview, Nopencl, opts)
251
252# ===========================================================================
253#
254
255MODELS = {}
256def model(name):
257    def gather_function(fn):
258        MODELS[name] = fn
259        return fn
260    return gather_function
261
262
263@model('cyl')
264def cylinder():
265    pars = dict(
266        scale=1, background=0,
267        sld=6e-6, solvent_sld=1e-6,
268        #radius=5, length=20,
269        radius=260, length=290,
270        theta=30, phi=15,
271        radius_pd=.2, radius_pd_n=1,
272        length_pd=.2,length_pd_n=1,
273        theta_pd=15, theta_pd_n=25,
274        phi_pd=15, phi_pd_n=1,
275        )
276    return 'cylinder', pars
277
278@model('capcyl')
279def capped_cylinder():
280    pars = dict(
281        scale=1, background=0,
282        sld=6e-6, solvent_sld=1e-6,
283        radius=260, cap_radius=80000, length=290,
284        theta=30, phi=15,
285        radius_pd=.2, radius_pd_n=1,
286        cap_radius_pd=.2, cap_radius_pd_n=1,
287        length_pd=.2, length_pd_n=1,
288        theta_pd=15, theta_pd_n=25,
289        phi_pd=15, phi_pd_n=1,
290        )
291    return 'capped_cylinder', pars
292
293
294@model('cscyl')
295def core_shell_cylinder():
296    pars = dict(
297        scale=1, background=0,
298        core_sld=6e-6, shell_sld=8e-6, solvent_sld=1e-6,
299        radius=325, thickness=25, length=34.2709,
300        theta=90, phi=0,
301        radius_pd=0.1, radius_pd_n=10,
302        length_pd=0.1, length_pd_n=5,
303        thickness_pd=0.1, thickness_pd_n=5,
304        theta_pd=15.8, theta_pd_n=5,
305        phi_pd=0.0008748, phi_pd_n=5,
306        )
307    return 'core_shell_cylinder', pars
308
309
310@model('ell')
311def ellipsoid():
312    pars = dict(
313        scale=1, background=0,
314        sld=6e-6, solvent_sld=1e-6,
315        rpolar=50, requatorial=30,
316        theta=0, phi=0,
317        rpolar_pd=0.3, rpolar_pd_n=10,
318        requatorial_pd=0, requatorial_pd_n=10,
319        theta_pd=0, theta_pd_n=45,
320        phi_pd=0, phi_pd_n=45,
321        )
322    return 'ellipsoid', pars
323
324
325@model('ell3')
326def triaxial_ellipsoid():
327    pars = dict(
328        scale=1, background=0,
329        sld=6e-6, solvent_sld=1e-6,
330        theta=0, phi=0, psi=0,
331        req_minor=25, req_major=36, rpolar=50,
332        theta_pd=0, theta_pd_n=5,
333        phi_pd=0, phi_pd_n=5,
334        psi_pd=0, psi_pd_n=5,
335        req_minor_pd=0, req_minor_pd_n=5,
336        req_major_pd=0, req_major_pd_n=5,
337        rpolar_pd=.3, rpolar_pd_n=25,
338        )
339    return 'triaxial_ellipsoid', pars
340
341@model('sph')
342def sphere():
343    pars = dict(
344        scale=1, background=0,
345        sld=6e-6, solvent_sld=1e-6,
346        radius=120,
347        radius_pd=.3, radius_pd_n=5,
348        )
349    return 'sphere', pars
350
351@model('lam')
352def lamellar():
353    pars = dict(
354        scale=1, background=0,
355        sld=6e-6, solvent_sld=1e-6,
356        thickness=40,
357        thickness_pd= 0.3, thickness_pd_n=40,
358        )
359    return 'lamellar', pars
360
361if __name__ == "__main__":
362    main()
Note: See TracBrowser for help on using the repository browser.