Changes in / [8696a87:504abee] in sasmodels
- Files:
-
- 1 deleted
- 18 edited
Legend:
- Unmodified
- Added
- Removed
-
extra/pylint.rc
r823e620 rd4666ca 10 10 11 11 # Profiled execution. 12 #profile=no12 profile=no 13 13 14 14 # Add files or directories to the blacklist. They should be base names, not … … 92 92 # Add a comment according to your evaluation note. This is used by the global 93 93 # evaluation report (RP0004). 94 #comment=no94 comment=no 95 95 96 96 # Template used to display messages. This is a python new-style format string … … 101 101 102 102 # Required attributes for module, separated by a comma 103 #required-attributes=103 required-attributes= 104 104 105 105 # List of builtins function names that should not be used, separated by a comma … … 108 108 # Good variable names which should always be accepted, separated by a comma 109 109 good-names=_, 110 input, id, 111 h, i, j, k, n, p, v, w, x, y, z, 112 q, qx, qy, qz, Q, Qx, Qy, Qz, 113 dt, dx, dy, dz, dq, 114 Iq, dIq, Iqxy, Iq_calc, 110 input, 111 h,i,j,k,n,w,x,y,z, 112 q,qx,qy,qz, 113 dt,dx,dy,dz,id, 114 Iq,dIq,Qx,Qy,Qz,Iqxy, 115 p, 115 116 ER, call_ER, VR, call_VR, 116 117 Rmax, SElength, … … 280 281 # (useful for modules/projects where namespaces are manipulated during runtime 281 282 # and thus existing member attributes cannot be deduced by static analysis 282 ignored-modules=numpy,np,numpy.random, 283 bumps,sas, 283 ignored-modules=numpy,np 284 284 285 285 # List of classes names for which member attributes should not be checked … … 289 289 # When zope mode is activated, add a predefined set of Zope acquired attributes 290 290 # to generated-members. 291 #zope=no291 zope=no 292 292 293 293 # List of members which are set dynamically and missed by pylint inference … … 319 319 # List of interface methods to ignore, separated by a comma. This is used for 320 320 # instance to not check methods defines in Zope's Interface base class. 321 #ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by321 ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by 322 322 323 323 # List of method names used to declare (i.e. assign) instance attributes. -
extra/pylint_numpy.py
r823e620 r63b32bb 8 8 #print("processing",module.name) 9 9 if module.name.startswith('numpy'): 10 if module.name == 'numpy': 11 import numpy 12 elif module.name == 'numpy.random': 13 import numpy.random 14 from numpy.random import seed, get_state, set_state 10 if module.name == 'numpy': import numpy 11 elif module.name == 'numpy.random': import numpy.random 15 12 -
extra/pylint_pyopencl.py
r823e620 r3c56da87 9 9 if module.name == 'pyopencl': 10 10 import pyopencl 11 import pyopencl as cl -
extra/run-pylint.py
r823e620 rf01e53d 6 6 7 7 def main(): 8 extra = abspath(dirname(__file__))9 root = abspath(joinpath(extra, '..'))10 11 8 envpath = os.environ.get('PYTHONPATH',None) 12 9 path = [envpath] if envpath else [] 13 path.append(extra) 14 15 #bumps = abspath(joinpath(root, "..", "bumps")) 16 #periodictable = abspath(joinpath(root, "..", "periodictable")) 17 #sasview = abspath(joinpath(root, "..", "sasview", "src")) 18 #path.extend((bumps, periodictable, sasview)) 19 10 path.append(abspath(dirname(__file__))) # so we can find the plugins 20 11 os.environ['PYTHONPATH'] = ':'.join(path) 21 22 # Run the lint command12 root = abspath(joinpath(dirname(__file__), '..')) 13 os.chdir(root) 23 14 cmd = "pylint --rcfile extra/pylint.rc -f parseable sasmodels" 24 os.chdir(root)25 15 status = os.system(cmd) 26 16 sys.exit(status) -
sasmodels/compare.py
r190fc2b r190fc2b 604 604 def columnize(L, indent="", width=79): 605 605 """ 606 Format a list of strings into columns. 607 608 Returns a string with carriage returns ready for printing. 606 Format a list of strings into columns for printing. 609 607 """ 610 608 column_width = max(len(w) for w in L) + 1 -
sasmodels/core.py
reafc9fa r190fc2b 38 38 """ 39 39 Load a model definition given the model name. 40 41 This returns a handle to the module defining the model. This can be42 used with functions in generate to build the docs or extract model info.43 40 """ 44 41 __import__('sasmodels.models.'+model_name) … … 118 115 Return a computation kernel from the model definition and the q input. 119 116 """ 120 return model(q_vectors) 117 model_input = model.make_input(q_vectors) 118 return model(model_input) 121 119 122 120 def get_weights(info, pars, name): -
sasmodels/data.py
r5c962df r69ec80f 87 87 88 88 class Data1D(object): 89 """90 1D data object.91 92 Note that this definition matches the attributes from sasview, with93 some generic 1D data vectors and some SAS specific definitions. Some94 refactoring to allow consistent naming conventions between 1D, 2D and95 SESANS data would be helpful.96 97 **Attributes**98 99 *x*, *dx*: $q$ vector and gaussian resolution100 101 *y*, *dy*: $I(q)$ vector and measurement uncertainty102 103 *mask*: values to include in plotting/analysis104 105 *dxl*: slit widths for slit smeared data, with *dx* ignored106 107 *qmin*, *qmax*: range of $q$ values in *x*108 109 *filename*: label for the data line110 111 *_xaxis*, *_xunit*: label and units for the *x* axis112 113 *_yaxis*, *_yunit*: label and units for the *y* axis114 """115 89 def __init__(self, x=None, y=None, dx=None, dy=None): 116 90 self.x, self.y, self.dx, self.dy = x, y, dx, dy … … 119 93 self.qmin = x.min() if x is not None else np.NaN 120 94 self.qmax = x.max() if x is not None else np.NaN 121 # TODO: why is 1D mask False and 2D mask True? 122 self.mask = (np.isnan(y) if y is not None 123 else np.zeros_like(x, 'b') if x is not None 124 else None) 95 self.mask = np.isnan(y) if y is not None else None 125 96 self._xaxis, self._xunit = "x", "" 126 97 self._yaxis, self._yunit = "y", "" … … 143 114 144 115 class Data2D(object): 145 """146 2D data object.147 148 Note that this definition matches the attributes from sasview. Some149 refactoring to allow consistent naming conventions between 1D, 2D and150 SESANS data would be helpful.151 152 **Attributes**153 154 *qx_data*, *dqx_data*: $q_x$ matrix and gaussian resolution155 156 *qy_data*, *dqy_data*: $q_y$ matrix and gaussian resolution157 158 *data*, *err_data*: $I(q)$ matrix and measurement uncertainty159 160 *mask*: values to exclude from plotting/analysis161 162 *qmin*, *qmax*: range of $q$ values in *x*163 164 *filename*: label for the data line165 166 *_xaxis*, *_xunit*: label and units for the *x* axis167 168 *_yaxis*, *_yunit*: label and units for the *y* axis169 170 *_zaxis*, *_zunit*: label and units for the *y* axis171 172 *Q_unit*, *I_unit*: units for Q and intensity173 174 *x_bins*, *y_bins*: grid steps in *x* and *y* directions175 """176 116 def __init__(self, x=None, y=None, z=None, dx=None, dy=None, dz=None): 177 117 self.qx_data, self.dqx_data = x, dx 178 118 self.qy_data, self.dqy_data = y, dy 179 119 self.data, self.err_data = z, dz 180 self.mask = (~np.isnan(z) if z is not None 181 else np.ones_like(x) if x is not None 182 else None) 120 self.mask = ~np.isnan(z) if z is not None else None 183 121 self.q_data = np.sqrt(x**2 + y**2) 184 122 self.qmin = 1e-16 … … 188 126 self.Q_unit = "1/A" 189 127 self.I_unit = "1/cm" 190 self.xaxis("Q_x", " 1/A")191 self.yaxis("Q_y", " 1/A")192 self.zaxis("Intensity", "1/cm")128 self.xaxis("Q_x", "A^{-1}") 129 self.yaxis("Q_y", "A^{-1}") 130 self.zaxis("Intensity", r"\text{cm}^{-1}") 193 131 self._xaxis, self._xunit = "x", "" 194 132 self._yaxis, self._yunit = "y", "" … … 219 157 220 158 class Vector(object): 221 """222 3-space vector of *x*, *y*, *z*223 """224 159 def __init__(self, x=None, y=None, z=None): 225 160 self.x, self.y, self.z = x, y, z … … 300 235 """ 301 236 Plot data loaded by the sasview loader. 302 303 *data* is a sasview data object, either 1D, 2D or SESANS.304 305 *view* is log or linear.306 307 *limits* sets the intensity limits on the plot; if None then the limits308 are inferred from the data.309 237 """ 310 238 # Note: kind of weird using the plot result functions to plot just the … … 321 249 def plot_theory(data, theory, resid=None, view='log', 322 250 use_data=True, limits=None): 323 """324 Plot theory calculation.325 326 *data* is needed to define the graph properties such as labels and327 units, and to define the data mask.328 329 *theory* is a matrix of the same shape as the data.330 331 *view* is log or linear332 333 *use_data* is True if the data should be plotted as well as the theory.334 335 *limits* sets the intensity limits on the plot; if None then the limits336 are inferred from the data.337 """338 251 if hasattr(data, 'lam'): 339 252 _plot_result_sesans(data, theory, resid, use_data=True, limits=limits) … … 345 258 346 259 def protect(fn): 347 """348 Decorator to wrap calls in an exception trapper which prints the349 exception and continues. Keyboard interrupts are ignored.350 """351 260 def wrapper(*args, **kw): 352 """353 Trap and print errors from function.354 """355 261 try: 356 262 return fn(*args, **kw) 357 except KeyboardInterrupt:358 raise359 263 except: 360 264 traceback.print_exc() … … 428 332 @protect 429 333 def _plot_result_sesans(data, theory, resid, use_data, limits=None): 430 """431 Plot SESANS results.432 """433 334 import matplotlib.pyplot as plt 434 335 use_data = use_data and data.y is not None … … 558 459 559 460 def demo(): 560 """561 Load and plot a SAS dataset.562 """563 461 data = load_data('DEC07086.DAT') 564 462 set_beam_stop(data, 0.004) -
sasmodels/direct_model.py
reafc9fa r9404dd3 1 """ 2 Class interface to the model calculator. 3 4 Calling a model is somewhat non-trivial since the functions called depend 5 on the data type. For 1D data the *Iq* kernel needs to be called, for 6 2D data the *Iqxy* kernel needs to be called, and for SESANS data the 7 *Iq* kernel needs to be called followed by a Hankel transform. Before 8 the kernel is called an appropriate *q* calculation vector needs to be 9 constructed. This is not the simple *q* vector where you have measured 10 the data since the resolution calculation will require values beyond the 11 range of the measured data. After the calculation the resolution calculator 12 must be called to return the predicted value for each measured data point. 13 14 :class:`DirectModel` is a callable object that takes *parameter=value* 15 keyword arguments and returns the appropriate theory values for the data. 16 17 :class:`DataMixin` does the real work of interpreting the data and calling 18 the model calculator. This is used by :class:`DirectModel`, which uses 19 direct parameter values and by :class:`bumps_model.Experiment` which wraps 20 the parameter values in boxes so that the user can set fitting ranges, etc. 21 on the individual parameters and send the model to the Bumps optimizers. 22 """ 23 from __future__ import print_function 1 import warnings 24 2 25 3 import numpy as np … … 41 19 currently used by :class:`sasview_model.SasviewModel` since this will 42 20 require a number of changes to SasView before we can do it. 43 44 :meth:`_interpret_data` initializes the data structures necessary45 to manage the calculations. This sets attributes in the child class46 such as *data_type* and *resolution*.47 48 :meth:`_calc_theory` evaluates the model at the given control values.49 50 :meth:`_set_data` sets the intensity data in the data object,51 possibly with random noise added. This is useful for simulating a52 dataset with the results from :meth:`_calc_theory`.53 21 """ 54 22 def _interpret_data(self, data, model): 55 # pylint: disable=attribute-defined-outside-init56 57 23 self._data = data 58 24 self._model = model … … 70 36 if self.data_type == 'sesans': 71 37 q = sesans.make_q(data.sample.zacceptance, data.Rmax) 72 index = slice(None, None) 73 res = None 38 self.index = slice(None, None) 74 39 if data.y is not None: 75 Iq, dIq = data.y, data.dy 76 else: 77 Iq, dIq = None, None 40 self.Iq = data.y 41 self.dIq = data.dy 78 42 #self._theory = np.zeros_like(q) 79 43 q_vectors = [q] … … 85 49 qmax = getattr(data, 'qmax', np.inf) 86 50 accuracy = getattr(data, 'accuracy', 'Low') 87 index = ~data.mask & (q >= qmin) & (q <= qmax)51 self.index = ~data.mask & (q >= qmin) & (q <= qmax) 88 52 if data.data is not None: 89 index &= ~np.isnan(data.data) 90 Iq = data.data[index] 91 dIq = data.err_data[index] 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]) 92 77 else: 93 Iq, dIq = None, None 94 res = resolution2d.Pinhole2D(data=data, index=index, 95 nsigma=3.0, accuracy=accuracy) 96 #self._theory = np.zeros_like(self.Iq) 97 q_vectors = res.q_calc 98 elif self.data_type == 'Iq': 99 index = (data.x >= data.qmin) & (data.x <= data.qmax) 100 if data.y is not None: 101 index &= ~np.isnan(data.y) 102 Iq = data.y[index] 103 dIq = data.dy[index] 104 else: 105 Iq, dIq = None, None 106 if getattr(data, 'dx', None) is not None: 107 q, dq = data.x[index], data.dx[index] 108 if (dq > 0).any(): 109 res = resolution.Pinhole1D(q, dq) 110 else: 111 res = resolution.Perfect1D(q) 112 elif (getattr(data, 'dxl', None) is not None 113 and getattr(data, 'dxw', None) is not None): 114 res = resolution.Slit1D(data.x[index], 115 width=data.dxh[index], 116 height=data.dxw[index]) 117 else: 118 res = resolution.Perfect1D(data.x[index]) 78 self.resolution = resolution.Perfect1D(data.x[self.index]) 119 79 120 80 #self._theory = np.zeros_like(self.Iq) 121 q_vectors = [ res.q_calc]81 q_vectors = [self.resolution.q_calc] 122 82 else: 123 83 raise ValueError("Unknown data type") # never gets here … … 127 87 self._kernel_inputs = [v for v in q_vectors] 128 88 self._kernel = None 129 self.Iq, self.dIq, self.index = Iq, dIq, index130 self.resolution = res131 89 132 90 def _set_data(self, Iq, noise=None): 133 # pylint: disable=attribute-defined-outside-init134 91 if noise is not None: 135 92 self.dIq = Iq*noise*0.01 … … 149 106 def _calc_theory(self, pars, cutoff=0.0): 150 107 if self._kernel is None: 151 self._kernel = make_kernel(self._model, self._kernel_inputs) # pylint: disable=attribute-defined-outside-init 108 q_input = self._model.make_input(self._kernel_inputs) 109 self._kernel = self._model(q_input) 152 110 153 111 Iq_calc = call_kernel(self._kernel, pars, cutoff=cutoff) … … 162 120 163 121 class DirectModel(DataMixin): 164 """165 Create a calculator object for a model.166 167 *data* is 1D SAS, 2D SAS or SESANS data168 169 *model* is a model calculator return from :func:`generate.load_model`170 171 *cutoff* is the polydispersity weight cutoff.172 """173 122 def __init__(self, data, model, cutoff=1e-5): 174 123 self.model = model 175 124 self.cutoff = cutoff 176 # Note: _interpret_data defines the model attributes177 125 self._interpret_data(data, model) 178 126 self.kernel = make_kernel(self.model, self._kernel_inputs) 179 127 def __call__(self, **pars): 180 128 return self._calc_theory(pars, cutoff=self.cutoff) 181 182 129 def ER(self, **pars): 183 """184 Compute the equivalent radius for the model.185 186 Return 0. if not defined.187 """188 130 return call_ER(self.model.info, pars) 189 190 131 def VR(self, **pars): 191 """192 Compute the equivalent volume for the model, including polydispersity193 effects.194 195 Return 1. if not defined.196 """197 132 return call_VR(self.model.info, pars) 198 199 133 def simulate_data(self, noise=None, **pars): 200 """201 Generate simulated data for the model.202 """203 134 Iq = self.__call__(**pars) 204 135 self._set_data(Iq, noise=noise) 205 136 206 def main(): 207 """ 208 Program to evaluate a particular model at a set of q values. 209 """ 137 def demo(): 210 138 import sys 211 139 from .data import empty_data1D, empty_data2D … … 216 144 model_name = sys.argv[1] 217 145 call = sys.argv[2].upper() 218 if call not in ("ER", 146 if call not in ("ER","VR"): 219 147 try: 220 148 values = [float(v) for v in call.split(',')] … … 225 153 data = empty_data1D([q]) 226 154 elif len(values) == 2: 227 qx, 228 data = empty_data2D([qx], 155 qx,qy = values 156 data = empty_data2D([qx],[qy]) 229 157 else: 230 158 print("use q or qx,qy or ER or VR") … … 236 164 model = load_model(model_definition, dtype='single') 237 165 calculator = DirectModel(data, model) 238 pars = dict((k, 166 pars = dict((k,float(v)) 239 167 for pair in sys.argv[3:] 240 for k, 168 for k,v in [pair.split('=')]) 241 169 if call == "ER": 242 170 print(calculator.ER(**pars)) … … 248 176 249 177 if __name__ == "__main__": 250 main()178 demo() -
sasmodels/exception.py
r823e620 reaca9eb 8 8 except NameError: 9 9 class WindowsError(Exception): 10 """11 Fake WindowsException when not on Windows.12 """13 10 pass 14 11 … … 34 31 # TODO: try to incorporate current stack trace in the raised exception 35 32 if isinstance(exc, WindowsError): 36 raise OSError(str(exc) + " " +msg)33 raise OSError(str(exc)+" "+msg) 37 34 38 35 args = exc.args … … 41 38 else: 42 39 try: 43 arg0 = " ".join((args[0], 40 arg0 = " ".join((args[0],msg)) 44 41 exc.args = tuple([arg0] + list(args[1:])) 45 42 except: 46 exc.args = (" ".join((str(exc), 43 exc.args = (" ".join((str(exc),msg)),) -
sasmodels/generate.py
reafc9fa r190fc2b 7 7 particular dimensions averaged over all orientations. 8 8 9 *Iqxy(qx, qy, p1, p2, ...)* returns the scattering at qx, 9 *Iqxy(qx, qy, p1, p2, ...)* returns the scattering at qx,qy for a form 10 10 with particular dimensions for a single orientation. 11 11 … … 47 47 the *sin* and *cos* values are needed for a particular argument. Since 48 48 this function does not exist in C99, all use of *sincos* should be 49 replaced by the macro *SINCOS(value, sn,cn)* where *sn* and *cn* are49 replaced by the macro *SINCOS(value,sn,cn)* where *sn* and *cn* are 50 50 previously declared *double* variables. When compiled for systems without 51 51 OpenCL, *SINCOS* will be replaced by *sin* and *cos* calls. If *value* is … … 194 194 returns a list of files required by the model. 195 195 """ 196 from __future__ import print_function197 196 198 197 # TODO: identify model files which have changed since loading and reload them. … … 313 312 raise ValueError("%r not found in %s" % (filename, search_path)) 314 313 315 def model_sources(info):314 def sources(info): 316 315 """ 317 316 Return a list of the sources file paths for the module. … … 373 372 374 373 375 def kernel_name(info, is_2 d):374 def kernel_name(info, is_2D): 376 375 """ 377 376 Name of the exported kernel symbol. 378 377 """ 379 return info['name'] + "_" + ("Iqxy" if is_2 delse "Iq")378 return info['name'] + "_" + ("Iqxy" if is_2D else "Iq") 380 379 381 380 … … 420 419 421 420 422 LOOP_OPEN = """\ 421 def build_polydispersity_loops(pd_pars): 422 """ 423 Build polydispersity loops 424 425 Returns loop opening and loop closing 426 """ 427 LOOP_OPEN = """\ 423 428 for (int %(name)s_i=0; %(name)s_i < N%(name)s; %(name)s_i++) { 424 429 const double %(name)s = loops[2*(%(name)s_i%(offset)s)]; 425 430 const double %(name)s_w = loops[2*(%(name)s_i%(offset)s)+1];\ 426 431 """ 427 def build_polydispersity_loops(pd_pars):428 """429 Build polydispersity loops430 431 Returns loop opening and loop closing432 """433 432 depth = 4 434 433 offset = "" … … 465 464 466 465 # Load additional sources 467 source = [open(f).read() for f in model_sources(info)]466 source = [open(f).read() for f in sources(info)] 468 467 469 468 # Prepare defines … … 573 572 574 573 #for d in defines: print(d) 575 defines= '\n'.join('#define %s %s' % (k, v) for k, v in defines)576 sources= '\n\n'.join(source)574 DEFINES = '\n'.join('#define %s %s' % (k, v) for k, v in defines) 575 SOURCES = '\n\n'.join(source) 577 576 return C_KERNEL_TEMPLATE % { 578 'DEFINES': defines,579 'SOURCES': sources,577 'DEFINES':DEFINES, 578 'SOURCES':SOURCES, 580 579 } 581 580 … … 591 590 demo_parameters = getattr(kernel_module, 'demo', None) 592 591 if demo_parameters is None: 593 demo_parameters = dict((p[0], 592 demo_parameters = dict((p[0],p[2]) for p in parameters) 594 593 filename = abspath(kernel_module.__file__) 595 594 kernel_id = splitext(basename(filename))[0] … … 598 597 name = " ".join(w.capitalize() for w in kernel_id.split('_')) 599 598 info = dict( 600 id =kernel_id, # string used to load the kernel599 id = kernel_id, # string used to load the kernel 601 600 filename=abspath(kernel_module.__file__), 602 601 name=name, … … 644 643 elif section_marker.match(line): 645 644 if len(line) >= len(prior): 646 yield "".join( ("**", prior, "**"))645 yield "".join( ("**",prior,"**") ) 647 646 prior = None 648 647 else: -
sasmodels/kernelcl.py
reafc9fa rcde11f0f 1 1 """ 2 GPU driver for C kernels2 GPU support through OpenCL 3 3 4 4 There should be a single GPU environment running on the system. This … … 152 152 153 153 154 def make_result(self, size): 155 self.res = np.empty(size, dtype=self.dtype) 156 self.res_b = cl.Buffer(self.program.context, mf.READ_WRITE, self.res.nbytes) 157 return self.res, self.res_b 158 159 154 160 # for now, this returns one device in the context 155 161 # TODO: create a context that contains all devices on all platforms … … 177 183 178 184 def has_type(self, dtype): 179 """180 Return True if all devices support a given type.181 """182 185 dtype = generate.F32 if dtype == 'fast' else np.dtype(dtype) 183 186 return all(has_type(d, dtype) for d in self.context.devices) 184 187 185 188 def _create_some_context(self): 186 """187 Protected call to cl.create_some_context without interactivity. Use188 this if PYOPENCL_CTX is set in the environment. Sets the *context*189 attribute.190 """191 189 try: 192 190 self.context = cl.create_some_context(interactive=False) … … 197 195 198 196 def compile_program(self, name, source, dtype, fast=False): 199 """200 Compile the program for the device in the given context.201 """202 197 key = "%s-%s-%s"%(name, dtype, fast) 203 198 if key not in self.compiled: … … 209 204 210 205 def release_program(self, name): 211 """212 Free memory associated with the program on the device.213 """214 206 if name in self.compiled: 215 207 self.compiled[name].release() … … 217 209 218 210 def _get_default_context(): 219 """220 Get an OpenCL context, preferring GPU over CPU.221 """222 211 default = None 223 212 for platform in cl.get_platforms(): … … 252 241 self.info = info 253 242 self.source = source 254 self.dtype = generate.F32 if dtype =='fast' else np.dtype(dtype)243 self.dtype = generate.F32 if dtype=='fast' else np.dtype(dtype) 255 244 self.fast = (dtype == 'fast') 256 245 self.program = None # delay program creation 257 246 258 247 def __getstate__(self): 259 return self.info, self.source, self.dtype, self.fast 248 state = self.__dict__.copy() 249 state['program'] = None 250 return state 260 251 261 252 def __setstate__(self, state): 262 self.info, self.source, self.dtype, self.fast = state 263 self.program = None 264 265 def __call__(self, q_vectors): 253 self.__dict__ = state.copy() 254 255 def __call__(self, q_input): 256 if self.dtype != q_input.dtype: 257 raise TypeError("data is %s kernel is %s" 258 % (q_input.dtype, self.dtype)) 266 259 if self.program is None: 267 260 compiler = environment().compile_program 268 261 self.program = compiler(self.info['name'], self.source, self.dtype, 269 262 self.fast) 270 is_2d = len(q_vectors) == 2 271 kernel_name = generate.kernel_name(self.info, is_2d) 263 kernel_name = generate.kernel_name(self.info, q_input.is_2D) 272 264 kernel = getattr(self.program, kernel_name) 273 return GpuKernel(kernel, self.info, q_ vectors, self.dtype)265 return GpuKernel(kernel, self.info, q_input) 274 266 275 267 def release(self): 276 """277 Free the resources associated with the model.278 """279 268 if self.program is not None: 280 269 environment().release_program(self.info['name']) 281 270 self.program = None 282 271 283 def __del__(self): 284 self.release() 272 def make_input(self, q_vectors): 273 """ 274 Make q input vectors available to the model. 275 276 Note that each model needs its own q vector even if the case of 277 mixture models because some models may be OpenCL, some may be 278 ctypes and some may be pure python. 279 """ 280 return GpuInput(q_vectors, dtype=self.dtype) 285 281 286 282 # TODO: check that we don't need a destructor for buffers which go out of scope … … 308 304 self.nq = q_vectors[0].size 309 305 self.dtype = np.dtype(dtype) 310 self.is_2 d= (len(q_vectors) == 2)306 self.is_2D = (len(q_vectors) == 2) 311 307 # TODO: stretch input based on get_warp() 312 308 # not doing it now since warp depends on kernel, which is not known … … 321 317 322 318 def release(self): 323 """324 Free the memory.325 """326 319 for b in self.q_buffers: 327 320 b.release() 328 321 self.q_buffers = [] 329 322 330 def __del__(self):331 self.release()332 333 323 class GpuKernel(object): 334 324 """ 335 325 Callable SAS kernel. 336 326 337 *kernel* is the GpuKernel object to call 327 *kernel* is the GpuKernel object to call. 338 328 339 329 *info* is the module information 340 330 341 *q_vectors* is the q vectors at which the kernel should be evaluated 342 343 *dtype* is the kernel precision 331 *q_input* is the DllInput q vectors at which the kernel should be 332 evaluated. 344 333 345 334 The resulting call method takes the *pars*, a list of values for … … 351 340 Call :meth:`release` when done with the kernel instance. 352 341 """ 353 def __init__(self, kernel, info, q_ vectors, dtype):354 q_input = GpuInput(q_vectors, dtype)342 def __init__(self, kernel, info, q_input): 343 self.q_input = q_input 355 344 self.kernel = kernel 356 345 self.info = info 357 346 self.res = np.empty(q_input.nq, q_input.dtype) 358 dim = '2d' if q_input.is_2 delse '1d'347 dim = '2d' if q_input.is_2D else '1d' 359 348 self.fixed_pars = info['partype']['fixed-' + dim] 360 349 self.pd_pars = info['partype']['pd-' + dim] … … 369 358 q_input.global_size[0] * q_input.dtype.itemsize) 370 359 for _ in env.queues] 371 self.q_input = q_input 360 372 361 373 362 def __call__(self, fixed_pars, pd_pars, cutoff=1e-5): … … 410 399 411 400 def release(self): 412 """413 Release resources associated with the kernel.414 """415 401 for b in self.loops_b: 416 402 b.release() … … 419 405 b.release() 420 406 self.res_b = [] 421 self.q_input.release()422 407 423 408 def __del__(self): -
sasmodels/kerneldll.py
reafc9fa r74667d3 1 1 r""" 2 DLL driver for C kernels 2 C types wrapper for sasview models. 3 3 4 4 The global attribute *ALLOW_SINGLE_PRECISION_DLLS* should be set to *True* if … … 44 44 directory for this application, then OpenMP should be supported. 45 45 """ 46 from __future__ import print_function47 46 48 47 import sys … … 123 122 models are allowed as DLLs. 124 123 """ 125 if callable(info.get('Iq', 124 if callable(info.get('Iq',None)): 126 125 return PyModel(info) 127 126 … … 140 139 141 140 source = generate.convert_type(source, dtype) 142 source_files = generate. model_sources(info) + [info['filename']]143 dll 141 source_files = generate.sources(info) + [info['filename']] 142 dll= dll_path(info, dtype) 144 143 newest = max(os.path.getmtime(f) for f in source_files) 145 if not os.path.exists(dll) or os.path.getmtime(dll) <newest:144 if not os.path.exists(dll) or os.path.getmtime(dll)<newest: 146 145 # Replace with a proper temp file 147 fid, filename = tempfile.mkstemp(suffix=".c", 148 os.fdopen(fid, 146 fid, filename = tempfile.mkstemp(suffix=".c",prefix=tempfile_prefix) 147 os.fdopen(fid,"w").write(source) 149 148 command = COMPILE%{"source":filename, "output":dll} 150 149 print("Compile command: "+command) … … 161 160 def load_dll(source, info, dtype="double"): 162 161 """ 163 Create and load a dll corresponding to the source, 162 Create and load a dll corresponding to the source,info pair returned 164 163 from :func:`sasmodels.generate.make` compiled for the target precision. 165 164 … … 200 199 Npd2d = len(self.info['partype']['pd-2d']) 201 200 202 #print("dll", 201 #print("dll",self.dllpath) 203 202 try: 204 203 self.dll = ct.CDLL(self.dllpath) … … 211 210 else c_longdouble) 212 211 pd_args_1d = [c_void_p, fp] + [c_int]*Npd1d if Npd1d else [] 213 pd_args_2d 212 pd_args_2d= [c_void_p, fp] + [c_int]*Npd2d if Npd2d else [] 214 213 self.Iq = self.dll[generate.kernel_name(self.info, False)] 215 214 self.Iq.argtypes = IQ_ARGS + pd_args_1d + [fp]*Nfixed1d … … 219 218 220 219 def __getstate__(self): 221 return self.info, self.dllpath220 return {'info': self.info, 'dllpath': self.dllpath, 'dll': None} 222 221 223 222 def __setstate__(self, state): 224 self. info, self.dllpath= state225 self.dll = None 226 227 def __call__(self, q_vectors):228 q_input = PyInput(q_vectors, self.dtype)223 self.__dict__ = state 224 225 def __call__(self, q_input): 226 if self.dtype != q_input.dtype: 227 raise TypeError("data is %s kernel is %s" % (q_input.dtype, self.dtype)) 229 228 if self.dll is None: self._load_dll() 230 kernel = self.Iqxy if q_input.is_2 delse self.Iq229 kernel = self.Iqxy if q_input.is_2D else self.Iq 231 230 return DllKernel(kernel, self.info, q_input) 232 231 232 # pylint: disable=no-self-use 233 def make_input(self, q_vectors): 234 """ 235 Make q input vectors available to the model. 236 237 Note that each model needs its own q vector even if the case of 238 mixture models because some models may be OpenCL, some may be 239 ctypes and some may be pure python. 240 """ 241 return PyInput(q_vectors, dtype=self.dtype) 242 233 243 def release(self): 234 """235 Release any resources associated with the model.236 """237 244 pass # TODO: should release the dll 238 245 … … 250 257 251 258 The resulting call method takes the *pars*, a list of values for 252 the fixed parameters to the kernel, and *pd_pars*, a list of (value, 259 the fixed parameters to the kernel, and *pd_pars*, a list of (value,weight) 253 260 vectors for the polydisperse parameters. *cutoff* determines the 254 261 integration limits: any points with combined weight less than *cutoff* … … 262 269 self.kernel = kernel 263 270 self.res = np.empty(q_input.nq, q_input.dtype) 264 dim = '2d' if q_input.is_2 delse '1d'271 dim = '2d' if q_input.is_2D else '1d' 265 272 self.fixed_pars = info['partype']['fixed-'+dim] 266 273 self.pd_pars = info['partype']['pd-'+dim] … … 292 299 293 300 def release(self): 294 """295 Release any resources associated with the kernel.296 """297 301 pass -
sasmodels/kernelpy.py
reafc9fa r4c2c535 1 """2 Python driver for python kernels3 4 Calls the kernel with a vector of $q$ values for a single parameter set.5 Polydispersity is supported by looping over different parameter sets and6 summing the results. The interface to :class:`PyModel` matches those for7 :class:`kernelcl.GpuModel` and :class:`kerneldll.DllModel`.8 """9 1 import numpy as np 10 2 from numpy import pi, cos … … 13 5 14 6 class PyModel(object): 15 """16 Wrapper for pure python models.17 """18 7 def __init__(self, info): 19 8 self.info = info 20 9 21 def __call__(self, q_vectors): 22 q_input = PyInput(q_vectors, dtype=F64) 23 kernel = self.info['Iqxy'] if q_input.is_2d else self.info['Iq'] 10 def __call__(self, q_input): 11 kernel = self.info['Iqxy'] if q_input.is_2D else self.info['Iq'] 24 12 return PyKernel(kernel, self.info, q_input) 25 13 14 # pylint: disable=no-self-use 15 def make_input(self, q_vectors): 16 return PyInput(q_vectors, dtype=F64) 17 26 18 def release(self): 27 """28 Free resources associated with the model.29 """30 19 pass 31 20 … … 52 41 self.nq = q_vectors[0].size 53 42 self.dtype = dtype 54 self.is_2 d= (len(q_vectors) == 2)43 self.is_2D = (len(q_vectors) == 2) 55 44 self.q_vectors = [np.ascontiguousarray(q, self.dtype) for q in q_vectors] 56 45 self.q_pointers = [q.ctypes.data for q in self.q_vectors] 57 46 58 47 def release(self): 59 """60 Free resources associated with the model inputs.61 """62 48 self.q_vectors = [] 63 49 … … 85 71 self.q_input = q_input 86 72 self.res = np.empty(q_input.nq, q_input.dtype) 87 dim = '2d' if q_input.is_2 delse '1d'73 dim = '2d' if q_input.is_2D else '1d' 88 74 # Loop over q unless user promises that the kernel is vectorized by 89 75 # taggining it with vectorized=True … … 91 77 if dim == '2d': 92 78 def vector_kernel(qx, qy, *args): 93 """94 Vectorized 2D kernel.95 """96 79 return np.array([kernel(qxi, qyi, *args) 97 80 for qxi, qyi in zip(qx, qy)]) 98 81 else: 99 82 def vector_kernel(q, *args): 100 """101 Vectorized 1D kernel.102 """103 83 return np.array([kernel(qi, *args) 104 84 for qi in q]) … … 142 122 143 123 def release(self): 144 """145 Free resources associated with the kernel.146 """147 124 self.q_input = None 148 125 -
sasmodels/model_test.py
r5c962df r9404dd3 9 9 if model1 is 'all', then all except the remaining models will be tested 10 10 11 Each model is tested using the default parameters at q=0.1, (qx, qy)=(0.1,0.1),11 Each model is tested using the default parameters at q=0.1, (qx,qy)=(0.1,0.1), 12 12 and the ER and VR are computed. The return values at these points are not 13 13 considered. The test is only to verify that the models run to completion, … … 30 30 [ {parameters}, (qx, qy), I(qx, Iqy)], 31 31 [ {parameters}, [(qx1, qy1), (qx2, qy2), ...], 32 [I(qx1, qy1), I(qx2,qy2), ...]],32 [I(qx1,qy1), I(qx2,qy2), ...]], 33 33 34 34 [ {parameters}, 'ER', ER(pars) ], … … 43 43 Precision defaults to 5 digits (relative). 44 44 """ 45 from __future__ import print_function46 45 47 46 import sys … … 56 55 57 56 def make_suite(loaders, models): 58 """59 Construct the pyunit test suite.60 61 *loaders* is the list of kernel drivers to use, which is one of62 *["dll", "opencl"]*, *["dll"]* or *["opencl"]*. For python models,63 the python driver is always used.64 65 *models* is the list of models to test, or *["all"]* to test all models.66 """67 57 68 58 ModelTestCase = _hide_model_case_from_nosetests() … … 85 75 # don't try to call cl kernel since it will not be 86 76 # available in some environmentes. 87 is_py = callable(getattr(model_definition, 77 is_py = callable(getattr(model_definition,'Iq', None)) 88 78 89 79 if is_py: # kernel implemented in python … … 121 111 def _hide_model_case_from_nosetests(): 122 112 class ModelTestCase(unittest.TestCase): 123 """124 Test suit for a particular model with a particular kernel driver.125 126 The test suite runs a simple smoke test to make sure the model127 functions, then runs the list of tests at the bottom of the model128 description file.129 """130 113 def __init__(self, test_name, definition, test_method_name, 131 114 platform, dtype): … … 140 123 def _runTest(self): 141 124 smoke_tests = [ 142 [{}, 0.1,None],143 [{}, (0.1, 0.1),None],144 [{}, 'ER',None],145 [{}, 'VR',None],125 [{},0.1,None], 126 [{},(0.1,0.1),None], 127 [{},'ER',None], 128 [{},'VR',None], 146 129 ] 147 130 … … 180 163 actual = [call_VR(model.info, pars)] 181 164 elif isinstance(x[0], tuple): 182 Qx, 165 Qx,Qy = zip(*x) 183 166 q_vectors = [np.array(Qx), np.array(Qy)] 184 167 kernel = make_kernel(model, q_vectors) … … 196 179 # smoke test --- make sure it runs and produces a value 197 180 self.assertTrue(np.isfinite(actual_yi), 198 181 'invalid f(%s): %s' % (xi, actual_yi)) 199 182 else: 200 183 err = abs(yi - actual_yi) 201 184 nrm = abs(yi) 202 185 self.assertLess(err * 10**5, nrm, 203 'f(%s); expected:%s; actual:%s' 204 % (xi, yi, actual_yi)) 186 'f(%s); expected:%s; actual:%s' % (xi, yi, actual_yi)) 205 187 206 188 return ModelTestCase … … 255 237 Run "nosetests sasmodels" on the command line to invoke it. 256 238 """ 257 tests = make_suite(['opencl', 'dll'],['all'])239 tests = make_suite(['opencl','dll'],['all']) 258 240 for test_i in tests: 259 241 yield test_i._runTest -
sasmodels/resolution.py
r5925e90 r190fc2b 14 14 "pinhole_extend_q", "slit_extend_q", "bin_edges", 15 15 "interpolate", "linear_extrapolation", "geometric_extrapolation", 16 ]16 ] 17 17 18 18 MINIMUM_RESOLUTION = 1e-8 … … 80 80 # default to Perfect1D if the pinhole geometry is not defined. 81 81 self.q, self.q_width = q, q_width 82 self.q_calc = (pinhole_extend_q(q, q_width, nsigma=nsigma)83 if q_calc is None else np.sort(q_calc))84 self.weight_matrix = pinhole_resolution( 85 self.q_calc,self.q, np.maximum(q_width, MINIMUM_RESOLUTION))82 self.q_calc = pinhole_extend_q(q, q_width, nsigma=nsigma) \ 83 if q_calc is None else np.sort(q_calc) 84 self.weight_matrix = pinhole_resolution(self.q_calc, 85 self.q, np.maximum(q_width, MINIMUM_RESOLUTION)) 86 86 87 87 def apply(self, theory): … … 470 470 471 471 def eval_form(q, form, pars): 472 """473 Return the SAS model evaluated at *q*.474 475 *form* is the SAS model returned from :fun:`core.load_model`.476 477 *pars* are the parameter values to use when evaluating.478 """479 472 from sasmodels import core 480 473 kernel = core.make_kernel(form, [q]) … … 485 478 486 479 def gaussian(q, q0, dq): 487 """488 Return the Gaussian resolution function.489 490 *q0* is the center, *dq* is the width and *q* are the points to evaluate.491 """492 480 from numpy import exp, pi 493 481 return exp(-0.5*((q-q0)/dq)**2)/(sqrt(2*pi)*dq) … … 571 559 572 560 class ResolutionTest(unittest.TestCase): 573 """574 Test the resolution calculations.575 """576 561 577 562 def setUp(self): … … 683 668 684 669 class IgorComparisonTest(unittest.TestCase): 685 """686 Test resolution calculations against those returned by Igor.687 """688 670 689 671 def setUp(self): … … 693 675 self.model = core.load_model(sphere, dtype='double') 694 676 695 def _eval_sphere(self, pars, resolution):677 def Iq_sphere(self, pars, resolution): 696 678 from sasmodels import core 697 679 kernel = core.make_kernel(self.model, [resolution.q_calc]) … … 701 683 return result 702 684 703 def _compare(self, q, output, answer, tolerance):685 def compare(self, q, output, answer, tolerance): 704 686 #err = (output - answer)/answer 705 687 #idx = abs(err) >= tolerance … … 718 700 q, width, answer, _ = data 719 701 resolution = Perfect1D(q) 720 output = self. _eval_sphere(pars, resolution)721 self. _compare(q, output, answer, 1e-6)702 output = self.Iq_sphere(pars, resolution) 703 self.compare(q, output, answer, 1e-6) 722 704 723 705 def test_pinhole(self): … … 731 713 q, q_width, answer = data 732 714 resolution = Pinhole1D(q, q_width) 733 output = self. _eval_sphere(pars, resolution)715 output = self.Iq_sphere(pars, resolution) 734 716 # TODO: relative error should be lower 735 self. _compare(q, output, answer, 3e-4)717 self.compare(q, output, answer, 3e-4) 736 718 737 719 def test_pinhole_romberg(self): … … 754 736 q_calc, tol = None, 0.01 755 737 resolution = Pinhole1D(q, q_width, q_calc=q_calc) 756 output = self. _eval_sphere(pars, resolution)738 output = self.Iq_sphere(pars, resolution) 757 739 if 0: # debug plot 758 740 import matplotlib.pyplot as plt 759 741 resolution = Perfect1D(q) 760 source = self. _eval_sphere(pars, resolution)742 source = self.Iq_sphere(pars, resolution) 761 743 plt.loglog(q, source, '.') 762 744 plt.loglog(q, answer, '-', hold=True) 763 745 plt.loglog(q, output, '-', hold=True) 764 746 plt.show() 765 self. _compare(q, output, answer, tol)747 self.compare(q, output, answer, tol) 766 748 767 749 def test_slit(self): … … 775 757 q, delta_qv, _, answer = data 776 758 resolution = Slit1D(q, width=delta_qv, height=0) 777 output = self. _eval_sphere(pars, resolution)759 output = self.Iq_sphere(pars, resolution) 778 760 # TODO: eliminate Igor test since it is too inaccurate to be useful. 779 761 # This means we can eliminate the test data as well, and instead 780 762 # use a generated q vector. 781 self. _compare(q, output, answer, 0.5)763 self.compare(q, output, answer, 0.5) 782 764 783 765 def test_slit_romberg(self): … … 795 777 delta_qv[0], 0.) 796 778 resolution = Slit1D(q, width=delta_qv, height=0, q_calc=q_calc) 797 output = self. _eval_sphere(pars, resolution)779 output = self.Iq_sphere(pars, resolution) 798 780 # TODO: relative error should be lower 799 self. _compare(q, output, answer, 0.025)781 self.compare(q, output, answer, 0.025) 800 782 801 783 def test_ellipsoid(self): … … 817 799 # TODO: 10% is too much error; use better algorithm 818 800 #print(np.max(abs(answer-output)/answer)) 819 self. _compare(q, output, answer, 0.1)801 self.compare(q, output, answer, 0.1) 820 802 821 803 #TODO: can sas q spacing be too sparse for the resolution calculation? … … 831 813 q, q_width, answer = data[:, ::20] # Take every nth point 832 814 resolution = Pinhole1D(q, q_width) 833 output = self. _eval_sphere(pars, resolution)834 self. _compare(q, output, answer, 1e-6)815 output = self.Iq_sphere(pars, resolution) 816 self.compare(q, output, answer, 1e-6) 835 817 836 818 … … 1085 1067 1086 1068 def demo_pinhole_1d(): 1087 """1088 Show example of pinhole smearing.1089 """1090 1069 q = np.logspace(-4, np.log10(0.2), 400) 1091 1070 q_width = 0.1*q … … 1094 1073 1095 1074 def demo_slit_1d(): 1096 """1097 Show example of slit smearing.1098 """1099 1075 q = np.logspace(-4, np.log10(0.2), 100) 1100 1076 w = h = 0. … … 1107 1083 1108 1084 def demo(): 1109 """1110 Run the resolution demos.1111 """1112 1085 import matplotlib.pyplot as plt 1113 1086 plt.subplot(121) -
sasmodels/resolution2d.py
r823e620 r841753c 143 143 if self.coords == 'polar': 144 144 q_r = sqrt(qx**2 + qy**2) 145 qx_res = ((dqx*cos(dphi) + q_r) * cos(-q_phi) 146 +dqy*sin(dphi) * sin(-q_phi))147 qy_res = (-(dqx*cos(dphi) + q_r) * sin(-q_phi) 148 +dqy*sin(dphi) * cos(-q_phi))145 qx_res = ((dqx*cos(dphi) + q_r) * cos(-q_phi) + 146 dqy*sin(dphi) * sin(-q_phi)) 147 qy_res = (-(dqx*cos(dphi) + q_r) * sin(-q_phi) + 148 dqy*sin(dphi) * cos(-q_phi)) 149 149 else: 150 qx_res = qx + dqx*cos(dphi)151 qy_res = qy + dqy*sin(dphi)150 qx_res = qx + dqx*cos(dphi) 151 qy_res = qy + dqy*sin(dphi) 152 152 153 153 … … 162 162 theory = np.reshape(theory, (nbins, nq)) 163 163 ## Averaging with Gaussian weighting: normalization included. 164 value = 164 value =np.average(theory, axis=0, weights=self.q_calc_weights) 165 165 ## Return the smeared values in the range of self.index 166 166 return value -
sasmodels/sasview_model.py
reafc9fa r9404dd3 283 283 """ 284 284 q_vectors = [np.asarray(q) for q in args] 285 fn = self._model( q_vectors)285 fn = self._model(self._model.make_input(q_vectors)) 286 286 pars = [self.params[v] for v in fn.fixed_pars] 287 287 pd_pars = [self._get_weights(p) for p in fn.pd_pars] -
sasmodels/weights.py
r5c962df r3c56da87 22 22 23 23 def get_pars(self): 24 """25 Return the parameters to the disperser as a dictionary.26 """27 24 pars = {'type': self.type} 28 25 pars.update(self.__dict__) … … 31 28 # pylint: disable=no-self-use 32 29 def set_weights(self, values, weights): 33 """34 Set the weights on the disperser if it is :class:`ArrayDispersion`.35 """36 30 raise RuntimeError("set_weights is only available for ArrayDispersion") 37 31 … … 42 36 *center* is the center of the distribution 43 37 44 *lb*, 38 *lb*,*ub* are the min and max allowed values 45 39 46 40 *relative* is True if the distribution width is proportional to the … … 69 63 70 64 class GaussianDispersion(Dispersion): 71 r"""72 Gaussian dispersion, with 1-\ $\sigma$ width.73 74 .. math::75 76 w = \exp\left(-\tfrac12 (x - c)^2/\sigma^2\right)77 """78 65 type = "gaussian" 79 66 default = dict(npts=35, width=0, nsigmas=3) … … 85 72 86 73 class RectangleDispersion(Dispersion): 87 r"""88 Uniform dispersion, with width $\sqrt{3}\sigma$.89 90 .. math::91 92 w = 193 """94 74 type = "rectangle" 95 75 default = dict(npts=35, width=0, nsigmas=1.70325) … … 101 81 102 82 class LogNormalDispersion(Dispersion): 103 r"""104 log Gaussian dispersion, with 1-\ $\sigma$ width.105 106 .. math::107 108 w = \frac{\exp\left(-\tfrac12 (\ln x - c)^2/\sigma^2\right)}{x\sigma}109 """110 83 type = "lognormal" 111 84 default = dict(npts=80, width=0, nsigmas=8) 112 85 def _weights(self, center, sigma, lb, ub): 113 x = self._linspace(center, sigma, max(lb, 1e-8), max(ub,1e-8))114 px = np.exp(-0.5*(np.log(x)-center)**2 /sigma**2)/(x*sigma)86 x = self._linspace(center, sigma, max(lb,1e-8), max(ub,1e-8)) 87 px = np.exp(-0.5*(np.log(x)-center)**2)/sigma**2/(x*sigma) 115 88 return x, px 116 89 117 90 118 91 class SchulzDispersion(Dispersion): 119 r"""120 Schultz dispersion, with 1-\ $\sigma$ width.121 122 .. math::123 124 w = \frac{z^z\,R^{z-1}}{e^{Rz}\,c \Gamma(z)}125 126 where $c$ is the center of the distribution, $R = x/c$ and $z=(c/\sigma)^2$.127 128 This is evaluated using logarithms as129 130 .. math::131 132 w = \exp\left(z \ln z + (z-1)\ln R - Rz - \ln c - \ln \Gamma(z) \right)133 """134 92 type = "schulz" 135 93 default = dict(npts=80, width=0, nsigmas=8) 136 94 def _weights(self, center, sigma, lb, ub): 137 x = self._linspace(center, sigma, max(lb, 1e-8), max(ub,1e-8))138 R 95 x = self._linspace(center, sigma, max(lb,1e-8), max(ub,1e-8)) 96 R= x/center 139 97 z = (center/sigma)**2 140 98 arg = z*np.log(z) + (z-1)*np.log(R) - R*z - np.log(center) - gammaln(z) … … 144 102 145 103 class ArrayDispersion(Dispersion): 146 r"""147 Empirical dispersion curve.148 149 Use :meth:`set_weights` to set $w = f(x)$.150 """151 104 type = "array" 152 105 default = dict(npts=35, width=0, nsigmas=1) … … 157 110 158 111 def set_weights(self, values, weights): 159 """160 Set the weights for the given x values.161 """162 112 self.values = np.ascontiguousarray(values, 'd') 163 113 self.weights = np.ascontiguousarray(weights, 'd') … … 167 117 # TODO: interpolate into the array dispersion using npts 168 118 x = center + self.values*sigma 169 idx = (x >= lb) & (x <=ub)119 idx = (x>=lb)&(x<=ub) 170 120 x = x[idx] 171 121 px = self.weights[idx] … … 174 124 175 125 # dispersion name -> disperser lookup table. 176 models = dict((d.type, 126 models = dict((d.type,d) for d in ( 177 127 GaussianDispersion, RectangleDispersion, 178 128 ArrayDispersion, SchulzDispersion, LogNormalDispersion … … 199 149 of the parameter, and false if it is an absolute width. 200 150 201 Returns *(value, 151 Returns *(value,weight)*, where *value* and *weight* are vectors. 202 152 """ 203 153 cls = models[disperser] 204 154 obj = cls(n, width, nsigmas) 205 v, 206 return v, 155 v,w = obj.get_weights(value, limits[0], limits[1], relative) 156 return v,w 207 157 208 158 # Hack to allow sasview dispersion objects to interoperate with sasmodels 209 dispersers = dict((v.__name__, k) for k,v in models.items())159 dispersers = dict((v.__name__,k) for k,v in models.items()) 210 160 dispersers['DispersionModel'] = RectangleDispersion.type 211 161
Note: See TracChangeset
for help on using the changeset viewer.