source: sasmodels/sasmodels/compare.py @ eb46451

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

better random model generation for RPA model

  • Property mode set to 100755
File size: 23.1 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4import sys
5import math
6from os.path import basename, dirname, join as joinpath
7import glob
8import datetime
9import traceback
10
11import numpy as np
12
13ROOT = dirname(__file__)
14sys.path.insert(0, ROOT)  # Make sure sasmodels is first on the path
15
16
17from . import core
18from . import kerneldll
19from . import generate
20from .data import plot_theory, empty_data1D, empty_data2D
21from .direct_model import DirectModel
22from .convert import revert_model, constrain_new_to_old
23kerneldll.ALLOW_SINGLE_PRECISION_DLLS = True
24
25# List of available models
26MODELS = [basename(f)[:-3]
27          for f in sorted(glob.glob(joinpath(ROOT,"models","[a-zA-Z]*.py")))]
28
29# CRUFT python 2.6
30if not hasattr(datetime.timedelta, 'total_seconds'):
31    def delay(dt):
32        """Return number date-time delta as number seconds"""
33        return dt.days * 86400 + dt.seconds + 1e-6 * dt.microseconds
34else:
35    def delay(dt):
36        """Return number date-time delta as number seconds"""
37        return dt.total_seconds()
38
39
40def tic():
41    """
42    Timer function.
43
44    Use "toc=tic()" to start the clock and "toc()" to measure
45    a time interval.
46    """
47    then = datetime.datetime.now()
48    return lambda: delay(datetime.datetime.now() - then)
49
50
51def set_beam_stop(data, radius, outer=None):
52    """
53    Add a beam stop of the given *radius*.  If *outer*, make an annulus.
54
55    Note: this function does not use the sasview package
56    """
57    if hasattr(data, 'qx_data'):
58        q = np.sqrt(data.qx_data**2 + data.qy_data**2)
59        data.mask = (q < radius)
60        if outer is not None:
61            data.mask |= (q >= outer)
62    else:
63        data.mask = (data.x < radius)
64        if outer is not None:
65            data.mask |= (data.x >= outer)
66
67
68def parameter_range(p, v):
69    """
70    Choose a parameter range based on parameter name and initial value.
71    """
72    if p.endswith('_pd_n'):
73        return [0, 100]
74    elif p.endswith('_pd_nsigma'):
75        return [0, 5]
76    elif p.endswith('_pd_type'):
77        return v
78    elif any(s in p for s in ('theta','phi','psi')):
79        # orientation in [-180,180], orientation pd in [0,45]
80        if p.endswith('_pd'):
81            return [0,45]
82        else:
83            return [-180, 180]
84    elif 'sld' in p:
85        return [-0.5, 10]
86    elif p.endswith('_pd'):
87        return [0, 1]
88    elif p == 'background':
89        return [0, 10]
90    elif p == 'scale':
91        return [0, 1e3]
92    elif p == 'case_num':
93        # RPA hack
94        return [0, 10]
95    elif v < 0:
96        # Kxy parameters in rpa model can be negative
97        return [2*v, -2*v]
98    else:
99        return [0, (2*v if v>0 else 1)]
100
101def _randomize_one(p, v):
102    """
103    Randomizing parameter.
104    """
105    if any(p.endswith(s) for s in ('_pd_n','_pd_nsigma','_pd_type')):
106        return v
107    else:
108        return np.random.uniform(*parameter_range(p, v))
109
110def randomize_pars(pars, seed=None):
111    np.random.seed(seed)
112    # Note: the sort guarantees order `of calls to random number generator
113    pars = dict((p,_randomize_one(p,v))
114                for p,v in sorted(pars.items()))
115    return pars
116
117def constrain_pars(model_definition, pars):
118    """
119    Restrict parameters to valid values.
120    """
121    name = model_definition.name
122    if name == 'capped_cylinder' and pars['cap_radius'] < pars['radius']:
123        pars['radius'],pars['cap_radius'] = pars['cap_radius'],pars['radius']
124    if name == 'barbell' and pars['bell_radius'] < pars['radius']:
125        pars['radius'],pars['bell_radius'] = pars['bell_radius'],pars['radius']
126
127    # Limit guinier to an Rg such that Iq > 1e-30 (single precision cutoff)
128    if name == 'guinier':
129        #q_max = 0.2  # mid q maximum
130        q_max = 1.0  # high q maximum
131        rg_max = np.sqrt(90*np.log(10) + 3*np.log(pars['scale']))/q_max
132        pars['rg'] = min(pars['rg'],rg_max)
133
134    if name == 'rpa':
135        # Make sure phi sums to 1.0
136        if pars['case_num'] < 2:
137            pars['Phia'] = 0.
138            pars['Phib'] = 0.
139        elif pars['case_num'] < 5:
140            pars['Phia'] = 0.
141        total = sum(pars['Phi'+c] for c in 'abcd')
142        for c in 'abcd':
143            pars['Phi'+c] /= total
144
145def parlist(pars):
146    return "\n".join("%s: %s"%(p,v) for p,v in sorted(pars.items()))
147
148def suppress_pd(pars):
149    """
150    Suppress theta_pd for now until the normalization is resolved.
151
152    May also suppress complete polydispersity of the model to test
153    models more quickly.
154    """
155    pars = pars.copy()
156    for p in pars:
157        if p.endswith("_pd_n"): pars[p] = 0
158    return pars
159
160def eval_sasview(model_definition, data):
161    # importing sas here so that the error message will be that sas failed to
162    # import rather than the more obscure smear_selection not imported error
163    import sas
164    from sas.models.qsmearing import smear_selection
165
166    # convert model parameters from sasmodel form to sasview form
167    #print("old",sorted(pars.items()))
168    modelname, pars = revert_model(model_definition, {})
169    #print("new",sorted(pars.items()))
170    sas = __import__('sas.models.'+modelname)
171    ModelClass = getattr(getattr(sas.models,modelname,None),modelname,None)
172    if ModelClass is None:
173        raise ValueError("could not find model %r in sas.models"%modelname)
174    model = ModelClass()
175    smearer = smear_selection(data, model=model)
176
177    if hasattr(data, 'qx_data'):
178        q = np.sqrt(data.qx_data**2 + data.qy_data**2)
179        index = ((~data.mask) & (~np.isnan(data.data))
180                 & (q >= data.qmin) & (q <= data.qmax))
181        if smearer is not None:
182            smearer.model = model  # because smear_selection has a bug
183            smearer.accuracy = data.accuracy
184            smearer.set_index(index)
185            theory = lambda: smearer.get_value()
186        else:
187            theory = lambda: model.evalDistribution([data.qx_data[index], data.qy_data[index]])
188    elif smearer is not None:
189        theory = lambda: smearer(model.evalDistribution(data.x))
190    else:
191        theory = lambda: model.evalDistribution(data.x)
192
193    def calculator(**pars):
194        # paying for parameter conversion each time to keep life simple, if not fast
195        _, pars = revert_model(model_definition, pars)
196        for k,v in pars.items():
197            parts = k.split('.')  # polydispersity components
198            if len(parts) == 2:
199                model.dispersion[parts[0]][parts[1]] = v
200            else:
201                model.setParam(k, v)
202        return theory()
203
204    calculator.engine = "sasview"
205    return calculator
206
207DTYPE_MAP = {
208    'half': '16',
209    'fast': 'fast',
210    'single': '32',
211    'double': '64',
212    'quad': '128',
213    'f16': '16',
214    'f32': '32',
215    'f64': '64',
216    'longdouble': '128',
217}
218def eval_opencl(model_definition, data, dtype='single', cutoff=0.):
219    try:
220        model = core.load_model(model_definition, dtype=dtype, platform="ocl")
221    except Exception as exc:
222        print(exc)
223        print("... trying again with single precision")
224        dtype = 'single'
225        model = core.load_model(model_definition, dtype=dtype, platform="ocl")
226    calculator = DirectModel(data, model, cutoff=cutoff)
227    calculator.engine = "OCL%s"%DTYPE_MAP[dtype]
228    return calculator
229
230def eval_ctypes(model_definition, data, dtype='double', cutoff=0.):
231    if dtype=='quad':
232        dtype = 'longdouble'
233    model = core.load_model(model_definition, dtype=dtype, platform="dll")
234    calculator = DirectModel(data, model, cutoff=cutoff)
235    calculator.engine = "OMP%s"%DTYPE_MAP[dtype]
236    return calculator
237
238def time_calculation(calculator, pars, Nevals=1):
239    # initialize the code so time is more accurate
240    value = calculator(**suppress_pd(pars))
241    toc = tic()
242    for _ in range(max(Nevals, 1)):  # make sure there is at least one eval
243        value = calculator(**pars)
244    average_time = toc()*1000./Nevals
245    return value, average_time
246
247def make_data(opts):
248    qmax, nq, res = opts['qmax'], opts['nq'], opts['res']
249    if opts['is2d']:
250        data = empty_data2D(np.linspace(-qmax, qmax, nq), resolution=res)
251        data.accuracy = opts['accuracy']
252        set_beam_stop(data, 0.004)
253        index = ~data.mask
254    else:
255        if opts['view'] == 'log':
256            qmax = math.log10(qmax)
257            q = np.logspace(qmax-3, qmax, nq)
258        else:
259            q = np.linspace(0.001*qmax, qmax, nq)
260        data = empty_data1D(q, resolution=res)
261        index = slice(None, None)
262    return data, index
263
264def make_engine(model_definition, data, dtype, cutoff):
265    if dtype == 'sasview':
266        return eval_sasview(model_definition, data)
267    elif dtype.endswith('!'):
268        return eval_ctypes(model_definition, data, dtype=dtype[:-1],
269                           cutoff=cutoff)
270    else:
271        return eval_opencl(model_definition, data, dtype=dtype,
272                           cutoff=cutoff)
273
274def compare(opts, limits=None):
275    Nbase, Ncomp = opts['N1'], opts['N2']
276    pars = opts['pars']
277    data = opts['data']
278
279    # Base calculation
280    if Nbase > 0:
281        base = opts['engines'][0]
282        try:
283            base_value, base_time = time_calculation(base, pars, Nbase)
284            print("%s t=%.1f ms, intensity=%.0f"%(base.engine, base_time, sum(base_value)))
285        except ImportError:
286            traceback.print_exc()
287            Nbase = 0
288
289    # Comparison calculation
290    if Ncomp > 0:
291        comp = opts['engines'][1]
292        try:
293            comp_value, comp_time = time_calculation(comp, pars, Ncomp)
294            print("%s t=%.1f ms, intensity=%.0f"%(comp.engine, comp_time, sum(comp_value)))
295        except ImportError:
296            traceback.print_exc()
297            Ncomp = 0
298
299    # Compare, but only if computing both forms
300    if Nbase > 0 and Ncomp > 0:
301        #print("speedup %.2g"%(comp_time/base_time))
302        #print("max |base/comp|", max(abs(base_value/comp_value)), "%.15g"%max(abs(base_value)), "%.15g"%max(abs(comp_value)))
303        #comp *= max(base_value/comp_value)
304        resid = (base_value - comp_value)
305        relerr = resid/comp_value
306        _print_stats("|%s - %s|"%(base.engine,comp.engine)+(" "*(3+len(comp.engine))), resid)
307        _print_stats("|(%s - %s) / %s|"%(base.engine,comp.engine,comp.engine), relerr)
308
309    # Plot if requested
310    if not opts['plot'] and not opts['explore']: return
311    view = opts['view']
312    import matplotlib.pyplot as plt
313    if limits is None:
314        vmin, vmax = np.Inf, -np.Inf
315        if Nbase > 0:
316            vmin = min(vmin, min(base_value))
317            vmax = max(vmax, max(base_value))
318        if Ncomp > 0:
319            vmin = min(vmin, min(comp_value))
320            vmax = max(vmax, max(comp_value))
321        limits = vmin, vmax
322
323    if Nbase > 0:
324        if Ncomp > 0: plt.subplot(131)
325        plot_theory(data, base_value, view=view, plot_data=False, limits=limits)
326        plt.title("%s t=%.1f ms"%(base.engine, base_time))
327        #cbar_title = "log I"
328    if Ncomp > 0:
329        if Nbase > 0: plt.subplot(132)
330        plot_theory(data, comp_value, view=view, plot_data=False, limits=limits)
331        plt.title("%s t=%.1f ms"%(comp.engine,comp_time))
332        #cbar_title = "log I"
333    if Ncomp > 0 and Nbase > 0:
334        plt.subplot(133)
335        if '-abs' in opts:
336            err,errstr,errview = resid, "abs err", "linear"
337        else:
338            err,errstr,errview = abs(relerr), "rel err", "log"
339        #err,errstr = base/comp,"ratio"
340        plot_theory(data, None, resid=err, view=errview, plot_data=False)
341        plt.title("max %s = %.3g"%(errstr, max(abs(err))))
342        #cbar_title = errstr if errview=="linear" else "log "+errstr
343    #if is2D:
344    #    h = plt.colorbar()
345    #    h.ax.set_title(cbar_title)
346
347    if Ncomp > 0 and Nbase > 0 and '-hist' in opts:
348        plt.figure()
349        v = relerr
350        v[v==0] = 0.5*np.min(np.abs(v[v!=0]))
351        plt.hist(np.log10(np.abs(v)), normed=1, bins=50);
352        plt.xlabel('log10(err), err = |(%s - %s) / %s|'%(base.engine, comp.engine, comp.engine));
353        plt.ylabel('P(err)')
354        plt.title('Distribution of relative error between calculation engines')
355
356    if not opts['explore']:
357        plt.show()
358
359    return limits
360
361def _print_stats(label, err):
362    sorted_err = np.sort(abs(err))
363    p50 = int((len(err)-1)*0.50)
364    p98 = int((len(err)-1)*0.98)
365    data = [
366        "max:%.3e"%sorted_err[-1],
367        "median:%.3e"%sorted_err[p50],
368        "98%%:%.3e"%sorted_err[p98],
369        "rms:%.3e"%np.sqrt(np.mean(err**2)),
370        "zero-offset:%+.3e"%np.mean(err),
371        ]
372    print(label+"  ".join(data))
373
374
375
376# ===========================================================================
377#
378USAGE="""
379usage: compare.py model N1 N2 [options...] [key=val]
380
381Compare the speed and value for a model between the SasView original and the
382sasmodels rewrite.
383
384model is the name of the model to compare (see below).
385N1 is the number of times to run sasmodels (default=1).
386N2 is the number times to run sasview (default=1).
387
388Options (* for default):
389
390    -plot*/-noplot plots or suppress the plot of the model
391    -lowq*/-midq/-highq/-exq use q values up to 0.05, 0.2, 1.0, 10.0
392    -nq=128 sets the number of Q points in the data set
393    -1d*/-2d computes 1d or 2d data
394    -preset*/-random[=seed] preset or random parameters
395    -mono/-poly* force monodisperse/polydisperse
396    -cutoff=1e-5* cutoff value for including a point in polydispersity
397    -pars/-nopars* prints the parameter set or not
398    -abs/-rel* plot relative or absolute error
399    -linear/-log*/-q4 intensity scaling
400    -hist/-nohist* plot histogram of relative error
401    -res=0 sets the resolution width dQ/Q if calculating with resolution
402    -accuracy=Low accuracy of the resolution calculation Low, Mid, High, Xhigh
403    -edit starts the parameter explorer
404
405Any two calculation engines can be selected for comparison:
406
407    -single/-double/-half/-fast sets an OpenCL calculation engine
408    -single!/-double!/-quad! sets an OpenMP calculation engine
409    -sasview sets the sasview calculation engine
410
411The default is -single -sasview.  Note that the interpretation of quad
412precision depends on architecture, and may vary from 64-bit to 128-bit,
413with 80-bit floats being common (1e-19 precision).
414
415Key=value pairs allow you to set specific values for the model parameters.
416
417Available models:
418"""
419
420
421NAME_OPTIONS = set([
422    'plot', 'noplot',
423    'half', 'fast', 'single', 'double',
424    'single!', 'double!', 'quad!', 'sasview',
425    'lowq', 'midq', 'highq', 'exq',
426    '2d', '1d',
427    'preset', 'random',
428    'poly', 'mono',
429    'nopars', 'pars',
430    'rel', 'abs',
431    'linear', 'log', 'q4',
432    'hist', 'nohist',
433    'edit',
434    ])
435VALUE_OPTIONS = [
436    # Note: random is both a name option and a value option
437    'cutoff', 'random', 'nq', 'res', 'accuracy',
438    ]
439
440def columnize(L, indent="", width=79):
441    column_width = max(len(w) for w in L) + 1
442    num_columns = (width - len(indent)) // column_width
443    num_rows = len(L) // num_columns
444    L = L + [""] * (num_rows*num_columns - len(L))
445    columns = [L[k*num_rows:(k+1)*num_rows] for k in range(num_columns)]
446    lines = [" ".join("%-*s"%(column_width, entry) for entry in row)
447             for row in zip(*columns)]
448    output = indent + ("\n"+indent).join(lines)
449    return output
450
451
452def get_demo_pars(model_definition):
453    info = generate.make_info(model_definition)
454    # Get the default values for the parameters
455    pars = dict((p[0],p[2]) for p in info['parameters'])
456
457    # Fill in default values for the polydispersity parameters
458    for p in info['parameters']:
459        if p[4] in ('volume', 'orientation'):
460            pars[p[0]+'_pd'] = 0.0
461            pars[p[0]+'_pd_n'] = 0
462            pars[p[0]+'_pd_nsigma'] = 3.0
463            pars[p[0]+'_pd_type'] = "gaussian"
464
465    # Plug in values given in demo
466    pars.update(info['demo'])
467    return pars
468
469def parse_opts():
470    flags = [arg for arg in sys.argv[1:] if arg.startswith('-')]
471    values = [arg for arg in sys.argv[1:] if not arg.startswith('-') and '=' in arg]
472    args = [arg for arg in sys.argv[1:] if not arg.startswith('-') and '=' not in arg]
473    models = "\n    ".join("%-15s"%v for v in MODELS)
474    if len(args) == 0:
475        print(USAGE)
476        print(columnize(MODELS, indent="  "))
477        sys.exit(1)
478    if args[0] not in MODELS:
479        print("Model %r not available. Use one of:\n    %s"%(args[0],models))
480        sys.exit(1)
481    if len(args) > 3:
482        print("expected parameters: model Nopencl Nsasview")
483
484    invalid = [o[1:] for o in flags
485               if o[1:] not in NAME_OPTIONS
486                  and not any(o.startswith('-%s='%t) for t in VALUE_OPTIONS)]
487    if invalid:
488        print("Invalid options: %s"%(", ".join(invalid)))
489        sys.exit(1)
490
491
492    # Interpret the flags
493    opts = {
494        'plot'      : True,
495        'view'      : 'log',
496        'is2d'      : False,
497        'qmax'      : 0.05,
498        'nq'        : 128,
499        'res'       : 0.0,
500        'accuracy'  : 'Low',
501        'cutoff'    : 1e-5,
502        'seed'      : -1,  # default to preset
503        'mono'      : False,
504        'show_pars' : False,
505        'show_hist' : False,
506        'rel_err'   : True,
507        'explore'   : False,
508    }
509    engines = []
510    for arg in flags:
511        if arg == '-noplot':    opts['plot'] = False
512        elif arg == '-plot':    opts['plot'] = True
513        elif arg == '-linear':  opts['view'] = 'linear'
514        elif arg == '-log':     opts['view'] = 'log'
515        elif arg == '-q4':      opts['view'] = 'q4'
516        elif arg == '-1d':      opts['is2d'] = False
517        elif arg == '-2d':      opts['is2d'] = True
518        elif arg == '-exq':     opts['qmax'] = 10.0
519        elif arg == '-highq':   opts['qmax'] = 1.0
520        elif arg == '-midq':    opts['qmax'] = 0.2
521        elif arg == '-loq':     opts['qmax'] = 0.05
522        elif arg.startswith('-nq='):       opts['nq'] = int(arg[4:])
523        elif arg.startswith('-res='):      opts['res'] = float(arg[5:])
524        elif arg.startswith('-accuracy='): opts['accuracy'] = arg[10:]
525        elif arg.startswith('-cutoff='):   opts['cutoff'] = float(arg[8:])
526        elif arg.startswith('-random='):   opts['seed'] = int(arg[8:])
527        elif arg == '-random':  opts['seed'] = np.random.randint(1e6)
528        elif arg == '-preset':  opts['seed'] = -1
529        elif arg == '-mono':    opts['mono'] = True
530        elif arg == '-poly':    opts['mono'] = False
531        elif arg == '-pars':    opts['show_pars'] = True
532        elif arg == '-nopars':  opts['show_pars'] = False
533        elif arg == '-hist':    opts['show_hist'] = True
534        elif arg == '-nohist':  opts['show_hist'] = False
535        elif arg == '-rel':     opts['rel_err'] = True
536        elif arg == '-abs':     opts['rel_err'] = False
537        elif arg == '-half':    engines.append(arg[1:])
538        elif arg == '-fast':    engines.append(arg[1:])
539        elif arg == '-single':  engines.append(arg[1:])
540        elif arg == '-double':  engines.append(arg[1:])
541        elif arg == '-single!': engines.append(arg[1:])
542        elif arg == '-double!': engines.append(arg[1:])
543        elif arg == '-quad!':   engines.append(arg[1:])
544        elif arg == '-sasview': engines.append(arg[1:])
545        elif arg == '-edit':    opts['explore'] = True
546
547    if len(engines) == 0:
548        engines.extend(['single','sasview'])
549    elif len(engines) == 1:
550        if engines[0][0] != 'sasview':
551            engines.append('sasview')
552        else:
553            engines.append('single')
554    elif len(engines) > 2:
555        del engines[2:]
556
557    name = args[0]
558    model_definition = core.load_model_definition(name)
559
560    N1 = int(args[1]) if len(args) > 1 else 1
561    N2 = int(args[2]) if len(args) > 2 else 1
562
563    # Get demo parameters from model definition, or use default parameters
564    # if model does not define demo parameters
565    pars = get_demo_pars(model_definition)
566
567    # Fill in parameters given on the command line
568    presets = {}
569    for arg in values:
570        k,v = arg.split('=',1)
571        if k not in pars:
572            # extract base name without polydispersity info
573            s = set(p.split('_pd')[0] for p in pars)
574            print("%r invalid; parameters are: %s"%(k,", ".join(sorted(s))))
575            sys.exit(1)
576        presets[k] = float(v) if not k.endswith('type') else v
577
578    # randomize parameters
579    #pars.update(set_pars)  # set value before random to control range
580    if opts['seed'] > -1:
581        pars = randomize_pars(pars, seed=opts['seed'])
582        print("Randomize using -random=%i"%opts['seed'])
583    if opts['mono']:
584        pars = suppress_pd(pars)
585    pars.update(presets)  # set value after random to control value
586    constrain_pars(model_definition, pars)
587    constrain_new_to_old(model_definition, pars)
588    if opts['show_pars']:
589        print("pars " + str(parlist(pars)))
590
591    # Create the computational engines
592    data, _index = make_data(opts)
593    if N1:
594        base = make_engine(model_definition, data, engines[0], opts['cutoff'])
595    else:
596        base = None
597    if N2:
598        comp = make_engine(model_definition, data, engines[1], opts['cutoff'])
599    else:
600        comp = None
601
602    # Remember it all
603    opts.update({
604        'name'      : name,
605        'def'       : model_definition,
606        'N1'        : N1,
607        'N2'        : N2,
608        'presets'   : presets,
609        'pars'      : pars,
610        'data'      : data,
611        'engines'   : [base, comp],
612    })
613
614    return opts
615
616def main():
617    opts = parse_opts()
618    if opts['explore']:
619        explore(opts)
620    else:
621        compare(opts)
622
623def explore(opts):
624    import wx
625    from bumps.names import FitProblem
626    from bumps.gui.app_frame import AppFrame
627
628    problem = FitProblem(Explore(opts))
629    isMac = "cocoa" in wx.version()
630    app = wx.App()
631    frame = AppFrame(parent=None, title="explore")
632    if not isMac: frame.Show()
633    frame.panel.set_model(model=problem)
634    frame.panel.Layout()
635    frame.panel.aui.Split(0, wx.TOP)
636    if isMac: frame.Show()
637    app.MainLoop()
638
639class Explore(object):
640    """
641    Return a bumps wrapper for a SAS model comparison.
642    """
643    def __init__(self, opts):
644        from bumps.cli import config_matplotlib
645        import bumps_model
646        config_matplotlib()
647        self.opts = opts
648        info = generate.make_info(opts['def'])
649        pars, pd_types = bumps_model.create_parameters(info, **opts['pars'])
650        if not opts['is2d']:
651            active = [base + ext
652                      for base in info['partype']['pd-1d']
653                      for ext in ['','_pd','_pd_n','_pd_nsigma']]
654            active.extend(info['partype']['fixed-1d'])
655            for k in active:
656                v = pars[k]
657                v.range(*parameter_range(k, v.value))
658        else:
659            for k, v in pars.items():
660                v.range(*parameter_range(k, v.value))
661
662        self.pars = pars
663        self.pd_types = pd_types
664        self.limits = None
665
666    def numpoints(self):
667        """
668        Return the number of points
669        """
670        return len(self.pars) + 1  # so dof is 1
671
672    def parameters(self):
673        """
674        Return a dictionary of parameters
675        """
676        return self.pars
677
678    def nllf(self):
679        return 0.  # No nllf
680
681    def plot(self, view='log'):
682        """
683        Plot the data and residuals.
684        """
685        pars = dict((k, v.value) for k,v in self.pars.items())
686        pars.update(self.pd_types)
687        self.opts['pars'] = pars
688        limits = compare(self.opts, limits=self.limits)
689        if self.limits is None:
690            vmin, vmax = limits
691            vmax = 1.3*vmax
692            vmin = vmax*1e-7
693            self.limits = vmin, vmax
694
695
696if __name__ == "__main__":
697    main()
Note: See TracBrowser for help on using the repository browser.