Changeset dd7fc12 in sasmodels
- Timestamp:
- Apr 15, 2016 11:11:43 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:
- 3599d36
- Parents:
- b151003
- Location:
- sasmodels
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
sasmodels/compare.py
rb151003 rdd7fc12 41 41 from .direct_model import DirectModel 42 42 from .convert import revert_name, revert_pars, constrain_new_to_old 43 44 try: 45 from typing import Optional, Dict, Any, Callable, Tuple 46 except: 47 pass 48 else: 49 from .modelinfo import ModelInfo, Parameter, ParameterSet 50 from .data import Data 51 Calculator = Callable[[float, ...], np.ndarray] 43 52 44 53 USAGE = """ … … 97 106 kerneldll.ALLOW_SINGLE_PRECISION_DLLS = True 98 107 99 MODELS = core.list_models()100 101 108 # CRUFT python 2.6 102 109 if not hasattr(datetime.timedelta, 'total_seconds'): … … 160 167 ... print(randint(0,1000000,3)) 161 168 ... raise Exception() 162 ... except :169 ... except Exception: 163 170 ... print("Exception raised") 164 171 ... print(randint(0,1000000)) … … 169 176 """ 170 177 def __init__(self, seed=None): 178 # type: (Optional[int]) -> None 171 179 self._state = np.random.get_state() 172 180 np.random.seed(seed) 173 181 174 182 def __enter__(self): 175 return None 176 177 def __exit__(self, *args): 183 # type: () -> None 184 pass 185 186 def __exit__(self, type, value, traceback): 187 # type: (Any, BaseException, Any) -> None 188 # TODO: better typing for __exit__ method 178 189 np.random.set_state(self._state) 179 190 180 191 def tic(): 192 # type: () -> Callable[[], float] 181 193 """ 182 194 Timer function. … … 190 202 191 203 def set_beam_stop(data, radius, outer=None): 204 # type: (Data, float, float) -> None 192 205 """ 193 206 Add a beam stop of the given *radius*. If *outer*, make an annulus. 194 207 195 Note: this function does not use the sasview package208 Note: this function does not require sasview 196 209 """ 197 210 if hasattr(data, 'qx_data'): … … 207 220 208 221 def parameter_range(p, v): 222 # type: (str, float) -> Tuple[float, float] 209 223 """ 210 224 Choose a parameter range based on parameter name and initial value. … … 212 226 # process the polydispersity options 213 227 if p.endswith('_pd_n'): 214 return [0, 100]228 return 0., 100. 215 229 elif p.endswith('_pd_nsigma'): 216 return [0, 5]230 return 0., 5. 217 231 elif p.endswith('_pd_type'): 218 r eturn v232 raise ValueError("Cannot return a range for a string value") 219 233 elif any(s in p for s in ('theta', 'phi', 'psi')): 220 234 # orientation in [-180,180], orientation pd in [0,45] 221 235 if p.endswith('_pd'): 222 return [0, 45]236 return 0., 45. 223 237 else: 224 return [-180, 180]238 return -180., 180. 225 239 elif p.endswith('_pd'): 226 return [0, 1]240 return 0., 1. 227 241 elif 'sld' in p: 228 return [-0.5, 10]242 return -0.5, 10. 229 243 elif p == 'background': 230 return [0, 10]244 return 0., 10. 231 245 elif p == 'scale': 232 return [0, 1e3]233 elif v < 0 :234 return [2*v, -2*v]246 return 0., 1.e3 247 elif v < 0.: 248 return 2.*v, -2.*v 235 249 else: 236 return [0, (2*v if v > 0 else 1)]250 return 0., (2.*v if v > 0. else 1.) 237 251 238 252 239 253 def _randomize_one(model_info, p, v): 254 # type: (ModelInfo, str, float) -> float 255 # type: (ModelInfo, str, str) -> str 240 256 """ 241 257 Randomize a single parameter. … … 263 279 264 280 def randomize_pars(model_info, pars, seed=None): 281 # type: (ModelInfo, ParameterSet, int) -> ParameterSet 265 282 """ 266 283 Generate random values for all of the parameters. … … 273 290 with push_seed(seed): 274 291 # Note: the sort guarantees order `of calls to random number generator 275 pars = dict((p, _randomize_one(model_info, p, v))276 for p, v in sorted(pars.items()))277 return pars292 random_pars = dict((p, _randomize_one(model_info, p, v)) 293 for p, v in sorted(pars.items())) 294 return random_pars 278 295 279 296 def constrain_pars(model_info, pars): 297 # type: (ModelInfo, ParameterSet) -> None 280 298 """ 281 299 Restrict parameters to valid values. … … 284 302 which need to support within model constraints (cap radius more than 285 303 cylinder radius in this case). 304 305 Warning: this updates the *pars* dictionary in place. 286 306 """ 287 307 name = model_info.id … … 315 335 316 336 def parlist(model_info, pars, is2d): 337 # type: (ModelInfo, ParameterSet, bool) -> str 317 338 """ 318 339 Format the parameter list for printing. … … 326 347 n=int(pars.get(p.id+"_pd_n", 0)), 327 348 nsigma=pars.get(p.id+"_pd_nsgima", 3.), 328 type=pars.get(p.id+"_pd_type", 'gaussian')) 349 pdtype=pars.get(p.id+"_pd_type", 'gaussian'), 350 ) 329 351 lines.append(_format_par(p.name, **fields)) 330 352 return "\n".join(lines) … … 332 354 #return "\n".join("%s: %s"%(p, v) for p, v in sorted(pars.items())) 333 355 334 def _format_par(name, value=0., pd=0., n=0, nsigma=3., type='gaussian'): 356 def _format_par(name, value=0., pd=0., n=0, nsigma=3., pdtype='gaussian'): 357 # type: (str, float, float, int, float, str) -> str 335 358 line = "%s: %g"%(name, value) 336 359 if pd != 0. and n != 0: 337 360 line += " +/- %g (%d points in [-%g,%g] sigma %s)"\ 338 % (pd, n, nsigma, nsigma, type)361 % (pd, n, nsigma, nsigma, pdtype) 339 362 return line 340 363 341 364 def suppress_pd(pars): 365 # type: (ParameterSet) -> ParameterSet 342 366 """ 343 367 Suppress theta_pd for now until the normalization is resolved. … … 352 376 353 377 def eval_sasview(model_info, data): 378 # type: (Modelinfo, Data) -> Calculator 354 379 """ 355 380 Return a model calculator using the pre-4.0 SasView models. … … 359 384 import sas 360 385 from sas.models.qsmearing import smear_selection 386 import sas.models 361 387 362 388 def get_model(name): 389 # type: (str) -> "sas.models.BaseComponent" 363 390 #print("new",sorted(_pars.items())) 364 sas =__import__('sas.models.' + name)391 __import__('sas.models.' + name) 365 392 ModelClass = getattr(getattr(sas.models, name, None), name, None) 366 393 if ModelClass is None: … … 400 427 401 428 def calculator(**pars): 429 # type: (float, ...) -> np.ndarray 402 430 """ 403 431 Sasview calculator for model. … … 406 434 pars = revert_pars(model_info, pars) 407 435 for k, v in pars.items(): 408 parts= k.split('.') # polydispersity components409 if len( parts) == 2:410 model.dispersion[ parts[0]][parts[1]] = v436 name_attr = k.split('.') # polydispersity components 437 if len(name_attr) == 2: 438 model.dispersion[name_attr[0]][name_attr[1]] = v 411 439 else: 412 440 model.setParam(k, v) … … 428 456 } 429 457 def eval_opencl(model_info, data, dtype='single', cutoff=0.): 458 # type: (ModelInfo, Data, str, float) -> Calculator 430 459 """ 431 460 Return a model calculator using the OpenCL calculation engine. … … 442 471 443 472 def eval_ctypes(model_info, data, dtype='double', cutoff=0.): 473 # type: (ModelInfo, Data, str, float) -> Calculator 444 474 """ 445 475 Return a model calculator using the DLL calculation engine. 446 476 """ 447 if dtype == 'quad':448 dtype = 'longdouble'449 477 model = core.build_model(model_info, dtype=dtype, platform="dll") 450 478 calculator = DirectModel(data, model, cutoff=cutoff) … … 453 481 454 482 def time_calculation(calculator, pars, Nevals=1): 483 # type: (Calculator, ParameterSet, int) -> Tuple[np.ndarray, float] 455 484 """ 456 485 Compute the average calculation time over N evaluations. … … 461 490 # initialize the code so time is more accurate 462 491 if Nevals > 1: 463 value =calculator(**suppress_pd(pars))492 calculator(**suppress_pd(pars)) 464 493 toc = tic() 465 for _ in range(max(Nevals, 1)): # make sure there is at least one eval 494 # make sure there is at least one eval 495 value = calculator(**pars) 496 for _ in range(Nevals-1): 466 497 value = calculator(**pars) 467 498 average_time = toc()*1000./Nevals … … 469 500 470 501 def make_data(opts): 502 # type: (Dict[str, Any]) -> Tuple[Data, np.ndarray] 471 503 """ 472 504 Generate an empty dataset, used with the model to set Q points … … 478 510 qmax, nq, res = opts['qmax'], opts['nq'], opts['res'] 479 511 if opts['is2d']: 480 data = empty_data2D(np.linspace(-qmax, qmax, nq), resolution=res) 512 q = np.linspace(-qmax, qmax, nq) # type: np.ndarray 513 data = empty_data2D(q, resolution=res) 481 514 data.accuracy = opts['accuracy'] 482 515 set_beam_stop(data, 0.0004) … … 495 528 496 529 def make_engine(model_info, data, dtype, cutoff): 530 # type: (ModelInfo, Data, str, float) -> Calculator 497 531 """ 498 532 Generate the appropriate calculation engine for the given datatype. … … 509 543 510 544 def _show_invalid(data, theory): 545 # type: (Data, np.ma.ndarray) -> None 546 """ 547 Display a list of the non-finite values in theory. 548 """ 511 549 if not theory.mask.any(): 512 550 return … … 514 552 if hasattr(data, 'x'): 515 553 bad = zip(data.x[theory.mask], theory[theory.mask]) 516 print(" *** ", ", ".join("I(%g)=%g"%(x, y) for x, y in bad))554 print(" *** ", ", ".join("I(%g)=%g"%(x, y) for x, y in bad)) 517 555 518 556 519 557 def compare(opts, limits=None): 558 # type: (Dict[str, Any], Optional[Tuple[float, float]]) -> Tuple[float, float] 520 559 """ 521 560 Preform a comparison using options from the command line. … … 532 571 data = opts['data'] 533 572 573 # silence the linter 574 base = opts['engines'][0] if Nbase else None 575 comp = opts['engines'][1] if Ncomp else None 576 base_time = comp_time = None 577 base_value = comp_value = resid = relerr = None 578 534 579 # Base calculation 535 580 if Nbase > 0: 536 base = opts['engines'][0]537 581 try: 538 base_ value, base_time = time_calculation(base, pars, Nbase)539 base_value = np.ma.masked_invalid(base_ value)582 base_raw, base_time = time_calculation(base, pars, Nbase) 583 base_value = np.ma.masked_invalid(base_raw) 540 584 print("%s t=%.2f ms, intensity=%.0f" 541 585 % (base.engine, base_time, base_value.sum())) … … 547 591 # Comparison calculation 548 592 if Ncomp > 0: 549 comp = opts['engines'][1]550 593 try: 551 comp_ value, comp_time = time_calculation(comp, pars, Ncomp)552 comp_value = np.ma.masked_invalid(comp_ value)594 comp_raw, comp_time = time_calculation(comp, pars, Ncomp) 595 comp_value = np.ma.masked_invalid(comp_raw) 553 596 print("%s t=%.2f ms, intensity=%.0f" 554 597 % (comp.engine, comp_time, comp_value.sum())) … … 625 668 626 669 def _print_stats(label, err): 670 # type: (str, np.ma.ndarray) -> None 671 # work with trimmed data, not the full set 627 672 sorted_err = np.sort(abs(err.compressed())) 628 p50 = int((len( err)-1)*0.50)629 p98 = int((len( err)-1)*0.98)673 p50 = int((len(sorted_err)-1)*0.50) 674 p98 = int((len(sorted_err)-1)*0.98) 630 675 data = [ 631 676 "max:%.3e"%sorted_err[-1], 632 677 "median:%.3e"%sorted_err[p50], 633 678 "98%%:%.3e"%sorted_err[p98], 634 "rms:%.3e"%np.sqrt(np.mean( err**2)),635 "zero-offset:%+.3e"%np.mean( err),679 "rms:%.3e"%np.sqrt(np.mean(sorted_err**2)), 680 "zero-offset:%+.3e"%np.mean(sorted_err), 636 681 ] 637 682 print(label+" "+" ".join(data)) … … 662 707 663 708 def columnize(L, indent="", width=79): 709 # type: (List[str], str, int) -> str 664 710 """ 665 711 Format a list of strings into columns. … … 679 725 680 726 def get_pars(model_info, use_demo=False): 727 # type: (ModelInfo, bool) -> ParameterSet 681 728 """ 682 729 Extract demo parameters from the model definition. … … 704 751 705 752 def parse_opts(): 753 # type: () -> Dict[str, Any] 706 754 """ 707 755 Parse command line options. … … 757 805 'explore' : False, 758 806 'use_demo' : True, 807 'zero' : False, 759 808 } 760 809 engines = [] … … 777 826 elif arg.startswith('-cutoff='): opts['cutoff'] = float(arg[8:]) 778 827 elif arg.startswith('-random='): opts['seed'] = int(arg[8:]) 779 elif arg == '-random': opts['seed'] = np.random.randint(1 e6)828 elif arg == '-random': opts['seed'] = np.random.randint(1000000) 780 829 elif arg == '-preset': opts['seed'] = -1 781 830 elif arg == '-mono': opts['mono'] = True … … 874 923 875 924 def explore(opts): 925 # type: (Dict[str, Any]) -> None 876 926 """ 877 927 Explore the model using the Bumps GUI. … … 900 950 """ 901 951 def __init__(self, opts): 952 # type: (Dict[str, Any]) -> None 902 953 from bumps.cli import config_matplotlib # type: ignore 903 954 from . import bumps_model … … 923 974 924 975 def numpoints(self): 976 # type: () -> int 925 977 """ 926 978 Return the number of points. … … 929 981 930 982 def parameters(self): 983 # type: () -> Any # Dict/List hierarchy of parameters 931 984 """ 932 985 Return a dictionary of parameters. … … 935 988 936 989 def nllf(self): 990 # type: () -> float 937 991 """ 938 992 Return cost. … … 942 996 943 997 def plot(self, view='log'): 998 # type: (str) -> None 944 999 """ 945 1000 Plot the data and residuals. … … 951 1006 if self.limits is None: 952 1007 vmin, vmax = limits 953 vmax = 1.3*vmax 954 vmin = vmax*1e-7 955 self.limits = vmin, vmax 1008 self.limits = vmax*1e-7, 1.3*vmax 956 1009 957 1010 958 1011 def main(): 1012 # type: () -> None 959 1013 """ 960 1014 Main program. -
sasmodels/core.py
rfa5fd8d rdd7fc12 28 28 try: 29 29 from typing import List, Union, Optional, Any 30 DType = Union[None, str, np.dtype]31 30 from .kernel import KernelModel 31 from .modelinfo import ModelInfo 32 32 except ImportError: 33 33 pass … … 56 56 return available_models 57 57 58 def isstr(s):59 # type: (Any) -> bool60 """61 Return True if *s* is a string-like object.62 """63 try: s + ''64 except Exception: return False65 return True66 67 58 def load_model(model_name, dtype=None, platform='ocl'): 68 # type: (str, DType, str) -> KernelModel59 # type: (str, str, str) -> KernelModel 69 60 """ 70 61 Load model info and build model. … … 102 93 103 94 def build_model(model_info, dtype=None, platform="ocl"): 104 # type: (modelinfo.ModelInfo, np.dtype, str) -> KernelModel95 # type: (modelinfo.ModelInfo, str, str) -> KernelModel 105 96 """ 106 97 Prepare the model for the default execution platform. … … 113 104 114 105 *dtype* indicates whether the model should use single or double precision 115 for the calculation. Any valid numpy single or double precision identifier 116 is valid, such as 'single', 'f', 'f32', or np.float32 for single, or 117 'double', 'd', 'f64' and np.float64 for double. If *None*, then use 118 'single' unless the model defines single=False. 106 for the calculation. Choices are 'single', 'double', 'quad', 'half', 107 or 'fast'. If *dtype* ends with '!', then force the use of the DLL rather 108 than OpenCL for the calculation. 119 109 120 110 *platform* should be "dll" to force the dll to be used for C models, … … 147 137 # source = open(model_info.name+'.cl','r').read() 148 138 source = generate.make_source(model_info) 149 if dtype is None: 150 dtype = generate.F32 if model_info.single else generate.F64 139 numpy_dtype, fast = parse_dtype(model_info, dtype) 151 140 if (platform == "dll" 141 or dtype.endswith('!') 152 142 or not HAVE_OPENCL 153 or not kernelcl.environment().has_type( dtype)):154 return kerneldll.load_dll(source, model_info, dtype)143 or not kernelcl.environment().has_type(numpy_dtype)): 144 return kerneldll.load_dll(source, model_info, numpy_dtype) 155 145 else: 156 return kernelcl.GpuModel(source, model_info, dtype)146 return kernelcl.GpuModel(source, model_info, numpy_dtype, fast=fast) 157 147 158 148 def precompile_dll(model_name, dtype="double"): 159 # type: (str, DType) -> Optional[str]149 # type: (str, str) -> Optional[str] 160 150 """ 161 151 Precompile the dll for a model. … … 172 162 """ 173 163 model_info = load_model_info(model_name) 164 numpy_dtype, fast = parse_dtype(model_info, dtype) 174 165 source = generate.make_source(model_info) 175 return kerneldll.make_dll(source, model_info, dtype=dtype) if source else None 166 return kerneldll.make_dll(source, model_info, dtype=numpy_dtype) if source else None 167 168 def parse_dtype(model_info, dtype): 169 # type: (ModelInfo, str) -> Tuple[np.dtype, bool] 170 """ 171 Interpret dtype string, returning np.dtype and fast flag. 172 173 Possible types include 'half', 'single', 'double' and 'quad'. If the 174 type is 'fast', then this is equivalent to dtype 'single' with the 175 fast flag set to True. 176 """ 177 # Fill in default type based on required precision in the model 178 if dtype is None: 179 dtype = 'single' if model_info.single else 'double' 180 181 # Ignore platform indicator 182 if dtype.endswith('!'): 183 dtype = dtype[:-1] 184 185 # Convert type string to type 186 if dtype == 'quad': 187 return generate.F128, False 188 elif dtype == 'half': 189 return generate.F16, False 190 elif dtype == 'fast': 191 return generate.F32, True 192 else: 193 return np.dtype(dtype), False 194 -
sasmodels/kernelcl.py
ra5b8477 rdd7fc12 103 103 ENV = None 104 104 def environment(): 105 # type: () -> "GpuEnvironment" 105 106 """ 106 107 Returns a singleton :class:`GpuEnvironment`. … … 114 115 115 116 def has_type(device, dtype): 117 # type: (cl.Device, np.dtype) -> bool 116 118 """ 117 119 Return true if device supports the requested precision. … … 127 129 128 130 def get_warp(kernel, queue): 131 # type: (cl.Kernel, cl.CommandQueue) -> int 129 132 """ 130 133 Return the size of an execution batch for *kernel* running on *queue*. … … 135 138 136 139 def _stretch_input(vector, dtype, extra=1e-3, boundary=32): 140 # type: (np.ndarray, np.dtype, float, int) -> np.ndarray 137 141 """ 138 142 Stretch an input vector to the correct boundary. … … 157 161 158 162 def compile_model(context, source, dtype, fast=False): 163 # type: (cl.Context, str, np.dtype, bool) -> cl.Program 159 164 """ 160 165 Build a model to run on the gpu. … … 192 197 """ 193 198 def __init__(self): 199 # type: () -> None 194 200 # find gpu context 195 201 #self.context = cl.create_some_context() … … 210 216 211 217 def has_type(self, dtype): 218 # type: (np.dtype) -> bool 212 219 """ 213 220 Return True if all devices support a given type. 214 221 """ 215 dtype = generate.F32 if dtype == 'fast' else np.dtype(dtype)216 222 return any(has_type(d, dtype) 217 223 for context in self.context … … 219 225 220 226 def get_queue(self, dtype): 227 # type: (np.dtype) -> cl.CommandQueue 221 228 """ 222 229 Return a command queue for the kernels of type dtype. … … 227 234 228 235 def get_context(self, dtype): 236 # type: (np.dtype) -> cl.Context 229 237 """ 230 238 Return a OpenCL context for the kernels of type dtype. … … 235 243 236 244 def _create_some_context(self): 245 # type: () -> cl.Context 237 246 """ 238 247 Protected call to cl.create_some_context without interactivity. Use … … 248 257 249 258 def compile_program(self, name, source, dtype, fast=False): 259 # type: (str, str, np.dtype, bool) -> cl.Program 250 260 """ 251 261 Compile the program for the device in the given context. … … 261 271 262 272 def release_program(self, name): 273 # type: (str) -> None 263 274 """ 264 275 Free memory associated with the program on the device. … … 269 280 270 281 def _get_default_context(): 282 # type: () -> cl.Context 271 283 """ 272 284 Get an OpenCL context, preferring GPU over CPU, and preferring Intel … … 334 346 that the compiler is allowed to take shortcuts. 335 347 """ 336 def __init__(self, source, model_info, dtype=generate.F32): 348 def __init__(self, source, model_info, dtype=generate.F32, fast=False): 349 # type: (str, ModelInfo, np.dtype, bool) -> None 337 350 self.info = model_info 338 351 self.source = source 339 self.dtype = generate.F32 if dtype == 'fast' else np.dtype(dtype)340 self.fast = (dtype == 'fast')352 self.dtype = dtype 353 self.fast = fast 341 354 self.program = None # delay program creation 342 355 343 356 def __getstate__(self): 357 # type: () -> Tuple[ModelInfo, str, np.dtype, bool] 344 358 return self.info, self.source, self.dtype, self.fast 345 359 346 360 def __setstate__(self, state): 361 # type: (Tuple[ModelInfo, str, np.dtype, bool]) -> None 347 362 self.info, self.source, self.dtype, self.fast = state 348 363 self.program = None 349 364 350 365 def make_kernel(self, q_vectors): 366 # type: (List[np.ndarray]) -> "GpuKernel" 351 367 if self.program is None: 352 368 compiler = environment().compile_program … … 356 372 kernel_name = generate.kernel_name(self.info, is_2d) 357 373 kernel = getattr(self.program, kernel_name) 358 return GpuKernel(kernel, self.info, q_vectors , self.dtype)374 return GpuKernel(kernel, self.info, q_vectors) 359 375 360 376 def release(self): 377 # type: () -> None 361 378 """ 362 379 Free the resources associated with the model. … … 367 384 368 385 def __del__(self): 386 # type: () -> None 369 387 self.release() 370 388 … … 390 408 """ 391 409 def __init__(self, q_vectors, dtype=generate.F32): 410 # type: (List[np.ndarray], np.dtype) -> None 392 411 # TODO: do we ever need double precision q? 393 412 env = environment() … … 419 438 420 439 def release(self): 440 # type: () -> None 421 441 """ 422 442 Free the memory. … … 427 447 428 448 def __del__(self): 449 # type: () -> None 429 450 self.release() 430 451 … … 450 471 """ 451 472 def __init__(self, kernel, model_info, q_vectors): 452 # type: ( KernelModel, ModelInfo, List[np.ndarray]) -> None473 # type: (cl.Kernel, ModelInfo, List[np.ndarray]) -> None 453 474 max_pd = model_info.parameters.max_pd 454 475 npars = len(model_info.parameters.kernel_parameters)-2 … … 505 526 506 527 def release(self): 528 # type: () -> None 507 529 """ 508 530 Release resources associated with the kernel. … … 513 535 514 536 def __del__(self): 537 # type: () -> None 515 538 self.release()
Note: See TracChangeset
for help on using the changeset viewer.