Changeset 346bc88 in sasmodels


Ignore:
Timestamp:
Aug 31, 2015 10:24:45 PM (9 years ago)
Author:
Paul Kienzle <pkienzle@…>
Branches:
master, core_shell_microgels, costrafo411, magnetic_model, release_v0.94, release_v0.95, ticket-1257-vesicle-product, ticket_1156, ticket_1265_superball, ticket_822_more_unit_tests
Children:
3e6aaad
Parents:
f224873
git-author:
Paul Kienzle <pkienzle@…> (08/31/15 22:12:39)
git-committer:
Paul Kienzle <pkienzle@…> (08/31/15 22:24:45)
Message:

Add 2D resolution smearing. Split BumpsModel? into Experiment and Model and fix up examples.

Files:
1 added
5 edited

Legend:

Unmodified
Added
Removed
  • compare.py

    raa4946b r346bc88  
    99import numpy as np 
    1010 
    11 from sasmodels.bumps_model import BumpsModel, plot_data, tic 
     11from sasmodels.bumps_model import Model, Experiment, plot_theory, tic 
    1212from sasmodels import core 
    1313from sasmodels import kerneldll 
     
    9797 
    9898def eval_sasview(name, pars, data, Nevals=1): 
     99    from sas.models.qsmearing import smear_selection 
    99100    model = sasview_model(name, **pars) 
     101    smearer = smear_selection(data, model=model) 
    100102    toc = tic() 
    101103    for _ in range(Nevals): 
    102104        if hasattr(data, 'qx_data'): 
    103             value = model.evalDistribution([data.qx_data, data.qy_data]) 
     105            q = np.sqrt(data.qx_data**2 + data.qy_data**2) 
     106            index = ((~data.mask) & (~np.isnan(data.data)) 
     107                     & (q >= data.qmin) & (q <= data.qmax)) 
     108            if smearer is not None: 
     109                smearer.model = model  # because smear_selection has a bug 
     110                smearer.set_index(index) 
     111                value = smearer.get_value() 
     112            else: 
     113                value = model.evalDistribution([data.qx_data[index], data.qy_data[index]]) 
    104114        else: 
    105115            value = model.evalDistribution(data.x) 
     116            if smearer is not None: 
     117                value = smearer(value) 
    106118    average_time = toc()*1000./Nevals 
    107119    return value, average_time 
     
    114126        print "... trying again with single precision" 
    115127        model = core.load_model(model_definition, dtype='single', platform="ocl") 
    116     problem = BumpsModel(data, model, cutoff=cutoff, **pars) 
     128    problem = Experiment(data, Model(model, **pars), cutoff=cutoff) 
    117129    toc = tic() 
    118130    for _ in range(Nevals): 
     
    125137def eval_ctypes(model_definition, pars, data, dtype='double', Nevals=1, cutoff=0): 
    126138    model = core.load_model(model_definition, dtype=dtype, platform="dll") 
    127     problem = BumpsModel(data, model, cutoff=cutoff, **pars) 
     139    problem = Experiment(data, Model(model, **pars), cutoff=cutoff) 
    128140    toc = tic() 
    129141    for _ in range(Nevals): 
     
    133145    return value, average_time 
    134146 
    135 def make_data(qmax, is2D, Nq=128, view='log'): 
     147def make_data(qmax, is2D, Nq=128, resolution=0.0, view='log'): 
    136148    if is2D: 
    137149        from sasmodels.bumps_model import empty_data2D, set_beam_stop 
    138         data = empty_data2D(np.linspace(-qmax, qmax, Nq)) 
     150        data = empty_data2D(np.linspace(-qmax, qmax, Nq), resolution=resolution) 
    139151        set_beam_stop(data, 0.004) 
    140152        index = ~data.mask 
     
    146158        else: 
    147159            q = np.linspace(0.001*qmax, qmax, Nq) 
    148         data = empty_data1D(q) 
     160        data = empty_data1D(q, resolution=resolution) 
    149161        index = slice(None, None) 
    150162    return data, index 
     
    159171    qmax = 10.0 if '-exq' in opts else 1.0 if '-highq' in opts else 0.2 if '-midq' in opts else 0.05 
    160172    Nq = int(opt_values.get('-Nq', '128')) 
     173    res = float(opt_values.get('-res', '0')) 
    161174    is2D = not "-1d" in opts 
    162     data, index = make_data(qmax, is2D, Nq, view=view) 
     175    data, index = make_data(qmax, is2D, Nq, res, view=view) 
    163176 
    164177 
     
    185198        ocl, ocl_time = eval_opencl(model_definition, pars, data, 
    186199                                    dtype=dtype, cutoff=cutoff, Nevals=Nocl) 
    187         print "opencl t=%.1f ms, intensity=%.0f"%(ocl_time, sum(ocl[index])) 
     200        print "opencl t=%.1f ms, intensity=%.0f"%(ocl_time, sum(ocl)) 
    188201        #print max(ocl), min(ocl) 
    189202 
     
    193206                                    dtype=dtype, cutoff=cutoff, Nevals=Ncpu) 
    194207        comp = "ctypes" 
    195         print "ctypes t=%.1f ms, intensity=%.0f"%(cpu_time, sum(cpu[index])) 
     208        print "ctypes t=%.1f ms, intensity=%.0f"%(cpu_time, sum(cpu)) 
    196209    elif Ncpu > 0: 
    197210        cpu, cpu_time = eval_sasview(model_definition, pars, data, Ncpu) 
    198211        comp = "sasview" 
    199         print "sasview t=%.1f ms, intensity=%.0f"%(cpu_time, sum(cpu[index])) 
     212        print "sasview t=%.1f ms, intensity=%.0f"%(cpu_time, sum(cpu)) 
    200213 
    201214    # Compare, but only if computing both forms 
     
    204217        #print "max |ocl/cpu|", max(abs(ocl/cpu)), "%.15g"%max(abs(ocl)), "%.15g"%max(abs(cpu)) 
    205218        #cpu *= max(ocl/cpu) 
    206         resid, relerr = np.zeros_like(ocl), np.zeros_like(ocl) 
    207         resid[index] = (ocl - cpu)[index] 
    208         relerr[index] = resid[index]/cpu[index] 
     219        resid = (ocl - cpu) 
     220        relerr = resid/cpu 
    209221        #bad = (relerr>1e-4) 
    210222        #print relerr[bad],cpu[bad],ocl[bad],data.qx_data[bad],data.qy_data[bad] 
     
    221233                ] 
    222234            print label,"  ".join(data) 
    223         stats("|ocl-%s|"%comp+(" "*(3+len(comp))), resid[index]) 
    224         stats("|(ocl-%s)/%s|"%(comp,comp), relerr[index]) 
     235        stats("|ocl-%s|"%comp+(" "*(3+len(comp))), resid) 
     236        stats("|(ocl-%s)/%s|"%(comp,comp), relerr) 
    225237 
    226238    # Plot if requested 
     
    229241    if Ncpu > 0: 
    230242        if Nocl > 0: plt.subplot(131) 
    231         plot_data(data, cpu, view=view) 
     243        plot_theory(data, cpu, view=view) 
    232244        plt.title("%s t=%.1f ms"%(comp,cpu_time)) 
    233245        cbar_title = "log I" 
    234246    if Nocl > 0: 
    235247        if Ncpu > 0: plt.subplot(132) 
    236         plot_data(data, ocl, view=view) 
     248        plot_theory(data, ocl, view=view) 
    237249        plt.title("opencl t=%.1f ms"%ocl_time) 
    238250        cbar_title = "log I" 
     
    244256            err,errstr,errview = abs(relerr), "rel err", "log" 
    245257        #err,errstr = ocl/cpu,"ratio" 
    246         plot_data(data, err, view=errview) 
    247         plt.title("max %s = %.3g"%(errstr, max(abs(err[index])))) 
     258        plot_theory(data, err, view=errview) 
     259        plt.title("max %s = %.3g"%(errstr, max(abs(err)))) 
    248260        cbar_title = errstr if errview=="linear" else "log "+errstr 
    249261    if is2D: 
     
    253265    if Ncpu > 0 and Nocl > 0 and '-hist' in opts: 
    254266        plt.figure() 
    255         v = relerr[index] 
     267        v = relerr 
    256268        v[v==0] = 0.5*np.min(np.abs(v[v!=0])) 
    257269        plt.hist(np.log10(np.abs(v)), normed=1, bins=50); 
     
    289301    -linear/-log/-q4 intensity scaling 
    290302    -hist/-nohist* plot histogram of relative error 
     303    -res=0 sets the resolution width dQ/Q if calculating with resolution 
    291304 
    292305Key=value pairs allow you to set specific values to any of the model 
     
    313326VALUE_OPTIONS = [ 
    314327    # Note: random is both a name option and a value option 
    315     'cutoff', 'random', 'Nq', 
     328    'cutoff', 'random', 'Nq', 'res', 
    316329    ] 
    317330 
  • example/fit.py

    r5d3d7b4 r346bc88  
    44import sys 
    55from bumps.names import * 
     6from sasmodels.core import load_model 
    67from sasmodels import bumps_model as sas 
    78 
     
    2324data = radial_data if section != "tangential" else tan_data 
    2425phi = 0 if section != "tangential" else 90 
    25 kernel = sas.load_model(name, dtype="single") 
     26kernel = load_model(name, dtype="single") 
    2627cutoff = 1e-3 
    2728 
    2829if name == "ellipsoid": 
    29     model = sas.BumpsModel(data, kernel, 
    30     scale=0.08, 
    31     rpolar=15, requatorial=800, 
    32     sld=.291, solvent_sld=7.105, 
    33     background=0, 
    34     theta=90, phi=phi, 
    35     theta_pd=15, theta_pd_n=40, theta_pd_nsigma=3, 
    36     rpolar_pd=0.222296, rpolar_pd_n=1, rpolar_pd_nsigma=0, 
    37     requatorial_pd=.000128, requatorial_pd_n=1, requatorial_pd_nsigma=0, 
    38     phi_pd=0, phi_pd_n=20, phi_pd_nsigma=3, 
    39     ) 
     30    model = sas.Model(kernel, 
     31        scale=0.08, 
     32        rpolar=15, requatorial=800, 
     33        sld=.291, solvent_sld=7.105, 
     34        background=0, 
     35        theta=90, phi=phi, 
     36        theta_pd=15, theta_pd_n=40, theta_pd_nsigma=3, 
     37        rpolar_pd=0.222296, rpolar_pd_n=1, rpolar_pd_nsigma=0, 
     38        requatorial_pd=.000128, requatorial_pd_n=1, requatorial_pd_nsigma=0, 
     39        phi_pd=0, phi_pd_n=20, phi_pd_nsigma=3, 
     40        ) 
    4041 
    4142 
    4243    # SET THE FITTING PARAMETERS 
    43     #model.rpolar.range(15, 1000) 
    44     #model.requatorial.range(15, 1000) 
    45     #model.theta_pd.range(0, 360) 
    46     #model.background.range(0,1000) 
     44    model.rpolar.range(15, 1000) 
     45    model.requatorial.range(15, 1000) 
     46    model.theta_pd.range(0, 360) 
     47    model.background.range(0,1000) 
    4748    model.scale.range(0, 10) 
    4849 
    4950 
     51 
    5052elif name == "lamellar": 
    51     model = sas.BumpsModel(data, kernel, 
    52     scale=0.08, 
    53     thickness=19.2946, 
    54     sld=5.38,sld_sol=7.105, 
    55     background=0.003, 
    56     thickness_pd= 0.37765, thickness_pd_n=10, thickness_pd_nsigma=3, 
    57     ) 
     53    model = sas.Model(kernel, 
     54        scale=0.08, 
     55        thickness=19.2946, 
     56        sld=5.38,sld_sol=7.105, 
     57        background=0.003, 
     58        thickness_pd= 0.37765, thickness_pd_n=10, thickness_pd_nsigma=3, 
     59        ) 
     60 
    5861 
    5962    # SET THE FITTING PARAMETERS 
     
    8487        theta_pd=10, theta_pd_n=50, theta_pd_nsigma=3, 
    8588        phi_pd=0, phi_pd_n=10, phi_pd_nsigma=3) 
    86     model = sas.BumpsModel(data, kernel, **pars) 
     89    model = sas.Model(kernel, **pars) 
    8790 
    8891    # SET THE FITTING PARAMETERS 
     
    99102 
    100103elif name == "core_shell_cylinder": 
    101     model = sas.BumpsModel(data, kernel, 
    102     scale= .031, radius=19.5, thickness=30, length=22, 
    103     core_sld=7.105, shell_sld=.291, solvent_sld=7.105, 
    104     background=0, theta=0, phi=phi, 
     104    model = sas.Model(kernel, 
     105        scale= .031, radius=19.5, thickness=30, length=22, 
     106        core_sld=7.105, shell_sld=.291, solvent_sld=7.105, 
     107        background=0, theta=0, phi=phi, 
    105108 
    106     radius_pd=0.26, radius_pd_n=10, radius_pd_nsigma=3, 
    107     length_pd=0.26, length_pd_n=10, length_pd_nsigma=3, 
    108     thickness_pd=1, thickness_pd_n=1, thickness_pd_nsigma=1, 
    109     theta_pd=1, theta_pd_n=10, theta_pd_nsigma=3, 
    110     phi_pd=0.1, phi_pd_n=1, phi_pd_nsigma=1, 
    111     ) 
     109        radius_pd=0.26, radius_pd_n=10, radius_pd_nsigma=3, 
     110        length_pd=0.26, length_pd_n=10, length_pd_nsigma=3, 
     111        thickness_pd=1, thickness_pd_n=1, thickness_pd_nsigma=1, 
     112        theta_pd=1, theta_pd_n=10, theta_pd_nsigma=3, 
     113        phi_pd=0.1, phi_pd_n=1, phi_pd_nsigma=1, 
     114        ) 
    112115 
    113116    # SET THE FITTING PARAMETERS 
     
    126129 
    127130elif name == "capped_cylinder": 
    128     model = sas.BumpsModel(data, kernel, 
    129     scale=.08, radius=20, cap_radius=40, length=400, 
    130     sld_capcyl=1, sld_solv=6.3, 
    131     background=0, theta=0, phi=phi, 
    132     radius_pd=.1, radius_pd_n=5, radius_pd_nsigma=3, 
    133     cap_radius_pd=.1, cap_radius_pd_n=5, cap_radius_pd_nsigma=3, 
    134     length_pd=.1, length_pd_n=1, length_pd_nsigma=0, 
    135     theta_pd=.1, theta_pd_n=1, theta_pd_nsigma=0, 
    136     phi_pd=.1, phi_pd_n=1, phi_pd_nsigma=0, 
    137     dtype=dtype) 
     131    model = sas.Model(kernel, 
     132        scale=.08, radius=20, cap_radius=40, length=400, 
     133        sld_capcyl=1, sld_solv=6.3, 
     134        background=0, theta=0, phi=phi, 
     135        radius_pd=.1, radius_pd_n=5, radius_pd_nsigma=3, 
     136        cap_radius_pd=.1, cap_radius_pd_n=5, cap_radius_pd_nsigma=3, 
     137        length_pd=.1, length_pd_n=1, length_pd_nsigma=0, 
     138        theta_pd=.1, theta_pd_n=1, theta_pd_nsigma=0, 
     139        phi_pd=.1, phi_pd_n=1, phi_pd_nsigma=0, 
     140        ) 
    138141 
    139142    model.scale.range(0, 1) 
     
    141144 
    142145elif name == "triaxial_ellipsoid": 
    143     model = sas.BumpsModel(data, kernel, 
    144     scale=0.08, req_minor=15, req_major=20, rpolar=500, 
    145     sldEll=7.105, solvent_sld=.291, 
    146     background=5, theta=0, phi=phi, psi=0, 
    147     theta_pd=20, theta_pd_n=40, theta_pd_nsigma=3, 
    148     phi_pd=.1, phi_pd_n=1, phi_pd_nsigma=0, 
    149     psi_pd=30, psi_pd_n=1, psi_pd_nsigma=0, 
    150     req_minor_pd=.1, req_minor_pd_n=1, req_minor_pd_nsigma=0, 
    151     req_major_pd=.1, req_major_pd_n=1, req_major_pd_nsigma=0, 
    152     rpolar_pd=.1, rpolar_pd_n=1, rpolar_pd_nsigma=0, dtype=dtype) 
     146    model = sas.Model(kernel, 
     147        scale=0.08, req_minor=15, req_major=20, rpolar=500, 
     148        sldEll=7.105, solvent_sld=.291, 
     149        background=5, theta=0, phi=phi, psi=0, 
     150        theta_pd=20, theta_pd_n=40, theta_pd_nsigma=3, 
     151        phi_pd=.1, phi_pd_n=1, phi_pd_nsigma=0, 
     152        psi_pd=30, psi_pd_n=1, psi_pd_nsigma=0, 
     153        req_minor_pd=.1, req_minor_pd_n=1, req_minor_pd_nsigma=0, 
     154        req_major_pd=.1, req_major_pd_n=1, req_major_pd_nsigma=0, 
     155        rpolar_pd=.1, rpolar_pd_n=1, rpolar_pd_nsigma=0, 
     156        ) 
    153157 
    154158    # SET THE FITTING PARAMETERS 
     
    166170 
    167171model.cutoff = cutoff 
     172M = sas.Experiment(data=data, model=model) 
    168173if section == "both": 
    169    tan_model = sas.BumpsModel(tan_data, model.model, model.parameters()) 
     174   tan_model = sas.Model(model.kernel, **model.parameters()) 
    170175   tan_model.phi = model.phi - 90 
    171176   tan_model.cutoff = cutoff 
    172    problem = FitProblem([model, tan_model]) 
     177   tan_M = sas.Experiment(data=tan_data, model=tan_model) 
     178   problem = FitProblem([M, tan_M]) 
    173179else: 
    174    problem = FitProblem(model) 
     180   problem = FitProblem(M) 
  • example/sesansfit.py

    rc210c94 r346bc88  
    1 import numpy as np 
    21from bumps.names import * 
    32 
    43from sasmodels import core, bumps_model 
    54 
    6 kernel = core.load_model("sphere", dtype='single') 
    7  
    8  
    9  
    105if True: # fix when data loader exists 
    116#    from sas.dataloader.readers\ 
    127    from sas.dataloader.loader import Loader 
    13     loader=Loader() 
     8    loader = Loader() 
    149    filename = 'testsasview1.ses' 
    15     data=loader.load(filename) 
     10    data = loader.load(filename) 
    1611    if data is None: raise IOError("Could not load file %r"%(filename,)) 
    17     data.x /=10 
     12    data.x /= 10 
    1813#    print data 
    1914#    data = load_sesans('mydatfile.pz') 
     
    4338##  Sphere parameters 
    4439 
     40kernel = core.load_model("sphere", dtype='single') 
    4541phi = Parameter(0.1, name="phi") 
    46 model = bumps_model.BumpsModel(data, kernel, 
    47     scale=phi*(1-phi), sld=7.0, solvent_sld=1.0, radius=radius) 
     42model = bumps_model.Model(kernel, 
     43    scale=phi*(1-phi), sld=7.0, solvent_sld=1.0, radius=radius, 
     44    ) 
    4845phi.range(0.001,0.5) 
    4946#model.radius.pmp(40) 
     
    5451#model.radius_pd_n=0 
    5552 
    56 if False: # have sans data 
    57     sansmodel = bumps_model.BumpsModel(sans_data, kernel, **model.parameters()) 
    58     problem = FitProblem([model, sansmodel]) 
    59 else: 
    60     problem = FitProblem(model) 
    61  
    62  
    6353### Tri-Axial Ellipsoid 
    6454# 
     55#kernel = core.load_model("triaxial_ellipsoid", dtype='single') 
    6556#phi = Parameter(0.1, name='phi') 
    66 #model = sas.BumpsModel(data, kernel, 
    67 #    scale=phi*(1-phi), sld=7.0, solvent_sld=1.0, radius=radius) 
     57#model = bumps_model.Model(kernel, 
     58#    scale=phi*(1-phi), sld=7.0, solvent_sld=1.0, radius=radius, 
     59#    ) 
    6860#phi.range(0.001,0.90) 
    6961##model.radius.pmp(40) 
     
    7163##model.sld.pmp(5) 
    7264##model.background 
    73 ##model.radius_pd=0 
    74 ##model.radius_pd_n=0 
    75 # 
    76 #if False: # have sans data 
    77 #    sansmodel = sas.BumpsModel(sans_data, kernel, **model.parameters()) 
    78 #    problem = FitProblem([model, sansmodel]) 
    79 #else: 
    80 #    problem = FitProblem(model) 
     65##model.radius_pd = 0 
     66##model.radius_pd_n = 0 
     67 
     68if False: # have sans data 
     69    M_sesans = bumps_model.Experiment(data=data, model=model) 
     70    M_sans = bumps_model.Experiment(data=sans_data, model=model) 
     71    problem = FitProblem([M_sesans, M_sans]) 
     72else: 
     73    M_sesans = bumps_model.Experiment(data=data, model=model) 
     74    problem = FitProblem(M_sesans) 
     75 
  • sasmodels/bumps_model.py

    r0656250 r346bc88  
    11""" 
    22Wrap sasmodels for direct use by bumps. 
     3 
     4:class:`Model` is a wrapper for the sasmodels kernel which defines a 
     5bumps *Parameter* box for each kernel parameter.  *Model* accepts keyword 
     6arguments to set the initial value for each parameter. 
     7 
     8:class:`Experiment` combines the *Model* function with a data file loaded by the 
     9sasview data loader.  *Experiment* takes a *cutoff* parameter controlling 
     10how far the polydispersity integral extends. 
     11 
     12A variety of helper functions are provided: 
     13 
     14    :func:`load_data` loads a sasview data file. 
     15 
     16    :func:`empty_data1D` creates an empty dataset, which is useful for plotting 
     17    a theory function before the data is measured. 
     18 
     19    :func:`empty_data2D` creates an empty 2D dataset. 
     20 
     21    :func:`set_beam_stop` masks the beam stop from the data. 
     22 
     23    :func:`set_half` selects the right or left half of the data, which can 
     24    be useful for shear measurements which have not been properly corrected 
     25    for path length and reflections. 
     26 
     27    :func:`set_top` cuts the top part off the data. 
     28 
     29    :func:`plot_data` plots the data file. 
     30 
     31    :func:`plot_theory` plots a calculated result from the model. 
     32 
    333""" 
    434 
    535import datetime 
     36import warnings 
    637 
    738import numpy as np 
    839 
    940from . import sesans 
     41from .resolution import Perfect1D, Pinhole1D, Slit1D 
     42from .resolution2d import Pinhole2D 
    1043 
    1144# CRUFT python 2.6 
     
    2053 
    2154 
     55# CRUFT: old style bumps wrapper which doesn't separate data and model 
     56def BumpsModel(data, model, cutoff=1e-5, **kw): 
     57    warnings.warn("Use of BumpsModel is deprecated.  Use bumps_model.Experiment instead.") 
     58    model = Model(model, **kw) 
     59    experiment = Experiment(data=data, model=model, cutoff=cutoff) 
     60    for k in model._parameter_names: 
     61        setattr(experiment, k, getattr(model, k)) 
     62    return experiment 
     63 
     64 
     65 
    2266def tic(): 
    2367    """ 
     
    4286    return data 
    4387 
    44  
    45 def empty_data1D(q): 
     88def plot_data(data, view='log'): 
     89    """ 
     90    Plot data loaded by the sasview loader. 
     91    """ 
     92    if hasattr(data, 'qx_data'): 
     93        _plot_2d_signal(data, data.data, view=view) 
     94    else: 
     95        # Note: kind of weird using the _plot_result1D to plot just the 
     96        # data, but it handles the masking and graph markup already, so 
     97        # do not repeat. 
     98        _plot_result1D(data, None, None, view) 
     99 
     100def plot_theory(data, theory, view='log'): 
     101    if hasattr(data, 'qx_data'): 
     102        _plot_2d_signal(data, theory, view=view) 
     103    else: 
     104        _plot_result1D(data, theory, None, view, include_data=False) 
     105 
     106 
     107def empty_data1D(q, resolution=0.05): 
    46108    """ 
    47109    Create empty 1D data using the given *q* as the x value. 
    48110 
    49     Resolutions dq/q is 5%. 
     111    *resolution* dq/q defaults to 5%. 
    50112    """ 
    51113 
     
    54116    Iq = 100 * np.ones_like(q) 
    55117    dIq = np.sqrt(Iq) 
    56     data = Data1D(q, Iq, dx=0.05 * q, dy=dIq) 
     118    data = Data1D(q, Iq, dx=resolution * q, dy=dIq) 
    57119    data.filename = "fake data" 
    58120    data.qmin, data.qmax = q.min(), q.max() 
     121    data.mask = np.zeros(len(Iq), dtype='bool') 
    59122    return data 
    60123 
    61124 
    62 def empty_data2D(qx, qy=None): 
     125def empty_data2D(qx, qy=None, resolution=0.05): 
    63126    """ 
    64127    Create empty 2D data using the given mesh. 
     
    66129    If *qy* is missing, create a square mesh with *qy=qx*. 
    67130 
    68     Resolution dq/q is 5%. 
     131    *resolution* dq/q defaults to 5%. 
    69132    """ 
    70133    from sas.dataloader.data_info import Data2D, Detector 
     
    85148    data.err_data = dIq 
    86149    data.mask = mask 
     150    data.qmin = 1e-16 
     151    data.qmax = np.inf 
    87152 
    88153    # 5% dQ/Q resolution 
    89     data.dqx_data = 0.05 * Qx 
    90     data.dqy_data = 0.05 * Qy 
     154    if resolution != 0: 
     155        data.dqx_data = resolution * Qx 
     156        data.dqy_data = resolution * Qy 
    91157 
    92158    detector = Detector() 
     
    145211 
    146212 
    147 def plot_data(data, Iq, vmin=None, vmax=None, view='log'): 
    148     """ 
    149     Plot the target value for the data.  This could be the data itself, 
    150     the theory calculation, or the residuals. 
    151  
    152     *scale* can be 'log' for log scale data, or 'linear'. 
    153     """ 
    154     from numpy.ma import masked_array 
    155     import matplotlib.pyplot as plt 
    156     if hasattr(data, 'qx_data'): 
    157         Iq = Iq + 0 
    158         valid = np.isfinite(Iq) 
    159         if view == 'log': 
    160             valid[valid] = (Iq[valid] > 0) 
    161             Iq[valid] = np.log10(Iq[valid]) 
    162         elif view == 'q4': 
    163             Iq[valid] = Iq*(data.qx_data[valid]**2+data.qy_data[valid]**2)**2 
    164         Iq[~valid | data.mask] = 0 
    165         #plottable = Iq 
    166         plottable = masked_array(Iq, ~valid | data.mask) 
    167         xmin, xmax = min(data.qx_data), max(data.qx_data) 
    168         ymin, ymax = min(data.qy_data), max(data.qy_data) 
    169         try: 
    170             if vmin is None: vmin = Iq[valid & ~data.mask].min() 
    171             if vmax is None: vmax = Iq[valid & ~data.mask].max() 
    172         except: 
    173             vmin, vmax = 0, 1 
    174         plt.imshow(plottable.reshape(128, 128), 
    175                    interpolation='nearest', aspect=1, origin='upper', 
    176                    extent=[xmin, xmax, ymin, ymax], vmin=vmin, vmax=vmax) 
    177     else: # 1D data 
    178         if view == 'linear' or view == 'q4': 
    179             #idx = np.isfinite(Iq) 
    180             scale = data.x**4 if view == 'q4' else 1.0 
    181             plt.plot(data.x, scale*Iq) #, '.') 
    182         else: 
    183             # Find the values that are finite and positive 
    184             idx = np.isfinite(Iq) 
    185             idx[idx] = (Iq[idx] > 0) 
    186             Iq[~idx] = np.nan 
    187             plt.loglog(data.x, Iq) 
    188  
    189  
    190 def _plot_result1D(data, theory, view): 
     213def _plot_result1D(data, theory, resid, view, include_data=True): 
    191214    """ 
    192215    Plot the data and residuals for 1D data. 
     
    197220    #data.y[data.y<0.05] = 0.5 
    198221    mdata = masked_array(data.y, data.mask) 
    199     mdata[np.isnan(mdata)] = masked 
     222    mdata[~np.isfinite(mdata)] = masked 
    200223    if view is 'log': 
    201224        mdata[mdata <= 0] = masked 
    202     mtheory = masked_array(theory, mdata.mask) 
    203     mresid = masked_array((theory - data.y) / data.dy, mdata.mask) 
    204225 
    205226    scale = data.x**4 if view == 'q4' else 1.0 
    206     plt.subplot(121) 
    207     plt.errorbar(data.x, scale*mdata, yerr=data.dy) 
    208     plt.plot(data.x, scale*mtheory, '-', hold=True) 
     227    if resid is not None: 
     228        plt.subplot(121) 
     229 
     230    if include_data: 
     231        plt.errorbar(data.x, scale*mdata, yerr=data.dy, fmt='.') 
     232    if theory is not None: 
     233        mtheory = masked_array(theory, mdata.mask) 
     234        plt.plot(data.x, scale*mtheory, '-', hold=True) 
     235    plt.xscale(view) 
    209236    plt.yscale('linear' if view == 'q4' else view) 
    210     plt.subplot(122) 
    211     plt.plot(data.x, mresid, 'x') 
     237    plt.xlabel('Q') 
     238    plt.ylabel('I(Q)') 
     239    if resid is not None: 
     240        mresid = masked_array(resid, mdata.mask) 
     241        plt.subplot(122) 
     242        plt.plot(data.x, mresid, 'x') 
     243        plt.ylabel('residuals') 
     244        plt.xlabel('Q') 
     245        plt.xscale(view) 
    212246 
    213247# pylint: disable=unused-argument 
    214 def _plot_sesans(data, theory, view): 
     248def _plot_sesans(data, theory, resid, view): 
    215249    import matplotlib.pyplot as plt 
    216     resid = (theory - data.y) / data.dy 
    217250    plt.subplot(121) 
    218251    plt.errorbar(data.x, data.y, yerr=data.dy) 
     
    225258    plt.ylabel('residuals (P/P0)') 
    226259 
    227 def _plot_result2D(data, theory, view): 
     260def _plot_result2D(data, theory, resid, view): 
    228261    """ 
    229262    Plot the data and residuals for 2D data. 
    230263    """ 
    231264    import matplotlib.pyplot as plt 
    232     resid = (theory - data.data) / data.err_data 
     265    target = data.data[~data.mask] 
     266    if view == 'log': 
     267        vmin = min(target[target>0].min(), theory[theory>0].min()) 
     268        vmax = max(target.max(), theory.max()) 
     269    else: 
     270        vmin = min(target.min(), theory.min()) 
     271        vmax = max(target.max(), theory.max()) 
     272    #print vmin, vmax 
    233273    plt.subplot(131) 
    234     plot_data(data, data.data, view=view) 
     274    _plot_2d_signal(data, target, view=view, vmin=vmin, vmax=vmax) 
     275    plt.title('data') 
    235276    plt.colorbar() 
    236277    plt.subplot(132) 
    237     plot_data(data, theory, view=view) 
     278    _plot_2d_signal(data, theory, view=view, vmin=vmin, vmax=vmax) 
     279    plt.title('theory') 
    238280    plt.colorbar() 
    239281    plt.subplot(133) 
    240     plot_data(data, resid, view='linear') 
     282    _plot_2d_signal(data, resid, view='linear') 
     283    plt.title('residuals') 
    241284    plt.colorbar() 
    242285 
    243 class BumpsModel(object): 
    244     """ 
    245     Return a bumps wrapper for a SAS model. 
    246  
    247     *data* is the data to be fitted. 
    248  
    249     *model* is the SAS model from :func:`core.load_model`. 
    250  
    251     *cutoff* is the integration cutoff, which avoids computing the 
    252     the SAS model where the polydispersity weight is low. 
    253  
    254     Model parameters can be initialized with additional keyword 
    255     arguments, or by assigning to model.parameter_name.value. 
    256  
    257     The resulting bumps model can be used directly in a FitProblem call. 
    258     """ 
    259     def __init__(self, data, model, cutoff=1e-5, **kw): 
     286def _plot_2d_signal(data, signal, vmin=None, vmax=None, view='log'): 
     287    """ 
     288    Plot the target value for the data.  This could be the data itself, 
     289    the theory calculation, or the residuals. 
     290 
     291    *scale* can be 'log' for log scale data, or 'linear'. 
     292    """ 
     293    import matplotlib.pyplot as plt 
     294    from numpy.ma import masked_array 
     295 
     296    image = np.zeros_like(data.qx_data) 
     297    image[~data.mask] = signal 
     298    valid = np.isfinite(image) 
     299    if view == 'log': 
     300        valid[valid] = (image[valid] > 0) 
     301        image[valid] = np.log10(image[valid]) 
     302    elif view == 'q4': 
     303        image[valid] *= (data.qx_data[valid]**2+data.qy_data[valid]**2)**2 
     304    image[~valid | data.mask] = 0 
     305    #plottable = Iq 
     306    plottable = masked_array(image, ~valid | data.mask) 
     307    xmin, xmax = min(data.qx_data), max(data.qx_data) 
     308    ymin, ymax = min(data.qy_data), max(data.qy_data) 
     309    # TODO: fix vmin, vmax so it is shared for theory/resid 
     310    vmin = vmax = None 
     311    try: 
     312        if vmin is None: vmin = image[valid & ~data.mask].min() 
     313        if vmax is None: vmax = image[valid & ~data.mask].max() 
     314    except: 
     315        vmin, vmax = 0, 1 
     316    #print vmin,vmax 
     317    plt.imshow(plottable.reshape(128, 128), 
     318               interpolation='nearest', aspect=1, origin='upper', 
     319               extent=[xmin, xmax, ymin, ymax], vmin=vmin, vmax=vmax) 
     320 
     321 
     322class Model(object): 
     323    def __init__(self, kernel, **kw): 
    260324        from bumps.names import Parameter 
    261325 
    262         # remember inputs so we can inspect from outside 
    263         self.data = data 
    264         self.model = model 
    265         self.cutoff = cutoff 
    266         if hasattr(data, 'lam'): 
    267             self.data_type = 'sesans' 
    268         elif hasattr(data, 'qx_data'): 
    269             self.data_type = 'Iqxy' 
    270         else: 
    271             self.data_type = 'Iq' 
    272  
    273         partype = model.info['partype'] 
    274  
    275         # interpret data 
    276         if self.data_type == 'sesans': 
    277             q = sesans.make_q(data.sample.zacceptance, data.Rmax) 
    278             self.index = slice(None, None) 
    279             self.Iq = data.y 
    280             self.dIq = data.dy 
    281             self._theory = np.zeros_like(q) 
    282             q_vectors = [q] 
    283         elif self.data_type == 'Iqxy': 
    284             self.index = (data.mask == 0) & (~np.isnan(data.data)) 
    285             self.Iq = data.data[self.index] 
    286             self.dIq = data.err_data[self.index] 
    287             self._theory = np.zeros_like(data.data) 
    288             if not partype['orientation'] and not partype['magnetic']: 
    289                 q_vectors = [np.sqrt(data.qx_data ** 2 + data.qy_data ** 2)] 
    290             else: 
    291                 q_vectors = [data.qx_data, data.qy_data] 
    292         elif self.data_type == 'Iq': 
    293             self.index = (data.x >= data.qmin) & (data.x <= data.qmax) & ~np.isnan(data.y) 
    294             self.Iq = data.y[self.index] 
    295             self.dIq = data.dy[self.index] 
    296             self._theory = np.zeros_like(data.y) 
    297             q_vectors = [data.x] 
    298         else: 
    299             raise ValueError("Unknown data type") # never gets here 
    300  
    301         # Remember function inputs so we can delay loading the function and 
    302         # so we can save/restore state 
    303         self._fn_inputs = [v[self.index] for v in q_vectors] 
    304         self._fn = None 
    305  
    306         # define bumps parameters 
     326        self.kernel = kernel 
     327        partype = kernel.info['partype'] 
     328 
    307329        pars = [] 
    308         for p in model.info['parameters']: 
     330        for p in kernel.info['parameters']: 
    309331            name, default, limits = p[0], p[2], p[3] 
    310332            value = kw.pop(name, default) 
     
    313335        for name in partype['pd-2d']: 
    314336            for xpart, xdefault, xlimits in [ 
    315                     ('_pd', 0, limits), 
    316                     ('_pd_n', 35, (0, 1000)), 
    317                     ('_pd_nsigma', 3, (0, 10)), 
    318                     ('_pd_type', 'gaussian', None), 
     337                ('_pd', 0, limits), 
     338                ('_pd_n', 35, (0, 1000)), 
     339                ('_pd_nsigma', 3, (0, 10)), 
     340                ('_pd_type', 'gaussian', None), 
    319341                ]: 
    320342                xname = name + xpart 
     
    328350            raise TypeError("unexpected parameters: %s" 
    329351                            % (", ".join(sorted(kw.keys())))) 
     352 
     353    def parameters(self): 
     354        """ 
     355        Return a dictionary of parameters 
     356        """ 
     357        return dict((k, getattr(self, k)) for k in self._parameter_names) 
     358 
     359class Experiment(object): 
     360    """ 
     361    Return a bumps wrapper for a SAS model. 
     362 
     363    *data* is the data to be fitted. 
     364 
     365    *model* is the SAS model from :func:`core.load_model`. 
     366 
     367    *cutoff* is the integration cutoff, which avoids computing the 
     368    the SAS model where the polydispersity weight is low. 
     369 
     370    Model parameters can be initialized with additional keyword 
     371    arguments, or by assigning to model.parameter_name.value. 
     372 
     373    The resulting bumps model can be used directly in a FitProblem call. 
     374    """ 
     375    def __init__(self, data, model, cutoff=1e-5): 
     376 
     377        # remember inputs so we can inspect from outside 
     378        self.data = data 
     379        self.model = model 
     380        self.cutoff = cutoff 
     381        if hasattr(data, 'lam'): 
     382            self.data_type = 'sesans' 
     383        elif hasattr(data, 'qx_data'): 
     384            self.data_type = 'Iqxy' 
     385        else: 
     386            self.data_type = 'Iq' 
     387 
     388        # interpret data 
     389        partype = model.kernel.info['partype'] 
     390        if self.data_type == 'sesans': 
     391            q = sesans.make_q(data.sample.zacceptance, data.Rmax) 
     392            self.index = slice(None, None) 
     393            self.Iq = data.y 
     394            self.dIq = data.dy 
     395            #self._theory = np.zeros_like(q) 
     396            q_vectors = [q] 
     397        elif self.data_type == 'Iqxy': 
     398            q = np.sqrt(data.qx_data**2 + data.qy_data**2) 
     399            qmin = getattr(data, 'qmin', 1e-16) 
     400            qmax = getattr(data, 'qmax', np.inf) 
     401            self.index = (~data.mask) & (~np.isnan(data.data)) \ 
     402                         & (q >= qmin) & (q <= qmax) 
     403            self.Iq = data.data[self.index] 
     404            self.dIq = data.err_data[self.index] 
     405            self.resolution = Pinhole2D(data=data, index=self.index, 
     406                                        nsigma=3.0, accuracy='Low') 
     407            #self._theory = np.zeros_like(self.Iq) 
     408            if not partype['orientation'] and not partype['magnetic']: 
     409                raise ValueError("not 2D without orientation or magnetic parameters") 
     410                #qx,qy = self.resolution.q_calc 
     411                #q_vectors = [np.sqrt(qx**2 + qy**2)] 
     412            else: 
     413                q_vectors = self.resolution.q_calc 
     414        elif self.data_type == 'Iq': 
     415            self.index = (data.x >= data.qmin) & (data.x <= data.qmax) & ~np.isnan(data.y) 
     416            self.Iq = data.y[self.index] 
     417            self.dIq = data.dy[self.index] 
     418            if getattr(data, 'dx', None) is not None: 
     419                q, dq = data.x[self.index], data.dx[self.index] 
     420                if (dq>0).any(): 
     421                    self.resolution = Pinhole1D(q, dq) 
     422                else: 
     423                    self.resolution = Perfect1D(q) 
     424            elif (getattr(data, 'dxl', None) is not None and 
     425                  getattr(data, 'dxw', None) is not None): 
     426                q = data.x[self.index] 
     427                width = data.dxh[self.index]  # Note: dx 
     428                self.resolution = Slit1D(data.x[self.index], 
     429                                         width=data.dxh[self.index], 
     430                                         height=data.dxw[self.index]) 
     431            else: 
     432                self.resolution = Perfect1D(data.x[self.index]) 
     433 
     434            #self._theory = np.zeros_like(self.Iq) 
     435            q_vectors = [self.resolution.q_calc] 
     436        else: 
     437            raise ValueError("Unknown data type") # never gets here 
     438 
     439        # Remember function inputs so we can delay loading the function and 
     440        # so we can save/restore state 
     441        self._fn_inputs = [v for v in q_vectors] 
     442        self._fn = None 
     443 
    330444        self.update() 
    331445 
     
    341455    def parameters(self): 
    342456        """ 
    343             Return a dictionary of parameters 
    344         """ 
    345         return dict((k, getattr(self, k)) for k in self._parameter_names) 
     457        Return a dictionary of parameters 
     458        """ 
     459        return self.model.parameters() 
    346460 
    347461    def theory(self): 
    348462        if 'theory' not in self._cache: 
    349463            if self._fn is None: 
    350                 q_input = self.model.make_input(self._fn_inputs) 
    351                 self._fn = self.model(q_input) 
    352  
    353             fixed_pars = [getattr(self, p).value for p in self._fn.fixed_pars] 
     464                q_input = self.model.kernel.make_input(self._fn_inputs) 
     465                self._fn = self.model.kernel(q_input) 
     466 
     467            fixed_pars = [getattr(self.model, p).value for p in self._fn.fixed_pars] 
    354468            pd_pars = [self._get_weights(p) for p in self._fn.pd_pars] 
    355469            #print fixed_pars,pd_pars 
    356             self._theory[self.index] = self._fn(fixed_pars, pd_pars, self.cutoff) 
     470            Iq_calc = self._fn(fixed_pars, pd_pars, self.cutoff) 
    357471            #self._theory[:] = self._fn.eval(pars, pd_pars) 
    358472            if self.data_type == 'sesans': 
    359473                result = sesans.hankel(self.data.x, self.data.lam * 1e-9, 
    360474                                       self.data.sample.thickness / 10, 
    361                                        self._fn_inputs[0], self._theory) 
     475                                       self._fn_inputs[0], Iq_calc) 
    362476                self._cache['theory'] = result 
    363477            else: 
    364                 self._cache['theory'] = self._theory 
     478                Iq = self.resolution.apply(Iq_calc) 
     479                self._cache['theory'] = Iq 
    365480        return self._cache['theory'] 
    366481 
    367482    def residuals(self): 
    368483        #if np.any(self.err ==0): print "zeros in err" 
    369         return (self.theory()[self.index] - self.Iq) / self.dIq 
     484        return (self.theory() - self.Iq) / self.dIq 
    370485 
    371486    def nllf(self): 
     
    381496        Plot the data and residuals. 
    382497        """ 
    383         data, theory = self.data, self.theory() 
     498        data, theory, resid = self.data, self.theory(), self.residuals() 
    384499        if self.data_type == 'Iq': 
    385             _plot_result1D(data, theory, view) 
     500            _plot_result1D(data, theory, resid, view) 
    386501        elif self.data_type == 'Iqxy': 
    387             _plot_result2D(data, theory, view) 
     502            _plot_result2D(data, theory, resid, view) 
    388503        elif self.data_type == 'sesans': 
    389             _plot_sesans(data, theory, view) 
     504            _plot_sesans(data, theory, resid, view) 
    390505        else: 
    391506            raise ValueError("Unknown data type") 
    392507 
    393508    def simulate_data(self, noise=None): 
    394         print "noise", noise 
    395         if noise is None: 
    396             noise = self.dIq[self.index] 
    397         else: 
    398             noise = 0.01 * noise 
    399             self.dIq[self.index] = noise 
    400         y = self.theory() 
    401         y += y * np.random.randn(*y.shape) * noise 
     509        theory = self.theory() 
     510        if noise is not None: 
     511            self.dIq = theory*noise*0.01 
     512        dy = self.dIq 
     513        y = theory + np.random.randn(*dy.shape) * dy 
     514        self.Iq = y 
    402515        if self.data_type == 'Iq': 
     516            self.data.dy[self.index] = dy 
    403517            self.data.y[self.index] = y 
    404518        elif self.data_type == 'Iqxy': 
     
    418532        from . import weights 
    419533 
    420         relative = self.model.info['partype']['pd-rel'] 
    421         limits = self.model.info['limits'] 
     534        relative = self.model.kernel.info['partype']['pd-rel'] 
     535        limits = self.model.kernel.info['limits'] 
    422536        disperser, value, npts, width, nsigma = [ 
    423             getattr(self, par + ext) 
     537            getattr(self.model, par + ext) 
    424538            for ext in ('_pd_type', '', '_pd_n', '_pd', '_pd_nsigma')] 
    425539        value, weight = weights.get_weights( 
     
    442556    data = load_data('DEC07086.DAT') 
    443557    set_beam_stop(data, 0.004) 
    444     plot_data(data, data.data) 
     558    plot_data(data) 
    445559    import matplotlib.pyplot as plt; plt.show() 
    446560 
  • sasmodels/resolution.py

    rf1b8c90 r346bc88  
    1111MINIMUM_RESOLUTION = 1e-8 
    1212 
    13 class Resolution1D(object): 
     13class Resolution(object): 
    1414    """ 
    1515    Abstract base class defining a 1D resolution function. 
     
    3232 
    3333 
    34 class Perfect1D(Resolution1D): 
     34class Perfect1D(Resolution): 
    3535    """ 
    3636    Resolution function to use when there is no actual resolution smearing 
     
    4545 
    4646 
    47 class Pinhole1D(Resolution1D): 
     47class Pinhole1D(Resolution): 
    4848    r""" 
    4949    Pinhole aperture with q-dependent gaussian resolution. 
     
    7474 
    7575    def apply(self, theory): 
     76        print "q calc", self.q_calc 
     77        print "weights", self.weight_matrix.shape 
    7678        return apply_resolution_matrix(self.weight_matrix, theory) 
    7779 
    7880 
    79 class Slit1D(Resolution1D): 
     81class Slit1D(Resolution): 
    8082    """ 
    8183    Slit aperture with a complicated resolution function. 
Note: See TracChangeset for help on using the changeset viewer.