Changeset 7cf2cfd in sasmodels
- Timestamp:
- Nov 22, 2015 11:37:15 PM (9 years ago)
- 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:
- 3b4243d
- Parents:
- 677ccf1
- Files:
-
- 1 added
- 1 deleted
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
compare.py
r29fc2a3 r7cf2cfd 6 6 from os.path import basename, dirname, join as joinpath 7 7 import glob 8 import datetime 8 9 9 10 import numpy as np … … 13 14 14 15 15 from sasmodels.bumps_model import Model, Experiment, plot_theory, tic16 16 from sasmodels import core 17 17 from sasmodels import kerneldll 18 from sasmodels.data import plot_theory, empty_data1D, empty_data2D 19 from sasmodels.direct_model import DirectModel 18 20 from sasmodels.convert import revert_model 19 21 kerneldll.ALLOW_SINGLE_PRECISION_DLLS = True … … 22 24 MODELS = [basename(f)[:-3] 23 25 for f in sorted(glob.glob(joinpath(ROOT,"sasmodels","models","[a-zA-Z]*.py")))] 26 27 # CRUFT python 2.6 28 if not hasattr(datetime.timedelta, 'total_seconds'): 29 def delay(dt): 30 """Return number date-time delta as number seconds""" 31 return dt.days * 86400 + dt.seconds + 1e-6 * dt.microseconds 32 else: 33 def delay(dt): 34 """Return number date-time delta as number seconds""" 35 return dt.total_seconds() 36 37 38 def tic(): 39 """ 40 Timer function. 41 42 Use "toc=tic()" to start the clock and "toc()" to measure 43 a time interval. 44 """ 45 then = datetime.datetime.now() 46 return lambda: delay(datetime.datetime.now() - then) 47 48 49 def set_beam_stop(data, radius, outer=None): 50 """ 51 Add a beam stop of the given *radius*. If *outer*, make an annulus. 52 53 Note: this function does not use the sasview package 54 """ 55 if hasattr(data, 'qx_data'): 56 q = np.sqrt(data.qx_data**2 + data.qy_data**2) 57 data.mask = (q < radius) 58 if outer is not None: 59 data.mask |= (q >= outer) 60 else: 61 data.mask = (data.x < radius) 62 if outer is not None: 63 data.mask |= (data.x >= outer) 24 64 25 65 … … 99 139 if p.endswith("_pd"): pars[p] = 0 100 140 101 def eval_sasview( name, pars, data, Nevals=1):141 def eval_sasview(model_definition, pars, data, Nevals=1): 102 142 from sas.models.qsmearing import smear_selection 103 model = sasview_model( name, **pars)143 model = sasview_model(model_definition, **pars) 104 144 smearer = smear_selection(data, model=model) 105 145 value = None # silence the linter … … 131 171 print "... trying again with single precision" 132 172 model = core.load_model(model_definition, dtype='single', platform="ocl") 133 problem = Experiment(data, Model(model, **pars), cutoff=cutoff)173 calculator = DirectModel(data, model, cutoff=cutoff) 134 174 value = None # silence the linter 135 175 toc = tic() 136 176 for _ in range(max(Nevals, 1)): # force at least one eval 137 #pars['scale'] = np.random.rand() 138 problem.update() 139 value = problem.theory() 177 value = calculator(**pars) 140 178 average_time = toc()*1000./Nevals 141 179 return value, average_time 142 180 181 143 182 def eval_ctypes(model_definition, pars, data, dtype='double', Nevals=1, cutoff=0.): 144 183 model = core.load_model(model_definition, dtype=dtype, platform="dll") 145 problem = Experiment(data, Model(model, **pars), cutoff=cutoff)184 calculator = DirectModel(data, model, cutoff=cutoff) 146 185 value = None # silence the linter 147 186 toc = tic() 148 187 for _ in range(max(Nevals, 1)): # force at least one eval 149 problem.update() 150 value = problem.theory() 188 value = calculator(**pars) 151 189 average_time = toc()*1000./Nevals 152 190 return value, average_time 153 191 192 154 193 def make_data(qmax, is2D, Nq=128, resolution=0.0, accuracy='Low', view='log'): 155 194 if is2D: 156 from sasmodels.bumps_model import empty_data2D, set_beam_stop157 195 data = empty_data2D(np.linspace(-qmax, qmax, Nq), resolution=resolution) 158 196 data.accuracy = accuracy … … 160 198 index = ~data.mask 161 199 else: 162 from sasmodels.bumps_model import empty_data1D163 200 if view == 'log': 164 201 qmax = math.log10(qmax) … … 190 227 191 228 # randomize parameters 192 pars.update(set_pars)229 #pars.update(set_pars) # set value before random to control range 193 230 if '-random' in opts or '-random' in opt_values: 194 231 seed = int(opt_values['-random']) if '-random' in opt_values else None 195 232 pars, seed = randomize_model(name, pars, seed=seed) 196 233 print "Randomize using -random=%i"%seed 234 pars.update(set_pars) # set value after random to control value 197 235 198 236 # parameter selection … … 217 255 print "ctypes t=%.1f ms, intensity=%.0f"%(cpu_time, sum(cpu)) 218 256 elif Ncpu > 0: 219 cpu, cpu_time = eval_sasview(model_definition, pars, data, Ncpu) 220 comp = "sasview" 221 print "sasview t=%.1f ms, intensity=%.0f"%(cpu_time, sum(cpu)) 257 try: 258 cpu, cpu_time = eval_sasview(model_definition, pars, data, Ncpu) 259 comp = "sasview" 260 #print "ocl/sasview", (ocl-pars['background'])/(cpu-pars['background']) 261 print "sasview t=%.1f ms, intensity=%.0f"%(cpu_time, sum(cpu)) 262 except ImportError: 263 Ncpu = 0 222 264 223 265 # Compare, but only if computing both forms … … 238 280 if Ncpu > 0: 239 281 if Nocl > 0: plt.subplot(131) 240 plot_theory(data, cpu, view=view )282 plot_theory(data, cpu, view=view, plot_data=False) 241 283 plt.title("%s t=%.1f ms"%(comp,cpu_time)) 242 cbar_title = "log I"284 #cbar_title = "log I" 243 285 if Nocl > 0: 244 286 if Ncpu > 0: plt.subplot(132) 245 plot_theory(data, ocl, view=view )287 plot_theory(data, ocl, view=view, plot_data=False) 246 288 plt.title("opencl t=%.1f ms"%ocl_time) 247 cbar_title = "log I"289 #cbar_title = "log I" 248 290 if Ncpu > 0 and Nocl > 0: 249 291 plt.subplot(133) … … 253 295 err,errstr,errview = abs(relerr), "rel err", "log" 254 296 #err,errstr = ocl/cpu,"ratio" 255 plot_theory(data, err, view=errview)297 plot_theory(data, None, resid=err, view=errview, plot_data=False) 256 298 plt.title("max %s = %.3g"%(errstr, max(abs(err)))) 257 cbar_title = errstr if errview=="linear" else "log "+errstr258 if is2D:259 h = plt.colorbar()260 h.ax.set_title(cbar_title)299 #cbar_title = errstr if errview=="linear" else "log "+errstr 300 #if is2D: 301 # h = plt.colorbar() 302 # h.ax.set_title(cbar_title) 261 303 262 304 if Ncpu > 0 and Nocl > 0 and '-hist' in opts: … … 320 362 321 363 Available models: 322 323 %s324 364 """ 365 325 366 326 367 NAME_OPTIONS = set([ … … 342 383 ] 343 384 385 def columnize(L, indent="", width=79): 386 column_width = max(len(w) for w in L) + 1 387 num_columns = (width - len(indent)) // column_width 388 num_rows = len(L) // num_columns 389 L = L + [""] * (num_rows*num_columns - len(L)) 390 columns = [L[k*num_rows:(k+1)*num_rows] for k in range(num_columns)] 391 lines = [" ".join("%-*s"%(column_width, entry) for entry in row) 392 for row in zip(*columns)] 393 output = indent + ("\n"+indent).join(lines) 394 return output 395 396 344 397 def get_demo_pars(name): 345 398 import sasmodels.models … … 355 408 models = "\n ".join("%-15s"%v for v in MODELS) 356 409 if len(args) == 0: 357 print(USAGE%models) 410 print(USAGE) 411 print(columnize(MODELS, indent=" ")) 358 412 sys.exit(1) 359 413 if args[0] not in MODELS: -
compare_many.py
rab55943 r7cf2cfd 1 1 #!/usr/bin/env python 2 3 2 import sys 3 import traceback 4 4 5 5 import numpy as np 6 6 7 from sasmodels import core 7 8 from sasmodels.kernelcl import environment 8 9 from compare import (MODELS, randomize_model, suppress_pd, eval_sasview, 9 eval_opencl, eval_ctypes, make_data, get_demo_pars) 10 eval_opencl, eval_ctypes, make_data, get_demo_pars, 11 columnize) 10 12 11 13 def get_stats(target, value, index): … … 13 15 relerr = resid/target[index] 14 16 srel = np.argsort(relerr) 15 p90 = int(len(relerr)*0.90)17 #p90 = int(len(relerr)*0.90) 16 18 p95 = int(len(relerr)*0.95) 17 19 maxrel = np.max(relerr) … … 27 29 groups.append(p) 28 30 groups.extend(['']*(len(stats)-1)) 31 groups.append("Parameters") 29 32 columns = ['Seed'] + stats*len(parts) + list(sorted(pars.keys())) 30 33 print(','.join('"%s"'%c for c in groups)) … … 32 35 33 36 def compare_instance(name, data, index, N=1, mono=True, cutoff=1e-5): 37 model_definition = core.load_model_definition(name) 34 38 pars = get_demo_pars(name) 35 39 header = '\n"Model","%s","Count","%d"'%(name, N) 36 40 if not mono: header += ',"Cutoff",%g'%(cutoff,) 37 41 print(header) 42 43 # Stuff the failure flag into a mutable object so we can update it from 44 # within the nested function. Note that the nested function uses "pars" 45 # which is dynamically scoped, not lexically scoped in this context. That 46 # is, pars is replaced each time in the loop, so don't assume that it is 47 # the default values defined above. 48 def trymodel(fn, *args, **kw): 49 try: 50 result, _ = fn(model_definition, pars, data, *args, **kw) 51 except: 52 result = np.NaN 53 traceback.print_exc() 54 return result 55 56 num_good = 0 38 57 first = True 39 58 for _ in range(N): … … 41 60 if mono: suppress_pd(pars) 42 61 43 target, _ = eval_sasview(name, pars, data) 62 # Force parameter constraints on a per-model basis. 63 if name in ('teubner_strey','broad_peak'): 64 pars['scale'] = 1.0 65 #if name == 'parallelepiped': 66 # pars['a_side'],pars['b_side'],pars['c_side'] = \ 67 # sorted([pars['a_side'],pars['b_side'],pars['c_side']]) 44 68 45 env = environment() 46 gpu_single_value,_ = eval_opencl(name, pars, data, dtype='single', cutoff=cutoff) 47 gpu_single = get_stats(target, gpu_single_value, index) 48 if env.has_double: 49 gpu_double_value,_ = eval_opencl(name, pars, data, dtype='double', cutoff=cutoff) 50 gpu_double = get_stats(target, gpu_double_value, index) 69 70 good = True 71 labels = [] 72 columns = [] 73 if 1: 74 sasview_value = trymodel(eval_sasview) 75 if 0: 76 gpu_single_value = trymodel(eval_opencl, dtype='single', cutoff=cutoff) 77 stats = get_stats(sasview_value, gpu_single_value, index) 78 columns.extend(stats) 79 labels.append('GPU single') 80 good = good and (stats[0] < 1e-14) 81 if 0 and environment().has_double: 82 gpu_double_value = trymodel(eval_opencl, dtype='double', cutoff=cutoff) 83 stats = get_stats(sasview_value, gpu_double_value, index) 84 columns.extend(stats) 85 labels.append('GPU double') 86 good = good and (stats[0] < 1e-14) 87 if 1: 88 cpu_double_value = trymodel(eval_ctypes, dtype='double', cutoff=cutoff) 89 stats = get_stats(sasview_value, cpu_double_value, index) 90 columns.extend(stats) 91 labels.append('CPU double') 92 good = good and (stats[0] < 1e-14) 93 if 0: 94 stats = get_stats(cpu_double_value, gpu_single_value, index) 95 columns.extend(stats) 96 labels.append('single/double') 97 good = good and (stats[0] < 1e-14) 98 99 columns += [v for _,v in sorted(pars.items())] 100 if first: 101 print_column_headers(pars, labels) 102 first = False 103 if good: 104 num_good += 1 51 105 else: 52 gpu_double = [0]*len(gpu_single) 53 cpu_double_value,_ = eval_ctypes(name, pars, data, dtype='double', cutoff=cutoff) 54 cpu_double = get_stats(target, cpu_double_value, index) 55 single_double = get_stats(cpu_double_value, gpu_single_value, index) 106 print(("%d,"%seed)+','.join("%g"%v for v in columns)) 107 print '"%d/%d good"'%(num_good, N) 56 108 57 values = (list(gpu_single) + list(gpu_double) + list(cpu_double)58 + list(single_double) + [v for _,v in sorted(pars.items())])59 if gpu_single[0] > 5e-5:60 if first:61 print_column_headers(pars,'GPU single|GPU double|CPU double|single/double'.split('|'))62 first = False63 print(("%d,"%seed)+','.join("%g"%v for v in values))64 109 65 def main(): 66 try: 67 model = sys.argv[1] 68 assert (model in MODELS) or (model == "all") 69 count = int(sys.argv[2]) 70 is2D = sys.argv[3].startswith('2d') 71 assert sys.argv[3][1] == 'd' 72 Nq = int(sys.argv[3][2:]) 73 mono = sys.argv[4] == 'mono' 74 cutoff = float(sys.argv[4]) if not mono else 0 75 except: 76 import traceback; traceback.print_exc() 77 models = "\n ".join("%-7s: %s"%(k,v.__name__.replace('_',' ')) 78 for k,v in sorted(MODELS.items())) 79 print("""\ 80 usage: compare_many.py MODEL COUNT (1dNQ|2dNQ) (CUTOFF|mono) 110 def print_usage(): 111 print "usage: compare_many.py MODEL COUNT (1dNQ|2dNQ) (CUTOFF|mono)" 81 112 82 MODEL is the model name of the model, which is one of: 83 %s 84 or "all" for all the models in alphabetical order. 113 114 def print_models(): 115 print(columnize(MODELS, indent=" ")) 116 117 118 def print_help(): 119 print_usage() 120 print("""\ 121 122 MODEL is the model name of the model or "all" for all the models 123 in alphabetical order. 85 124 86 125 COUNT is the number of randomly generated parameter sets to try. A value … … 98 137 choice of polydisperse parameters, and the number of points in the distribution 99 138 is set in compare.py defaults for each model. 100 """%(models,)) 139 140 Available models: 141 """) 142 print_models() 143 144 def main(): 145 if len(sys.argv) == 1: 146 print_help() 147 sys.exit(1) 148 149 model = sys.argv[1] 150 if not (model in MODELS) and (model != "all"): 151 print 'Bad model %s. Use "all" or one of:' 152 print_models() 153 sys.exit(1) 154 try: 155 count = int(sys.argv[2]) 156 is2D = sys.argv[3].startswith('2d') 157 assert sys.argv[3][1] == 'd' 158 Nq = int(sys.argv[3][2:]) 159 mono = sys.argv[4] == 'mono' 160 cutoff = float(sys.argv[4]) if not mono else 0 161 except: 162 print_usage() 101 163 sys.exit(1) 102 164 -
example/fit.py
r346bc88 r7cf2cfd 5 5 from bumps.names import * 6 6 from sasmodels.core import load_model 7 from sasmodels import bumps_model as sas 7 from sasmodels.bumps_model import Model, Experiment 8 from sasmodels.data import load_data, set_beam_stop, set_top 8 9 9 10 """ IMPORT THE DATA USED """ 10 radial_data = sas.load_data('DEC07267.DAT')11 s as.set_beam_stop(radial_data, 0.00669, outer=0.025)12 s as.set_top(radial_data, -.0185)11 radial_data = load_data('DEC07267.DAT') 12 set_beam_stop(radial_data, 0.00669, outer=0.025) 13 set_top(radial_data, -.0185) 13 14 14 tan_data = sas.load_data('DEC07266.DAT')15 s as.set_beam_stop(tan_data, 0.00669, outer=0.025)16 s as.set_top(tan_data, -.0185)15 tan_data = load_data('DEC07266.DAT') 16 set_beam_stop(tan_data, 0.00669, outer=0.025) 17 set_top(tan_data, -.0185) 17 18 #sas.set_half(tan_data, 'right') 18 19 … … 28 29 29 30 if name == "ellipsoid": 30 model = sas.Model(kernel,31 model = Model(kernel, 31 32 scale=0.08, 32 33 rpolar=15, requatorial=800, … … 51 52 52 53 elif name == "lamellar": 53 model = sas.Model(kernel,54 model = Model(kernel, 54 55 scale=0.08, 55 56 thickness=19.2946, … … 87 88 theta_pd=10, theta_pd_n=50, theta_pd_nsigma=3, 88 89 phi_pd=0, phi_pd_n=10, phi_pd_nsigma=3) 89 model = sas.Model(kernel, **pars)90 model = Model(kernel, **pars) 90 91 91 92 # SET THE FITTING PARAMETERS … … 102 103 103 104 elif name == "core_shell_cylinder": 104 model = sas.Model(kernel,105 model = Model(kernel, 105 106 scale= .031, radius=19.5, thickness=30, length=22, 106 107 core_sld=7.105, shell_sld=.291, solvent_sld=7.105, … … 129 130 130 131 elif name == "capped_cylinder": 131 model = sas.Model(kernel,132 model = Model(kernel, 132 133 scale=.08, radius=20, cap_radius=40, length=400, 133 134 sld_capcyl=1, sld_solv=6.3, … … 144 145 145 146 elif name == "triaxial_ellipsoid": 146 model = sas.Model(kernel,147 model = Model(kernel, 147 148 scale=0.08, req_minor=15, req_major=20, rpolar=500, 148 149 sldEll=7.105, solvent_sld=.291, … … 170 171 171 172 model.cutoff = cutoff 172 M = sas.Experiment(data=data, model=model)173 M = Experiment(data=data, model=model) 173 174 if section == "both": 174 tan_model = sas.Model(model.kernel, **model.parameters())175 tan_model = Model(model.kernel, **model.parameters()) 175 176 tan_model.phi = model.phi - 90 176 177 tan_model.cutoff = cutoff 177 tan_M = sas.Experiment(data=tan_data, model=tan_model)178 tan_M = Experiment(data=tan_data, model=tan_model) 178 179 problem = FitProblem([M, tan_M]) 179 180 else: -
sasmodels/bumps_model.py
r5d80bbf r7cf2cfd 10 10 how far the polydispersity integral extends. 11 11 12 A 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 plotting17 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 can24 be useful for shear measurements which have not been properly corrected25 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 33 12 """ 34 13 35 14 import datetime 36 15 import warnings 37 import traceback38 16 39 17 import numpy as np 40 18 19 from bumps.names import Parameter 20 41 21 from . import sesans 42 from .resolution import Perfect1D, Pinhole1D, Slit1D 43 from .resolution2d import Pinhole2D 44 45 # CRUFT python 2.6 46 if not hasattr(datetime.timedelta, 'total_seconds'): 47 def delay(dt): 48 """Return number date-time delta as number seconds""" 49 return dt.days * 86400 + dt.seconds + 1e-6 * dt.microseconds 50 else: 51 def delay(dt): 52 """Return number date-time delta as number seconds""" 53 return dt.total_seconds() 54 22 from . import weights 23 from .data import plot_theory 24 from .direct_model import DataMixin 55 25 56 26 # CRUFT: old style bumps wrapper which doesn't separate data and model … … 64 34 65 35 66 67 def tic():68 """69 Timer function.70 71 Use "toc=tic()" to start the clock and "toc()" to measure72 a time interval.73 """74 then = datetime.datetime.now()75 return lambda: delay(datetime.datetime.now() - then)76 77 78 def load_data(filename):79 """80 Load data using a sasview loader.81 """82 from sas.dataloader.loader import Loader83 loader = Loader()84 data = loader.load(filename)85 if data is None:86 raise IOError("Data %r could not be loaded" % filename)87 return data88 89 def plot_data(data, view='log'):90 """91 Plot data loaded by the sasview loader.92 """93 if hasattr(data, 'qx_data'):94 _plot_2d_signal(data, data.data, view=view)95 else:96 # Note: kind of weird using the _plot_result1D to plot just the97 # data, but it handles the masking and graph markup already, so98 # do not repeat.99 _plot_result1D(data, None, None, view)100 101 def plot_theory(data, theory, view='log'):102 if hasattr(data, 'qx_data'):103 _plot_2d_signal(data, theory, view=view)104 else:105 _plot_result1D(data, theory, None, view, include_data=False)106 107 108 def empty_data1D(q, resolution=0.05):109 """110 Create empty 1D data using the given *q* as the x value.111 112 *resolution* dq/q defaults to 5%.113 """114 115 from sas.dataloader.data_info import Data1D116 117 Iq = 100 * np.ones_like(q)118 dIq = np.sqrt(Iq)119 data = Data1D(q, Iq, dx=resolution * q, dy=dIq)120 data.filename = "fake data"121 data.qmin, data.qmax = q.min(), q.max()122 data.mask = np.zeros(len(Iq), dtype='bool')123 return data124 125 126 def empty_data2D(qx, qy=None, resolution=0.05):127 """128 Create empty 2D data using the given mesh.129 130 If *qy* is missing, create a square mesh with *qy=qx*.131 132 *resolution* dq/q defaults to 5%.133 """134 from sas.dataloader.data_info import Data2D, Detector135 136 if qy is None:137 qy = qx138 Qx, Qy = np.meshgrid(qx, qy)139 Qx, Qy = Qx.flatten(), Qy.flatten()140 Iq = 100 * np.ones_like(Qx)141 dIq = np.sqrt(Iq)142 mask = np.ones(len(Iq), dtype='bool')143 144 data = Data2D()145 data.filename = "fake data"146 data.qx_data = Qx147 data.qy_data = Qy148 data.data = Iq149 data.err_data = dIq150 data.mask = mask151 data.qmin = 1e-16152 data.qmax = np.inf153 154 # 5% dQ/Q resolution155 if resolution != 0:156 # https://www.ncnr.nist.gov/staff/hammouda/distance_learning/chapter_15.pdf157 # Should have an additional constant which depends on distances and158 # radii of the aperture, pixel dimensions and wavelength spread159 # Instead, assume radial dQ/Q is constant, and perpendicular matches160 # radial (which instead it should be inverse).161 Q = np.sqrt(Qx**2 + Qy**2)162 data.dqx_data = resolution * Q163 data.dqy_data = resolution * Q164 165 detector = Detector()166 detector.pixel_size.x = 5 # mm167 detector.pixel_size.y = 5 # mm168 detector.distance = 4 # m169 data.detector.append(detector)170 data.xbins = qx171 data.ybins = qy172 data.source.wavelength = 5 # angstroms173 data.source.wavelength_unit = "A"174 data.Q_unit = "1/A"175 data.I_unit = "1/cm"176 data.q_data = np.sqrt(Qx ** 2 + Qy ** 2)177 data.xaxis("Q_x", "A^{-1}")178 data.yaxis("Q_y", "A^{-1}")179 data.zaxis("Intensity", r"\text{cm}^{-1}")180 return data181 182 183 def set_beam_stop(data, radius, outer=None):184 """185 Add a beam stop of the given *radius*. If *outer*, make an annulus.186 """187 from sas.dataloader.manipulations import Ringcut188 if hasattr(data, 'qx_data'):189 data.mask = Ringcut(0, radius)(data)190 if outer is not None:191 data.mask += Ringcut(outer, np.inf)(data)192 else:193 data.mask = (data.x >= radius)194 if outer is not None:195 data.mask &= (data.x < outer)196 197 198 def set_half(data, half):199 """200 Select half of the data, either "right" or "left".201 """202 from sas.dataloader.manipulations import Boxcut203 if half == 'right':204 data.mask += \205 Boxcut(x_min=-np.inf, x_max=0.0, y_min=-np.inf, y_max=np.inf)(data)206 if half == 'left':207 data.mask += \208 Boxcut(x_min=0.0, x_max=np.inf, y_min=-np.inf, y_max=np.inf)(data)209 210 211 def set_top(data, cutoff):212 """213 Chop the top off the data, above *cutoff*.214 """215 from sas.dataloader.manipulations import Boxcut216 data.mask += \217 Boxcut(x_min=-np.inf, x_max=np.inf, y_min=-np.inf, y_max=cutoff)(data)218 219 def protect(fn):220 def wrapper(*args, **kw):221 try:222 return fn(*args, **kw)223 except:224 traceback.print_exc()225 return wrapper226 227 @protect228 def _plot_result1D(data, theory, resid, view, include_data=True):229 """230 Plot the data and residuals for 1D data.231 """232 import matplotlib.pyplot as plt233 from numpy.ma import masked_array, masked234 #print "not a number",sum(np.isnan(data.y))235 #data.y[data.y<0.05] = 0.5236 mdata = masked_array(data.y, data.mask)237 mdata[~np.isfinite(mdata)] = masked238 if view is 'log':239 mdata[mdata <= 0] = masked240 241 scale = data.x**4 if view == 'q4' else 1.0242 if resid is not None:243 plt.subplot(121)244 245 positive = False246 if include_data:247 plt.errorbar(data.x, scale*mdata, yerr=data.dy, fmt='.')248 positive = positive or (mdata>0).any()249 if theory is not None:250 mtheory = masked_array(theory, mdata.mask)251 plt.plot(data.x, scale*mtheory, '-', hold=True)252 positive = positive or (mtheory>0).any()253 plt.xscale(view)254 plt.yscale('linear' if view == 'q4' or not positive else view)255 plt.xlabel('Q')256 plt.ylabel('I(Q)')257 if resid is not None:258 mresid = masked_array(resid, mdata.mask)259 plt.subplot(122)260 plt.plot(data.x, mresid, 'x')261 plt.ylabel('residuals')262 plt.xlabel('Q')263 plt.xscale(view)264 265 # pylint: disable=unused-argument266 @protect267 def _plot_sesans(data, theory, resid, view):268 import matplotlib.pyplot as plt269 plt.subplot(121)270 plt.errorbar(data.x, data.y, yerr=data.dy)271 plt.plot(data.x, theory, '-', hold=True)272 plt.xlabel('spin echo length (nm)')273 plt.ylabel('polarization (P/P0)')274 plt.subplot(122)275 plt.plot(data.x, resid, 'x')276 plt.xlabel('spin echo length (nm)')277 plt.ylabel('residuals (P/P0)')278 279 @protect280 def _plot_result2D(data, theory, resid, view):281 """282 Plot the data and residuals for 2D data.283 """284 import matplotlib.pyplot as plt285 target = data.data[~data.mask]286 if view == 'log':287 vmin = min(target[target>0].min(), theory[theory>0].min())288 vmax = max(target.max(), theory.max())289 else:290 vmin = min(target.min(), theory.min())291 vmax = max(target.max(), theory.max())292 #print vmin, vmax293 plt.subplot(131)294 _plot_2d_signal(data, target, view=view, vmin=vmin, vmax=vmax)295 plt.title('data')296 plt.colorbar()297 plt.subplot(132)298 _plot_2d_signal(data, theory, view=view, vmin=vmin, vmax=vmax)299 plt.title('theory')300 plt.colorbar()301 plt.subplot(133)302 _plot_2d_signal(data, resid, view='linear')303 plt.title('residuals')304 plt.colorbar()305 306 @protect307 def _plot_2d_signal(data, signal, vmin=None, vmax=None, view='log'):308 """309 Plot the target value for the data. This could be the data itself,310 the theory calculation, or the residuals.311 312 *scale* can be 'log' for log scale data, or 'linear'.313 """314 import matplotlib.pyplot as plt315 from numpy.ma import masked_array316 317 image = np.zeros_like(data.qx_data)318 image[~data.mask] = signal319 valid = np.isfinite(image)320 if view == 'log':321 valid[valid] = (image[valid] > 0)322 image[valid] = np.log10(image[valid])323 elif view == 'q4':324 image[valid] *= (data.qx_data[valid]**2+data.qy_data[valid]**2)**2325 image[~valid | data.mask] = 0326 #plottable = Iq327 plottable = masked_array(image, ~valid | data.mask)328 xmin, xmax = min(data.qx_data), max(data.qx_data)329 ymin, ymax = min(data.qy_data), max(data.qy_data)330 # TODO: fix vmin, vmax so it is shared for theory/resid331 vmin = vmax = None332 try:333 if vmin is None: vmin = image[valid & ~data.mask].min()334 if vmax is None: vmax = image[valid & ~data.mask].max()335 except:336 vmin, vmax = 0, 1337 #print vmin,vmax338 plt.imshow(plottable.reshape(128, 128),339 interpolation='nearest', aspect=1, origin='upper',340 extent=[xmin, xmax, ymin, ymax], vmin=vmin, vmax=vmax)341 342 343 36 class Model(object): 344 def __init__(self, kernel, **kw): 345 from bumps.names import Parameter 346 347 self.kernel = kernel 348 partype = kernel.info['partype'] 37 def __init__(self, model, **kw): 38 self._sasmodel = model 39 partype = model.info['partype'] 349 40 350 41 pars = [] 351 for p in kernel.info['parameters']:42 for p in model.info['parameters']: 352 43 name, default, limits = p[0], p[2], p[3] 353 44 value = kw.pop(name, default) … … 378 69 return dict((k, getattr(self, k)) for k in self._parameter_names) 379 70 380 class Experiment(object): 71 72 class Experiment(DataMixin): 381 73 """ 382 74 Return a bumps wrapper for a SAS model. … … 397 89 398 90 # remember inputs so we can inspect from outside 399 self.data = data400 91 self.model = model 401 92 self.cutoff = cutoff 402 if hasattr(data, 'lam'): 403 self.data_type = 'sesans' 404 elif hasattr(data, 'qx_data'): 405 self.data_type = 'Iqxy' 406 else: 407 self.data_type = 'Iq' 408 409 # interpret data 410 partype = model.kernel.info['partype'] 411 if self.data_type == 'sesans': 412 q = sesans.make_q(data.sample.zacceptance, data.Rmax) 413 self.index = slice(None, None) 414 self.Iq = data.y 415 self.dIq = data.dy 416 #self._theory = np.zeros_like(q) 417 q_vectors = [q] 418 elif self.data_type == 'Iqxy': 419 q = np.sqrt(data.qx_data**2 + data.qy_data**2) 420 qmin = getattr(data, 'qmin', 1e-16) 421 qmax = getattr(data, 'qmax', np.inf) 422 accuracy = getattr(data, 'accuracy', 'Low') 423 self.index = (~data.mask) & (~np.isnan(data.data)) \ 424 & (q >= qmin) & (q <= qmax) 425 self.Iq = data.data[self.index] 426 self.dIq = data.err_data[self.index] 427 self.resolution = Pinhole2D(data=data, index=self.index, 428 nsigma=3.0, accuracy=accuracy) 429 #self._theory = np.zeros_like(self.Iq) 430 if not partype['orientation'] and not partype['magnetic']: 431 raise ValueError("not 2D without orientation or magnetic parameters") 432 #qx,qy = self.resolution.q_calc 433 #q_vectors = [np.sqrt(qx**2 + qy**2)] 434 else: 435 q_vectors = self.resolution.q_calc 436 elif self.data_type == 'Iq': 437 self.index = (data.x >= data.qmin) & (data.x <= data.qmax) & ~np.isnan(data.y) 438 self.Iq = data.y[self.index] 439 self.dIq = data.dy[self.index] 440 if getattr(data, 'dx', None) is not None: 441 q, dq = data.x[self.index], data.dx[self.index] 442 if (dq>0).any(): 443 self.resolution = Pinhole1D(q, dq) 444 else: 445 self.resolution = Perfect1D(q) 446 elif (getattr(data, 'dxl', None) is not None and 447 getattr(data, 'dxw', None) is not None): 448 q = data.x[self.index] 449 width = data.dxh[self.index] # Note: dx 450 self.resolution = Slit1D(data.x[self.index], 451 width=data.dxh[self.index], 452 height=data.dxw[self.index]) 453 else: 454 self.resolution = Perfect1D(data.x[self.index]) 455 456 #self._theory = np.zeros_like(self.Iq) 457 q_vectors = [self.resolution.q_calc] 458 else: 459 raise ValueError("Unknown data type") # never gets here 460 461 # Remember function inputs so we can delay loading the function and 462 # so we can save/restore state 463 self._fn_inputs = [v for v in q_vectors] 464 self._fn = None 465 93 self._interpret_data(data, model._sasmodel) 466 94 self.update() 467 95 … … 483 111 def theory(self): 484 112 if 'theory' not in self._cache: 113 pars = dict((k, v.value) for k,v in self.model.parameters().items()) 114 self._cache['theory'] = self._calc_theory(pars, cutoff=self.cutoff) 115 """ 485 116 if self._fn is None: 486 q_input = self.model.kernel.make_input(self._ fn_inputs)117 q_input = self.model.kernel.make_input(self._kernel_inputs) 487 118 self._fn = self.model.kernel(q_input) 488 119 … … 495 126 result = sesans.hankel(self.data.x, self.data.lam * 1e-9, 496 127 self.data.sample.thickness / 10, 497 self._ fn_inputs[0], Iq_calc)128 self._kernel_inputs[0], Iq_calc) 498 129 self._cache['theory'] = result 499 130 else: 500 131 Iq = self.resolution.apply(Iq_calc) 501 132 self._cache['theory'] = Iq 133 """ 502 134 return self._cache['theory'] 503 135 … … 518 150 Plot the data and residuals. 519 151 """ 520 data, theory, resid = self.data, self.theory(), self.residuals() 521 if self.data_type == 'Iq': 522 _plot_result1D(data, theory, resid, view) 523 elif self.data_type == 'Iqxy': 524 _plot_result2D(data, theory, resid, view) 525 elif self.data_type == 'sesans': 526 _plot_sesans(data, theory, resid, view) 527 else: 528 raise ValueError("Unknown data type") 152 data, theory, resid = self._data, self.theory(), self.residuals() 153 plot_theory(data, theory, resid, view) 529 154 530 155 def simulate_data(self, noise=None): 531 theory = self.theory() 532 if noise is not None: 533 self.dIq = theory*noise*0.01 534 dy = self.dIq 535 y = theory + np.random.randn(*dy.shape) * dy 536 self.Iq = y 537 if self.data_type == 'Iq': 538 self.data.dy[self.index] = dy 539 self.data.y[self.index] = y 540 elif self.data_type == 'Iqxy': 541 self.data.data[self.index] = y 542 elif self.data_type == 'sesans': 543 self.data.y[self.index] = y 544 else: 545 raise ValueError("Unknown model") 156 Iq = self.theory() 157 self._set_data(Iq, noise) 546 158 547 159 def save(self, basename): 548 160 pass 549 161 550 def _get_weights(self, par):162 def remove_get_weights(self, name): 551 163 """ 552 164 Get parameter dispersion weights 553 165 """ 554 from . import weights 555 556 relative = self.model.kernel.info['partype']['pd-rel'] 557 limits = self.model.kernel.info['limits'] 166 info = self.model.kernel.info 167 relative = name in info['partype']['pd-rel'] 168 limits = info['limits'][name] 558 169 disperser, value, npts, width, nsigma = [ 559 getattr(self.model, par+ ext)170 getattr(self.model, name + ext) 560 171 for ext in ('_pd_type', '', '_pd_n', '_pd', '_pd_nsigma')] 561 172 value, weight = weights.get_weights( 562 173 disperser, int(npts.value), width.value, nsigma.value, 563 value.value, limits [par], par inrelative)174 value.value, limits, relative) 564 175 return value, weight / np.sum(weight) 565 176 … … 567 178 # Can't pickle gpu functions, so instead make them lazy 568 179 state = self.__dict__.copy() 569 state['_ fn'] = None180 state['_kernel'] = None 570 181 return state 571 182 … … 573 184 # pylint: disable=attribute-defined-outside-init 574 185 self.__dict__ = state 575 576 577 def demo():578 data = load_data('DEC07086.DAT')579 set_beam_stop(data, 0.004)580 plot_data(data)581 import matplotlib.pyplot as plt; plt.show()582 583 584 if __name__ == "__main__":585 demo() -
sasmodels/core.py
rbcd3aa3 r7cf2cfd 123 123 """ 124 124 relative = name in info['partype']['pd-rel'] 125 limits = info['limits'] 125 limits = info['limits'][name] 126 126 disperser = pars.get(name+'_pd_type', 'gaussian') 127 127 value = pars.get(name, info['defaults'][name]) … … 130 130 nsigma = pars.get(name+'_pd_nsigma', 3.0) 131 131 value,weight = weights.get_weights( 132 disperser, npts, width, nsigma, 133 value, limits[name], relative) 134 return value,weight/np.sum(weight) 132 disperser, npts, width, nsigma, value, limits, relative) 133 return value, weight / np.sum(weight) 135 134 136 135 def dispersion_mesh(pars): -
sasmodels/direct_model.py
raa4946b r7cf2cfd 5 5 from .core import load_model_definition, load_model, make_kernel 6 6 from .core import call_kernel, call_ER, call_VR 7 from . import sesans 8 from . import resolution 9 from . import resolution2d 7 10 8 class DirectModel: 9 def __init__(self, name, q_vectors=None, dtype='single'): 10 self.model_definition = load_model_definition(name) 11 self.model = load_model(self.model_definition, dtype=dtype) 12 if q_vectors is not None: 13 q_vectors = [np.ascontiguousarray(q,dtype=dtype) for q in q_vectors] 14 self.kernel = make_kernel(self.model, q_vectors) 11 class DataMixin(object): 12 """ 13 DataMixin captures the common aspects of evaluating a SAS model for a 14 particular data set, including calculating Iq and evaluating the 15 resolution function. It is used in particular by :class:`DirectModel`, 16 which evaluates a SAS model parameters as key word arguments to the 17 calculator method, and by :class:`bumps_model.Experiment`, which wraps the 18 model and data for use with the Bumps fitting engine. It is not 19 currently used by :class:`sasview_model.SasviewModel` since this will 20 require a number of changes to SasView before we can do it. 21 """ 22 def _interpret_data(self, data, model): 23 self._data = data 24 self._model = model 25 26 # interpret data 27 if hasattr(data, 'lam'): 28 self.data_type = 'sesans' 29 elif hasattr(data, 'qx_data'): 30 self.data_type = 'Iqxy' 31 else: 32 self.data_type = 'Iq' 33 34 partype = model.info['partype'] 35 36 if self.data_type == 'sesans': 37 q = sesans.make_q(data.sample.zacceptance, data.Rmax) 38 self.index = slice(None, None) 39 if data.y is not None: 40 self.Iq = data.y 41 self.dIq = data.dy 42 #self._theory = np.zeros_like(q) 43 q_vectors = [q] 44 elif self.data_type == 'Iqxy': 45 if not partype['orientation'] and not partype['magnetic']: 46 raise ValueError("not 2D without orientation or magnetic parameters") 47 q = np.sqrt(data.qx_data**2 + data.qy_data**2) 48 qmin = getattr(data, 'qmin', 1e-16) 49 qmax = getattr(data, 'qmax', np.inf) 50 accuracy = getattr(data, 'accuracy', 'Low') 51 self.index = ~data.mask & (q >= qmin) & (q <= qmax) 52 if data.data is not None: 53 self.index &= ~np.isnan(data.data) 54 self.Iq = data.data[self.index] 55 self.dIq = data.err_data[self.index] 56 self.resolution = resolution2d.Pinhole2D(data=data, index=self.index, 57 nsigma=3.0, accuracy=accuracy) 58 #self._theory = np.zeros_like(self.Iq) 59 q_vectors = self.resolution.q_calc 60 elif self.data_type == 'Iq': 61 self.index = (data.x >= data.qmin) & (data.x <= data.qmax) 62 if data.y is not None: 63 self.index &= ~np.isnan(data.y) 64 self.Iq = data.y[self.index] 65 self.dIq = data.dy[self.index] 66 if getattr(data, 'dx', None) is not None: 67 q, dq = data.x[self.index], data.dx[self.index] 68 if (dq>0).any(): 69 self.resolution = resolution.Pinhole1D(q, dq) 70 else: 71 self.resolution = resolution.Perfect1D(q) 72 elif (getattr(data, 'dxl', None) is not None and 73 getattr(data, 'dxw', None) is not None): 74 self.resolution = resolution.Slit1D(data.x[self.index], 75 width=data.dxh[self.index], 76 height=data.dxw[self.index]) 77 else: 78 self.resolution = resolution.Perfect1D(data.x[self.index]) 79 80 #self._theory = np.zeros_like(self.Iq) 81 q_vectors = [self.resolution.q_calc] 82 else: 83 raise ValueError("Unknown data type") # never gets here 84 85 # Remember function inputs so we can delay loading the function and 86 # so we can save/restore state 87 self._kernel_inputs = [v for v in q_vectors] 88 self._kernel = None 89 90 def _set_data(self, Iq, noise=None): 91 if noise is not None: 92 self.dIq = Iq*noise*0.01 93 dy = self.dIq 94 y = Iq + np.random.randn(*dy.shape) * dy 95 self.Iq = y 96 if self.data_type == 'Iq': 97 self._data.dy[self.index] = dy 98 self._data.y[self.index] = y 99 elif self.data_type == 'Iqxy': 100 self._data.data[self.index] = y 101 elif self.data_type == 'sesans': 102 self._data.y[self.index] = y 103 else: 104 raise ValueError("Unknown model") 105 106 def _calc_theory(self, pars, cutoff=0.0): 107 if self._kernel is None: 108 q_input = self._model.make_input(self._kernel_inputs) 109 self._kernel = self._model(q_input) 110 111 Iq_calc = call_kernel(self._kernel, pars, cutoff=cutoff) 112 if self.data_type == 'sesans': 113 result = sesans.hankel(self._data.x, self._data.lam * 1e-9, 114 self._data.sample.thickness / 10, 115 self._kernel_inputs[0], Iq_calc) 116 else: 117 result = self.resolution.apply(Iq_calc) 118 return result 119 120 121 class DirectModel(DataMixin): 122 def __init__(self, data, model, cutoff=1e-5): 123 self.model = model 124 self.cutoff = cutoff 125 self._interpret_data(data, model) 126 self.kernel = make_kernel(self.model, self._kernel_inputs) 15 127 def __call__(self, **pars): 16 return call_kernel(self.kernel, pars)128 return self._calc_theory(pars, cutoff=self.cutoff) 17 129 def ER(self, **pars): 18 130 return call_ER(self.model.info, pars) 19 131 def VR(self, **pars): 20 132 return call_VR(self.model.info, pars) 133 def simulate_data(self, noise=None, **pars): 134 Iq = self.__call__(**pars) 135 self._set_data(Iq, noise=noise) 21 136 22 137 def demo(): 23 138 import sys 139 from .data import empty_data1D, empty_data2D 140 24 141 if len(sys.argv) < 3: 25 142 print "usage: python -m sasmodels.direct_model modelname (q|qx,qy) par=val ..." … … 27 144 model_name = sys.argv[1] 28 145 call = sys.argv[2].upper() 29 if call in ("ER","VR"): 30 q_vectors = None 31 else: 32 values = [float(v) for v in sys.argv[2].split(',')] 146 if call not in ("ER","VR"): 147 try: 148 values = [float(v) for v in call.split(',')] 149 except: 150 values = [] 33 151 if len(values) == 1: 34 q = values[0]35 q_vectors = [[q]]152 q, = values 153 data = empty_data1D([q]) 36 154 elif len(values) == 2: 37 155 qx,qy = values 38 q_vectors = [[qx],[qy]]156 data = empty_data2D([qx],[qy]) 39 157 else: 40 158 print "use q or qx,qy or ER or VR" 41 159 sys.exit(1) 42 model = DirectModel(model_name, q_vectors) 160 else: 161 data = empty_data1D([0.001]) # Data not used in ER/VR 162 163 model_definition = load_model_definition(model_name) 164 model = load_model(model_definition, dtype='single') 165 calculator = DirectModel(data, model) 43 166 pars = dict((k,float(v)) 44 167 for pair in sys.argv[3:] 45 168 for k,v in [pair.split('=')]) 46 169 if call == "ER": 47 print model.ER(**pars)170 print calculator.ER(**pars) 48 171 elif call == "VR": 49 print model.VR(**pars)172 print calculator.VR(**pars) 50 173 else: 51 Iq = model(**pars)174 Iq = calculator(**pars) 52 175 print Iq[0] 53 176
Note: See TracChangeset
for help on using the changeset viewer.