Changeset 8696a87 in sasmodels
- Timestamp:
- Feb 1, 2016 4:38:33 AM (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:
- f12357f, 577912b
- Parents:
- 504abee (diff), 5c962df (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent. - Files:
-
- 5 added
- 19 edited
Legend:
- Unmodified
- Added
- Removed
-
extra/pylint.rc
rd4666ca r823e620 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, 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, 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, 116 115 ER, call_ER, VR, call_VR, 117 116 Rmax, SElength, … … 281 280 # (useful for modules/projects where namespaces are manipulated during runtime 282 281 # and thus existing member attributes cannot be deduced by static analysis 283 ignored-modules=numpy,np 282 ignored-modules=numpy,np,numpy.random, 283 bumps,sas, 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
r63b32bb r823e620 8 8 #print("processing",module.name) 9 9 if module.name.startswith('numpy'): 10 if module.name == 'numpy': import numpy 11 elif module.name == 'numpy.random': import numpy.random 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 12 15 -
extra/pylint_pyopencl.py
r3c56da87 r823e620 9 9 if module.name == 'pyopencl': 10 10 import pyopencl 11 import pyopencl as cl -
extra/run-pylint.py
rf01e53d r823e620 6 6 7 7 def main(): 8 extra = abspath(dirname(__file__)) 9 root = abspath(joinpath(extra, '..')) 10 8 11 envpath = os.environ.get('PYTHONPATH',None) 9 12 path = [envpath] if envpath else [] 10 path.append(abspath(dirname(__file__))) # so we can find the plugins 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 11 20 os.environ['PYTHONPATH'] = ':'.join(path) 12 root = abspath(joinpath(dirname(__file__), '..')) 21 22 # Run the lint command 23 cmd = "pylint --rcfile extra/pylint.rc -f parseable sasmodels" 13 24 os.chdir(root) 14 cmd = "pylint --rcfile extra/pylint.rc -f parseable sasmodels"15 25 status = os.system(cmd) 16 26 sys.exit(status) -
sasmodels/compare.py
r190fc2b rd07c883 604 604 def columnize(L, indent="", width=79): 605 605 """ 606 Format a list of strings into columns for printing. 606 Format a list of strings into columns. 607 608 Returns a string with carriage returns ready for printing. 607 609 """ 608 610 column_width = max(len(w) for w in L) + 1 -
sasmodels/core.py
r190fc2b reafc9fa 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 be 42 used with functions in generate to build the docs or extract model info. 40 43 """ 41 44 __import__('sasmodels.models.'+model_name) … … 115 118 Return a computation kernel from the model definition and the q input. 116 119 """ 117 model_input = model.make_input(q_vectors) 118 return model(model_input) 120 return model(q_vectors) 119 121 120 122 def get_weights(info, pars, name): -
sasmodels/data.py
r69ec80f r5c962df 87 87 88 88 class Data1D(object): 89 """ 90 1D data object. 91 92 Note that this definition matches the attributes from sasview, with 93 some generic 1D data vectors and some SAS specific definitions. Some 94 refactoring to allow consistent naming conventions between 1D, 2D and 95 SESANS data would be helpful. 96 97 **Attributes** 98 99 *x*, *dx*: $q$ vector and gaussian resolution 100 101 *y*, *dy*: $I(q)$ vector and measurement uncertainty 102 103 *mask*: values to include in plotting/analysis 104 105 *dxl*: slit widths for slit smeared data, with *dx* ignored 106 107 *qmin*, *qmax*: range of $q$ values in *x* 108 109 *filename*: label for the data line 110 111 *_xaxis*, *_xunit*: label and units for the *x* axis 112 113 *_yaxis*, *_yunit*: label and units for the *y* axis 114 """ 89 115 def __init__(self, x=None, y=None, dx=None, dy=None): 90 116 self.x, self.y, self.dx, self.dy = x, y, dx, dy … … 93 119 self.qmin = x.min() if x is not None else np.NaN 94 120 self.qmax = x.max() if x is not None else np.NaN 95 self.mask = np.isnan(y) if y is not None else None 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) 96 125 self._xaxis, self._xunit = "x", "" 97 126 self._yaxis, self._yunit = "y", "" … … 114 143 115 144 class Data2D(object): 145 """ 146 2D data object. 147 148 Note that this definition matches the attributes from sasview. Some 149 refactoring to allow consistent naming conventions between 1D, 2D and 150 SESANS data would be helpful. 151 152 **Attributes** 153 154 *qx_data*, *dqx_data*: $q_x$ matrix and gaussian resolution 155 156 *qy_data*, *dqy_data*: $q_y$ matrix and gaussian resolution 157 158 *data*, *err_data*: $I(q)$ matrix and measurement uncertainty 159 160 *mask*: values to exclude from plotting/analysis 161 162 *qmin*, *qmax*: range of $q$ values in *x* 163 164 *filename*: label for the data line 165 166 *_xaxis*, *_xunit*: label and units for the *x* axis 167 168 *_yaxis*, *_yunit*: label and units for the *y* axis 169 170 *_zaxis*, *_zunit*: label and units for the *y* axis 171 172 *Q_unit*, *I_unit*: units for Q and intensity 173 174 *x_bins*, *y_bins*: grid steps in *x* and *y* directions 175 """ 116 176 def __init__(self, x=None, y=None, z=None, dx=None, dy=None, dz=None): 117 177 self.qx_data, self.dqx_data = x, dx 118 178 self.qy_data, self.dqy_data = y, dy 119 179 self.data, self.err_data = z, dz 120 self.mask = ~np.isnan(z) if z is not None else None 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) 121 183 self.q_data = np.sqrt(x**2 + y**2) 122 184 self.qmin = 1e-16 … … 126 188 self.Q_unit = "1/A" 127 189 self.I_unit = "1/cm" 128 self.xaxis("Q_x", " A^{-1}")129 self.yaxis("Q_y", " A^{-1}")130 self.zaxis("Intensity", r"\text{cm}^{-1}")190 self.xaxis("Q_x", "1/A") 191 self.yaxis("Q_y", "1/A") 192 self.zaxis("Intensity", "1/cm") 131 193 self._xaxis, self._xunit = "x", "" 132 194 self._yaxis, self._yunit = "y", "" … … 157 219 158 220 class Vector(object): 221 """ 222 3-space vector of *x*, *y*, *z* 223 """ 159 224 def __init__(self, x=None, y=None, z=None): 160 225 self.x, self.y, self.z = x, y, z … … 235 300 """ 236 301 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 limits 308 are inferred from the data. 237 309 """ 238 310 # Note: kind of weird using the plot result functions to plot just the … … 249 321 def plot_theory(data, theory, resid=None, view='log', 250 322 use_data=True, limits=None): 323 """ 324 Plot theory calculation. 325 326 *data* is needed to define the graph properties such as labels and 327 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 linear 332 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 limits 336 are inferred from the data. 337 """ 251 338 if hasattr(data, 'lam'): 252 339 _plot_result_sesans(data, theory, resid, use_data=True, limits=limits) … … 258 345 259 346 def protect(fn): 347 """ 348 Decorator to wrap calls in an exception trapper which prints the 349 exception and continues. Keyboard interrupts are ignored. 350 """ 260 351 def wrapper(*args, **kw): 352 """ 353 Trap and print errors from function. 354 """ 261 355 try: 262 356 return fn(*args, **kw) 357 except KeyboardInterrupt: 358 raise 263 359 except: 264 360 traceback.print_exc() … … 332 428 @protect 333 429 def _plot_result_sesans(data, theory, resid, use_data, limits=None): 430 """ 431 Plot SESANS results. 432 """ 334 433 import matplotlib.pyplot as plt 335 434 use_data = use_data and data.y is not None … … 459 558 460 559 def demo(): 560 """ 561 Load and plot a SAS dataset. 562 """ 461 563 data = load_data('DEC07086.DAT') 462 564 set_beam_stop(data, 0.004) -
sasmodels/direct_model.py
r9404dd3 reafc9fa 1 import warnings 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 2 24 3 25 import numpy as np … … 19 41 currently used by :class:`sasview_model.SasviewModel` since this will 20 42 require a number of changes to SasView before we can do it. 43 44 :meth:`_interpret_data` initializes the data structures necessary 45 to manage the calculations. This sets attributes in the child class 46 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 a 52 dataset with the results from :meth:`_calc_theory`. 21 53 """ 22 54 def _interpret_data(self, data, model): 55 # pylint: disable=attribute-defined-outside-init 56 23 57 self._data = data 24 58 self._model = model … … 36 70 if self.data_type == 'sesans': 37 71 q = sesans.make_q(data.sample.zacceptance, data.Rmax) 38 self.index = slice(None, None) 72 index = slice(None, None) 73 res = None 39 74 if data.y is not None: 40 self.Iq = data.y 41 self.dIq = data.dy 75 Iq, dIq = data.y, data.dy 76 else: 77 Iq, dIq = None, None 42 78 #self._theory = np.zeros_like(q) 43 79 q_vectors = [q] … … 49 85 qmax = getattr(data, 'qmax', np.inf) 50 86 accuracy = getattr(data, 'accuracy', 'Low') 51 self.index = ~data.mask & (q >= qmin) & (q <= qmax)87 index = ~data.mask & (q >= qmin) & (q <= qmax) 52 88 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) 89 index &= ~np.isnan(data.data) 90 Iq = data.data[index] 91 dIq = data.err_data[index] 92 else: 93 Iq, dIq = None, None 94 res = resolution2d.Pinhole2D(data=data, index=index, 95 nsigma=3.0, accuracy=accuracy) 58 96 #self._theory = np.zeros_like(self.Iq) 59 q_vectors = self.resolution.q_calc97 q_vectors = res.q_calc 60 98 elif self.data_type == 'Iq': 61 self.index = (data.x >= data.qmin) & (data.x <= data.qmax)99 index = (data.x >= data.qmin) & (data.x <= data.qmax) 62 100 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] 101 index &= ~np.isnan(data.y) 102 Iq = data.y[index] 103 dIq = data.dy[index] 104 else: 105 Iq, dIq = None, None 66 106 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)107 q, dq = data.x[index], data.dx[index] 108 if (dq > 0).any(): 109 res = resolution.Pinhole1D(q, dq) 70 110 else: 71 self.resolution= resolution.Perfect1D(q)72 elif (getattr(data, 'dxl', None) is not None and73 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])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]) 79 119 80 120 #self._theory = np.zeros_like(self.Iq) 81 q_vectors = [ self.resolution.q_calc]121 q_vectors = [res.q_calc] 82 122 else: 83 123 raise ValueError("Unknown data type") # never gets here … … 87 127 self._kernel_inputs = [v for v in q_vectors] 88 128 self._kernel = None 129 self.Iq, self.dIq, self.index = Iq, dIq, index 130 self.resolution = res 89 131 90 132 def _set_data(self, Iq, noise=None): 133 # pylint: disable=attribute-defined-outside-init 91 134 if noise is not None: 92 135 self.dIq = Iq*noise*0.01 … … 106 149 def _calc_theory(self, pars, cutoff=0.0): 107 150 if self._kernel is None: 108 q_input = self._model.make_input(self._kernel_inputs) 109 self._kernel = self._model(q_input) 151 self._kernel = make_kernel(self._model, self._kernel_inputs) # pylint: disable=attribute-defined-outside-init 110 152 111 153 Iq_calc = call_kernel(self._kernel, pars, cutoff=cutoff) … … 120 162 121 163 class DirectModel(DataMixin): 164 """ 165 Create a calculator object for a model. 166 167 *data* is 1D SAS, 2D SAS or SESANS data 168 169 *model* is a model calculator return from :func:`generate.load_model` 170 171 *cutoff* is the polydispersity weight cutoff. 172 """ 122 173 def __init__(self, data, model, cutoff=1e-5): 123 174 self.model = model 124 175 self.cutoff = cutoff 176 # Note: _interpret_data defines the model attributes 125 177 self._interpret_data(data, model) 126 self.kernel = make_kernel(self.model, self._kernel_inputs) 178 127 179 def __call__(self, **pars): 128 180 return self._calc_theory(pars, cutoff=self.cutoff) 181 129 182 def ER(self, **pars): 183 """ 184 Compute the equivalent radius for the model. 185 186 Return 0. if not defined. 187 """ 130 188 return call_ER(self.model.info, pars) 189 131 190 def VR(self, **pars): 191 """ 192 Compute the equivalent volume for the model, including polydispersity 193 effects. 194 195 Return 1. if not defined. 196 """ 132 197 return call_VR(self.model.info, pars) 198 133 199 def simulate_data(self, noise=None, **pars): 200 """ 201 Generate simulated data for the model. 202 """ 134 203 Iq = self.__call__(**pars) 135 204 self._set_data(Iq, noise=noise) 136 205 137 def demo(): 206 def main(): 207 """ 208 Program to evaluate a particular model at a set of q values. 209 """ 138 210 import sys 139 211 from .data import empty_data1D, empty_data2D … … 144 216 model_name = sys.argv[1] 145 217 call = sys.argv[2].upper() 146 if call not in ("ER", "VR"):218 if call not in ("ER", "VR"): 147 219 try: 148 220 values = [float(v) for v in call.split(',')] … … 153 225 data = empty_data1D([q]) 154 226 elif len(values) == 2: 155 qx, qy = values156 data = empty_data2D([qx], [qy])227 qx, qy = values 228 data = empty_data2D([qx], [qy]) 157 229 else: 158 230 print("use q or qx,qy or ER or VR") … … 164 236 model = load_model(model_definition, dtype='single') 165 237 calculator = DirectModel(data, model) 166 pars = dict((k, float(v))238 pars = dict((k, float(v)) 167 239 for pair in sys.argv[3:] 168 for k, v in [pair.split('=')])240 for k, v in [pair.split('=')]) 169 241 if call == "ER": 170 242 print(calculator.ER(**pars)) … … 176 248 177 249 if __name__ == "__main__": 178 demo()250 main() -
sasmodels/exception.py
reaca9eb r823e620 8 8 except NameError: 9 9 class WindowsError(Exception): 10 """ 11 Fake WindowsException when not on Windows. 12 """ 10 13 pass 11 14 … … 31 34 # TODO: try to incorporate current stack trace in the raised exception 32 35 if isinstance(exc, WindowsError): 33 raise OSError(str(exc) +" "+msg)36 raise OSError(str(exc) + " " + msg) 34 37 35 38 args = exc.args … … 38 41 else: 39 42 try: 40 arg0 = " ".join((args[0], msg))43 arg0 = " ".join((args[0], msg)) 41 44 exc.args = tuple([arg0] + list(args[1:])) 42 45 except: 43 exc.args = (" ".join((str(exc), msg)),)46 exc.args = (" ".join((str(exc), msg)),) -
sasmodels/generate.py
r190fc2b reafc9fa 7 7 particular dimensions averaged over all orientations. 8 8 9 *Iqxy(qx, qy, p1, p2, ...)* returns the scattering at qx, qy for a form9 *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_function 196 197 197 198 # TODO: identify model files which have changed since loading and reload them. … … 312 313 raise ValueError("%r not found in %s" % (filename, search_path)) 313 314 314 def sources(info):315 def model_sources(info): 315 316 """ 316 317 Return a list of the sources file paths for the module. … … 372 373 373 374 374 def kernel_name(info, is_2 D):375 def kernel_name(info, is_2d): 375 376 """ 376 377 Name of the exported kernel symbol. 377 378 """ 378 return info['name'] + "_" + ("Iqxy" if is_2 Delse "Iq")379 return info['name'] + "_" + ("Iqxy" if is_2d else "Iq") 379 380 380 381 … … 419 420 420 421 421 def build_polydispersity_loops(pd_pars): 422 """ 423 Build polydispersity loops 424 425 Returns loop opening and loop closing 426 """ 427 LOOP_OPEN = """\ 422 LOOP_OPEN = """\ 428 423 for (int %(name)s_i=0; %(name)s_i < N%(name)s; %(name)s_i++) { 429 424 const double %(name)s = loops[2*(%(name)s_i%(offset)s)]; 430 425 const double %(name)s_w = loops[2*(%(name)s_i%(offset)s)+1];\ 431 426 """ 427 def build_polydispersity_loops(pd_pars): 428 """ 429 Build polydispersity loops 430 431 Returns loop opening and loop closing 432 """ 432 433 depth = 4 433 434 offset = "" … … 464 465 465 466 # Load additional sources 466 source = [open(f).read() for f in sources(info)]467 source = [open(f).read() for f in model_sources(info)] 467 468 468 469 # Prepare defines … … 572 573 573 574 #for d in defines: print(d) 574 DEFINES= '\n'.join('#define %s %s' % (k, v) for k, v in defines)575 SOURCES= '\n\n'.join(source)575 defines = '\n'.join('#define %s %s' % (k, v) for k, v in defines) 576 sources = '\n\n'.join(source) 576 577 return C_KERNEL_TEMPLATE % { 577 'DEFINES': DEFINES,578 'SOURCES': SOURCES,578 'DEFINES': defines, 579 'SOURCES': sources, 579 580 } 580 581 … … 590 591 demo_parameters = getattr(kernel_module, 'demo', None) 591 592 if demo_parameters is None: 592 demo_parameters = dict((p[0], p[2]) for p in parameters)593 demo_parameters = dict((p[0], p[2]) for p in parameters) 593 594 filename = abspath(kernel_module.__file__) 594 595 kernel_id = splitext(basename(filename))[0] … … 597 598 name = " ".join(w.capitalize() for w in kernel_id.split('_')) 598 599 info = dict( 599 id =kernel_id, # string used to load the kernel600 id=kernel_id, # string used to load the kernel 600 601 filename=abspath(kernel_module.__file__), 601 602 name=name, … … 643 644 elif section_marker.match(line): 644 645 if len(line) >= len(prior): 645 yield "".join( ("**",prior,"**"))646 yield "".join(("**", prior, "**")) 646 647 prior = None 647 648 else: -
sasmodels/kernelcl.py
rcde11f0f reafc9fa 1 1 """ 2 GPU support through OpenCL2 GPU driver for C kernels 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_b158 159 160 154 # for now, this returns one device in the context 161 155 # TODO: create a context that contains all devices on all platforms … … 183 177 184 178 def has_type(self, dtype): 179 """ 180 Return True if all devices support a given type. 181 """ 185 182 dtype = generate.F32 if dtype == 'fast' else np.dtype(dtype) 186 183 return all(has_type(d, dtype) for d in self.context.devices) 187 184 188 185 def _create_some_context(self): 186 """ 187 Protected call to cl.create_some_context without interactivity. Use 188 this if PYOPENCL_CTX is set in the environment. Sets the *context* 189 attribute. 190 """ 189 191 try: 190 192 self.context = cl.create_some_context(interactive=False) … … 195 197 196 198 def compile_program(self, name, source, dtype, fast=False): 199 """ 200 Compile the program for the device in the given context. 201 """ 197 202 key = "%s-%s-%s"%(name, dtype, fast) 198 203 if key not in self.compiled: … … 204 209 205 210 def release_program(self, name): 211 """ 212 Free memory associated with the program on the device. 213 """ 206 214 if name in self.compiled: 207 215 self.compiled[name].release() … … 209 217 210 218 def _get_default_context(): 219 """ 220 Get an OpenCL context, preferring GPU over CPU. 221 """ 211 222 default = None 212 223 for platform in cl.get_platforms(): … … 241 252 self.info = info 242 253 self.source = source 243 self.dtype = generate.F32 if dtype =='fast' else np.dtype(dtype)254 self.dtype = generate.F32 if dtype == 'fast' else np.dtype(dtype) 244 255 self.fast = (dtype == 'fast') 245 256 self.program = None # delay program creation 246 257 247 258 def __getstate__(self): 248 state = self.__dict__.copy() 249 state['program'] = None 250 return state 259 return self.info, self.source, self.dtype, self.fast 251 260 252 261 def __setstate__(self, state): 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)) 262 self.info, self.source, self.dtype, self.fast = state 263 self.program = None 264 265 def __call__(self, q_vectors): 259 266 if self.program is None: 260 267 compiler = environment().compile_program 261 268 self.program = compiler(self.info['name'], self.source, self.dtype, 262 269 self.fast) 263 kernel_name = generate.kernel_name(self.info, q_input.is_2D) 270 is_2d = len(q_vectors) == 2 271 kernel_name = generate.kernel_name(self.info, is_2d) 264 272 kernel = getattr(self.program, kernel_name) 265 return GpuKernel(kernel, self.info, q_ input)273 return GpuKernel(kernel, self.info, q_vectors, self.dtype) 266 274 267 275 def release(self): 276 """ 277 Free the resources associated with the model. 278 """ 268 279 if self.program is not None: 269 280 environment().release_program(self.info['name']) 270 281 self.program = None 271 282 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) 283 def __del__(self): 284 self.release() 281 285 282 286 # TODO: check that we don't need a destructor for buffers which go out of scope … … 304 308 self.nq = q_vectors[0].size 305 309 self.dtype = np.dtype(dtype) 306 self.is_2 D= (len(q_vectors) == 2)310 self.is_2d = (len(q_vectors) == 2) 307 311 # TODO: stretch input based on get_warp() 308 312 # not doing it now since warp depends on kernel, which is not known … … 317 321 318 322 def release(self): 323 """ 324 Free the memory. 325 """ 319 326 for b in self.q_buffers: 320 327 b.release() 321 328 self.q_buffers = [] 322 329 330 def __del__(self): 331 self.release() 332 323 333 class GpuKernel(object): 324 334 """ 325 335 Callable SAS kernel. 326 336 327 *kernel* is the GpuKernel object to call .337 *kernel* is the GpuKernel object to call 328 338 329 339 *info* is the module information 330 340 331 *q_input* is the DllInput q vectors at which the kernel should be 332 evaluated. 341 *q_vectors* is the q vectors at which the kernel should be evaluated 342 343 *dtype* is the kernel precision 333 344 334 345 The resulting call method takes the *pars*, a list of values for … … 340 351 Call :meth:`release` when done with the kernel instance. 341 352 """ 342 def __init__(self, kernel, info, q_ input):343 self.q_input = q_input353 def __init__(self, kernel, info, q_vectors, dtype): 354 q_input = GpuInput(q_vectors, dtype) 344 355 self.kernel = kernel 345 356 self.info = info 346 357 self.res = np.empty(q_input.nq, q_input.dtype) 347 dim = '2d' if q_input.is_2 Delse '1d'358 dim = '2d' if q_input.is_2d else '1d' 348 359 self.fixed_pars = info['partype']['fixed-' + dim] 349 360 self.pd_pars = info['partype']['pd-' + dim] … … 358 369 q_input.global_size[0] * q_input.dtype.itemsize) 359 370 for _ in env.queues] 360 371 self.q_input = q_input 361 372 362 373 def __call__(self, fixed_pars, pd_pars, cutoff=1e-5): … … 399 410 400 411 def release(self): 412 """ 413 Release resources associated with the kernel. 414 """ 401 415 for b in self.loops_b: 402 416 b.release() … … 405 419 b.release() 406 420 self.res_b = [] 421 self.q_input.release() 407 422 408 423 def __del__(self): -
sasmodels/kerneldll.py
r74667d3 reafc9fa 1 1 r""" 2 C types wrapper for sasview models. 2 DLL driver for C kernels 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_function 46 47 47 48 import sys … … 122 123 models are allowed as DLLs. 123 124 """ 124 if callable(info.get('Iq', None)):125 if callable(info.get('Iq', None)): 125 126 return PyModel(info) 126 127 … … 139 140 140 141 source = generate.convert_type(source, dtype) 141 source_files = generate. sources(info) + [info['filename']]142 dll = dll_path(info, dtype)142 source_files = generate.model_sources(info) + [info['filename']] 143 dll = dll_path(info, dtype) 143 144 newest = max(os.path.getmtime(f) for f in source_files) 144 if not os.path.exists(dll) or os.path.getmtime(dll) <newest:145 if not os.path.exists(dll) or os.path.getmtime(dll) < newest: 145 146 # Replace with a proper temp file 146 fid, filename = tempfile.mkstemp(suffix=".c", prefix=tempfile_prefix)147 os.fdopen(fid, "w").write(source)147 fid, filename = tempfile.mkstemp(suffix=".c", prefix=tempfile_prefix) 148 os.fdopen(fid, "w").write(source) 148 149 command = COMPILE%{"source":filename, "output":dll} 149 150 print("Compile command: "+command) … … 160 161 def load_dll(source, info, dtype="double"): 161 162 """ 162 Create and load a dll corresponding to the source, info pair returned163 Create and load a dll corresponding to the source, info pair returned 163 164 from :func:`sasmodels.generate.make` compiled for the target precision. 164 165 … … 199 200 Npd2d = len(self.info['partype']['pd-2d']) 200 201 201 #print("dll", self.dllpath)202 #print("dll", self.dllpath) 202 203 try: 203 204 self.dll = ct.CDLL(self.dllpath) … … 210 211 else c_longdouble) 211 212 pd_args_1d = [c_void_p, fp] + [c_int]*Npd1d if Npd1d else [] 212 pd_args_2d = [c_void_p, fp] + [c_int]*Npd2d if Npd2d else []213 pd_args_2d = [c_void_p, fp] + [c_int]*Npd2d if Npd2d else [] 213 214 self.Iq = self.dll[generate.kernel_name(self.info, False)] 214 215 self.Iq.argtypes = IQ_ARGS + pd_args_1d + [fp]*Nfixed1d … … 218 219 219 220 def __getstate__(self): 220 return {'info': self.info, 'dllpath': self.dllpath, 'dll': None}221 return self.info, self.dllpath 221 222 222 223 def __setstate__(self, state): 223 self. __dict__= state224 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))224 self.info, self.dllpath = state 225 self.dll = None 226 227 def __call__(self, q_vectors): 228 q_input = PyInput(q_vectors, self.dtype) 228 229 if self.dll is None: self._load_dll() 229 kernel = self.Iqxy if q_input.is_2 Delse self.Iq230 kernel = self.Iqxy if q_input.is_2d else self.Iq 230 231 return DllKernel(kernel, self.info, q_input) 231 232 232 # pylint: disable=no-self-use233 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 of238 mixture models because some models may be OpenCL, some may be239 ctypes and some may be pure python.240 """241 return PyInput(q_vectors, dtype=self.dtype)242 243 233 def release(self): 234 """ 235 Release any resources associated with the model. 236 """ 244 237 pass # TODO: should release the dll 245 238 … … 257 250 258 251 The resulting call method takes the *pars*, a list of values for 259 the fixed parameters to the kernel, and *pd_pars*, a list of (value, weight)252 the fixed parameters to the kernel, and *pd_pars*, a list of (value, weight) 260 253 vectors for the polydisperse parameters. *cutoff* determines the 261 254 integration limits: any points with combined weight less than *cutoff* … … 269 262 self.kernel = kernel 270 263 self.res = np.empty(q_input.nq, q_input.dtype) 271 dim = '2d' if q_input.is_2 Delse '1d'264 dim = '2d' if q_input.is_2d else '1d' 272 265 self.fixed_pars = info['partype']['fixed-'+dim] 273 266 self.pd_pars = info['partype']['pd-'+dim] … … 299 292 300 293 def release(self): 294 """ 295 Release any resources associated with the kernel. 296 """ 301 297 pass -
sasmodels/kernelpy.py
r4c2c535 reafc9fa 1 """ 2 Python driver for python kernels 3 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 and 6 summing the results. The interface to :class:`PyModel` matches those for 7 :class:`kernelcl.GpuModel` and :class:`kerneldll.DllModel`. 8 """ 1 9 import numpy as np 2 10 from numpy import pi, cos … … 5 13 6 14 class PyModel(object): 15 """ 16 Wrapper for pure python models. 17 """ 7 18 def __init__(self, info): 8 19 self.info = info 9 20 10 def __call__(self, q_input): 11 kernel = self.info['Iqxy'] if q_input.is_2D else self.info['Iq'] 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'] 12 24 return PyKernel(kernel, self.info, q_input) 13 25 14 # pylint: disable=no-self-use15 def make_input(self, q_vectors):16 return PyInput(q_vectors, dtype=F64)17 18 26 def release(self): 27 """ 28 Free resources associated with the model. 29 """ 19 30 pass 20 31 … … 41 52 self.nq = q_vectors[0].size 42 53 self.dtype = dtype 43 self.is_2 D= (len(q_vectors) == 2)54 self.is_2d = (len(q_vectors) == 2) 44 55 self.q_vectors = [np.ascontiguousarray(q, self.dtype) for q in q_vectors] 45 56 self.q_pointers = [q.ctypes.data for q in self.q_vectors] 46 57 47 58 def release(self): 59 """ 60 Free resources associated with the model inputs. 61 """ 48 62 self.q_vectors = [] 49 63 … … 71 85 self.q_input = q_input 72 86 self.res = np.empty(q_input.nq, q_input.dtype) 73 dim = '2d' if q_input.is_2 Delse '1d'87 dim = '2d' if q_input.is_2d else '1d' 74 88 # Loop over q unless user promises that the kernel is vectorized by 75 89 # taggining it with vectorized=True … … 77 91 if dim == '2d': 78 92 def vector_kernel(qx, qy, *args): 93 """ 94 Vectorized 2D kernel. 95 """ 79 96 return np.array([kernel(qxi, qyi, *args) 80 97 for qxi, qyi in zip(qx, qy)]) 81 98 else: 82 99 def vector_kernel(q, *args): 100 """ 101 Vectorized 1D kernel. 102 """ 83 103 return np.array([kernel(qi, *args) 84 104 for qi in q]) … … 122 142 123 143 def release(self): 144 """ 145 Free resources associated with the kernel. 146 """ 124 147 self.q_input = None 125 148 -
sasmodels/model_test.py
r9404dd3 r5c962df 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_function 45 46 46 47 import sys … … 55 56 56 57 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 of 62 *["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 """ 57 67 58 68 ModelTestCase = _hide_model_case_from_nosetests() … … 75 85 # don't try to call cl kernel since it will not be 76 86 # available in some environmentes. 77 is_py = callable(getattr(model_definition, 'Iq', None))87 is_py = callable(getattr(model_definition, 'Iq', None)) 78 88 79 89 if is_py: # kernel implemented in python … … 111 121 def _hide_model_case_from_nosetests(): 112 122 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 model 127 functions, then runs the list of tests at the bottom of the model 128 description file. 129 """ 113 130 def __init__(self, test_name, definition, test_method_name, 114 131 platform, dtype): … … 123 140 def _runTest(self): 124 141 smoke_tests = [ 125 [{}, 0.1,None],126 [{}, (0.1,0.1),None],127 [{}, 'ER',None],128 [{}, 'VR',None],142 [{}, 0.1, None], 143 [{}, (0.1, 0.1), None], 144 [{}, 'ER', None], 145 [{}, 'VR', None], 129 146 ] 130 147 … … 163 180 actual = [call_VR(model.info, pars)] 164 181 elif isinstance(x[0], tuple): 165 Qx, Qy = zip(*x)182 Qx, Qy = zip(*x) 166 183 q_vectors = [np.array(Qx), np.array(Qy)] 167 184 kernel = make_kernel(model, q_vectors) … … 179 196 # smoke test --- make sure it runs and produces a value 180 197 self.assertTrue(np.isfinite(actual_yi), 181 'invalid f(%s): %s' % (xi, actual_yi))198 'invalid f(%s): %s' % (xi, actual_yi)) 182 199 else: 183 200 err = abs(yi - actual_yi) 184 201 nrm = abs(yi) 185 202 self.assertLess(err * 10**5, nrm, 186 'f(%s); expected:%s; actual:%s' % (xi, yi, actual_yi)) 203 'f(%s); expected:%s; actual:%s' 204 % (xi, yi, actual_yi)) 187 205 188 206 return ModelTestCase … … 237 255 Run "nosetests sasmodels" on the command line to invoke it. 238 256 """ 239 tests = make_suite(['opencl', 'dll'],['all'])257 tests = make_suite(['opencl', 'dll'], ['all']) 240 258 for test_i in tests: 241 259 yield test_i._runTest -
sasmodels/resolution.py
r190fc2b r5925e90 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( self.q_calc,85 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)) 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 """ 472 479 from sasmodels import core 473 480 kernel = core.make_kernel(form, [q]) … … 478 485 479 486 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 """ 480 492 from numpy import exp, pi 481 493 return exp(-0.5*((q-q0)/dq)**2)/(sqrt(2*pi)*dq) … … 559 571 560 572 class ResolutionTest(unittest.TestCase): 573 """ 574 Test the resolution calculations. 575 """ 561 576 562 577 def setUp(self): … … 668 683 669 684 class IgorComparisonTest(unittest.TestCase): 685 """ 686 Test resolution calculations against those returned by Igor. 687 """ 670 688 671 689 def setUp(self): … … 675 693 self.model = core.load_model(sphere, dtype='double') 676 694 677 def Iq_sphere(self, pars, resolution):695 def _eval_sphere(self, pars, resolution): 678 696 from sasmodels import core 679 697 kernel = core.make_kernel(self.model, [resolution.q_calc]) … … 683 701 return result 684 702 685 def compare(self, q, output, answer, tolerance):703 def _compare(self, q, output, answer, tolerance): 686 704 #err = (output - answer)/answer 687 705 #idx = abs(err) >= tolerance … … 700 718 q, width, answer, _ = data 701 719 resolution = Perfect1D(q) 702 output = self. Iq_sphere(pars, resolution)703 self. compare(q, output, answer, 1e-6)720 output = self._eval_sphere(pars, resolution) 721 self._compare(q, output, answer, 1e-6) 704 722 705 723 def test_pinhole(self): … … 713 731 q, q_width, answer = data 714 732 resolution = Pinhole1D(q, q_width) 715 output = self. Iq_sphere(pars, resolution)733 output = self._eval_sphere(pars, resolution) 716 734 # TODO: relative error should be lower 717 self. compare(q, output, answer, 3e-4)735 self._compare(q, output, answer, 3e-4) 718 736 719 737 def test_pinhole_romberg(self): … … 736 754 q_calc, tol = None, 0.01 737 755 resolution = Pinhole1D(q, q_width, q_calc=q_calc) 738 output = self. Iq_sphere(pars, resolution)756 output = self._eval_sphere(pars, resolution) 739 757 if 0: # debug plot 740 758 import matplotlib.pyplot as plt 741 759 resolution = Perfect1D(q) 742 source = self. Iq_sphere(pars, resolution)760 source = self._eval_sphere(pars, resolution) 743 761 plt.loglog(q, source, '.') 744 762 plt.loglog(q, answer, '-', hold=True) 745 763 plt.loglog(q, output, '-', hold=True) 746 764 plt.show() 747 self. compare(q, output, answer, tol)765 self._compare(q, output, answer, tol) 748 766 749 767 def test_slit(self): … … 757 775 q, delta_qv, _, answer = data 758 776 resolution = Slit1D(q, width=delta_qv, height=0) 759 output = self. Iq_sphere(pars, resolution)777 output = self._eval_sphere(pars, resolution) 760 778 # TODO: eliminate Igor test since it is too inaccurate to be useful. 761 779 # This means we can eliminate the test data as well, and instead 762 780 # use a generated q vector. 763 self. compare(q, output, answer, 0.5)781 self._compare(q, output, answer, 0.5) 764 782 765 783 def test_slit_romberg(self): … … 777 795 delta_qv[0], 0.) 778 796 resolution = Slit1D(q, width=delta_qv, height=0, q_calc=q_calc) 779 output = self. Iq_sphere(pars, resolution)797 output = self._eval_sphere(pars, resolution) 780 798 # TODO: relative error should be lower 781 self. compare(q, output, answer, 0.025)799 self._compare(q, output, answer, 0.025) 782 800 783 801 def test_ellipsoid(self): … … 799 817 # TODO: 10% is too much error; use better algorithm 800 818 #print(np.max(abs(answer-output)/answer)) 801 self. compare(q, output, answer, 0.1)819 self._compare(q, output, answer, 0.1) 802 820 803 821 #TODO: can sas q spacing be too sparse for the resolution calculation? … … 813 831 q, q_width, answer = data[:, ::20] # Take every nth point 814 832 resolution = Pinhole1D(q, q_width) 815 output = self. Iq_sphere(pars, resolution)816 self. compare(q, output, answer, 1e-6)833 output = self._eval_sphere(pars, resolution) 834 self._compare(q, output, answer, 1e-6) 817 835 818 836 … … 1067 1085 1068 1086 def demo_pinhole_1d(): 1087 """ 1088 Show example of pinhole smearing. 1089 """ 1069 1090 q = np.logspace(-4, np.log10(0.2), 400) 1070 1091 q_width = 0.1*q … … 1073 1094 1074 1095 def demo_slit_1d(): 1096 """ 1097 Show example of slit smearing. 1098 """ 1075 1099 q = np.logspace(-4, np.log10(0.2), 100) 1076 1100 w = h = 0. … … 1083 1107 1084 1108 def demo(): 1109 """ 1110 Run the resolution demos. 1111 """ 1085 1112 import matplotlib.pyplot as plt 1086 1113 plt.subplot(121) -
sasmodels/resolution2d.py
r841753c r823e620 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 147 qy_res = (-(dqx*cos(dphi) + q_r) * sin(-q_phi) +148 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 + 151 qy_res = qy + 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 = np.average(theory, axis=0, weights=self.q_calc_weights)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
r9404dd3 reafc9fa 283 283 """ 284 284 q_vectors = [np.asarray(q) for q in args] 285 fn = self._model( self._model.make_input(q_vectors))285 fn = self._model(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
r3c56da87 r5c962df 22 22 23 23 def get_pars(self): 24 """ 25 Return the parameters to the disperser as a dictionary. 26 """ 24 27 pars = {'type': self.type} 25 28 pars.update(self.__dict__) … … 28 31 # pylint: disable=no-self-use 29 32 def set_weights(self, values, weights): 33 """ 34 Set the weights on the disperser if it is :class:`ArrayDispersion`. 35 """ 30 36 raise RuntimeError("set_weights is only available for ArrayDispersion") 31 37 … … 36 42 *center* is the center of the distribution 37 43 38 *lb*, *ub* are the min and max allowed values44 *lb*, *ub* are the min and max allowed values 39 45 40 46 *relative* is True if the distribution width is proportional to the … … 63 69 64 70 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 """ 65 78 type = "gaussian" 66 79 default = dict(npts=35, width=0, nsigmas=3) … … 72 85 73 86 class RectangleDispersion(Dispersion): 87 r""" 88 Uniform dispersion, with width $\sqrt{3}\sigma$. 89 90 .. math:: 91 92 w = 1 93 """ 74 94 type = "rectangle" 75 95 default = dict(npts=35, width=0, nsigmas=1.70325) … … 81 101 82 102 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 """ 83 110 type = "lognormal" 84 111 default = dict(npts=80, width=0, nsigmas=8) 85 112 def _weights(self, center, sigma, lb, ub): 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)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) 88 115 return x, px 89 116 90 117 91 118 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 as 129 130 .. math:: 131 132 w = \exp\left(z \ln z + (z-1)\ln R - Rz - \ln c - \ln \Gamma(z) \right) 133 """ 92 134 type = "schulz" 93 135 default = dict(npts=80, width=0, nsigmas=8) 94 136 def _weights(self, center, sigma, lb, ub): 95 x = self._linspace(center, sigma, max(lb, 1e-8), max(ub,1e-8))96 R = x/center137 x = self._linspace(center, sigma, max(lb, 1e-8), max(ub, 1e-8)) 138 R = x/center 97 139 z = (center/sigma)**2 98 140 arg = z*np.log(z) + (z-1)*np.log(R) - R*z - np.log(center) - gammaln(z) … … 102 144 103 145 class ArrayDispersion(Dispersion): 146 r""" 147 Empirical dispersion curve. 148 149 Use :meth:`set_weights` to set $w = f(x)$. 150 """ 104 151 type = "array" 105 152 default = dict(npts=35, width=0, nsigmas=1) … … 110 157 111 158 def set_weights(self, values, weights): 159 """ 160 Set the weights for the given x values. 161 """ 112 162 self.values = np.ascontiguousarray(values, 'd') 113 163 self.weights = np.ascontiguousarray(weights, 'd') … … 117 167 # TODO: interpolate into the array dispersion using npts 118 168 x = center + self.values*sigma 119 idx = (x >=lb)&(x<=ub)169 idx = (x >= lb) & (x <= ub) 120 170 x = x[idx] 121 171 px = self.weights[idx] … … 124 174 125 175 # dispersion name -> disperser lookup table. 126 models = dict((d.type, d) for d in (176 models = dict((d.type, d) for d in ( 127 177 GaussianDispersion, RectangleDispersion, 128 178 ArrayDispersion, SchulzDispersion, LogNormalDispersion … … 149 199 of the parameter, and false if it is an absolute width. 150 200 151 Returns *(value, weight)*, where *value* and *weight* are vectors.201 Returns *(value, weight)*, where *value* and *weight* are vectors. 152 202 """ 153 203 cls = models[disperser] 154 204 obj = cls(n, width, nsigmas) 155 v, w = obj.get_weights(value, limits[0], limits[1], relative)156 return v, w205 v, w = obj.get_weights(value, limits[0], limits[1], relative) 206 return v, w 157 207 158 208 # Hack to allow sasview dispersion objects to interoperate with sasmodels 159 dispersers = dict((v.__name__, k) for k,v in models.items())209 dispersers = dict((v.__name__, k) for k, v in models.items()) 160 210 dispersers['DispersionModel'] = RectangleDispersion.type 161 211 -
sasmodels/models/lib/wrc_cyl.c
rf94d8a2 r504abee 297 297 } 298 298 299 299 static double 300 Sdebye_kernel(double arg) 301 { 302 // ORIGINAL 303 double result = 2.0*(exp(-arg) + arg -1.0)/(pow((arg),2)); 304 305 // CONVERSION 1 from http://herbie.uwplse.org/ 306 // 307 // exhibits discontinuity - needs more investigation 308 //double a1 = 1.0/6.0; 309 //double a2 = 1.0/72.0; 310 //double a3 = 1.0/24.0; 311 //double result = pow((1.0 - a1*arg - (a2+a3)*arg*arg), 2); 312 313 return result; 314 } 300 315 static double 301 316 Sdebye(double q, double L, double b) 302 317 { 303 return 2.0*(exp(-u_WR(q,L,b)) + u_WR(q,L,b) -1.0)/(pow((u_WR(q,L,b)),2)); 318 double arg = u_WR(q,L,b); 319 return Sdebye_kernel(arg); 304 320 } 305 321 … … 308 324 Sdebye1(double q, double L, double b) 309 325 { 310 return 2.0*(exp(-u1(q,L,b)) + u1(q,L,b) -1.0)/( pow((u1(q,L,b)),2.0) ); 326 double arg = u1(q,L,b); 327 return Sdebye_kernel(arg); 328 311 329 } 312 330
Note: See TracChangeset
for help on using the changeset viewer.