Changeset 17bbadd in sasmodels
- Timestamp:
- Mar 15, 2016 12:47:12 PM (9 years ago)
- Branches:
- master, core_shell_microgels, costrafo411, magnetic_model, release_v0.94, release_v0.95, ticket-1257-vesicle-product, ticket_1156, ticket_1265_superball, ticket_822_more_unit_tests
- Children:
- 754e27b
- Parents:
- 5ceb7d0
- Location:
- sasmodels
- Files:
-
- 1 added
- 13 edited
Legend:
- Unmodified
- Added
- Removed
-
sasmodels/compare.py
r6869ceb r17bbadd 38 38 from . import core 39 39 from . import kerneldll 40 from . import generate40 from . import product 41 41 from .data import plot_theory, empty_data1D, empty_data2D 42 42 from .direct_model import DirectModel 43 from .convert import revert_ model, constrain_new_to_old43 from .convert import revert_pars, constrain_new_to_old 44 44 45 45 USAGE = """ … … 264 264 return pars 265 265 266 def constrain_pars(model_ definition, pars):266 def constrain_pars(model_info, pars): 267 267 """ 268 268 Restrict parameters to valid values. … … 272 272 cylinder radius in this case). 273 273 """ 274 name = model_definition.name 274 name = model_info['id'] 275 # if it is a product model, then just look at the form factor since 276 # none of the structure factors need any constraints. 277 if '*' in name: 278 name = name.split('*')[0] 279 275 280 if name == 'capped_cylinder' and pars['cap_radius'] < pars['radius']: 276 281 pars['radius'], pars['cap_radius'] = pars['cap_radius'], pars['radius'] … … 340 345 return pars 341 346 342 def eval_sasview(model_ definition, data):347 def eval_sasview(model_info, data): 343 348 """ 344 349 Return a model calculator using the SasView fitting engine. … … 349 354 from sas.models.qsmearing import smear_selection 350 355 351 # convert model parameters from sasmodel form to sasview form 352 #print("old",sorted(pars.items())) 353 modelname, _ = revert_model(model_definition, {}) 354 #print("new",sorted(_pars.items())) 355 sas = __import__('sas.models.'+modelname) 356 ModelClass = getattr(getattr(sas.models, modelname, None), modelname, None) 357 if ModelClass is None: 358 raise ValueError("could not find model %r in sas.models"%modelname) 359 model = ModelClass() 356 def get_model(name): 357 #print("new",sorted(_pars.items())) 358 sas = __import__('sas.models.' + name) 359 ModelClass = getattr(getattr(sas.models, name, None), name, None) 360 if ModelClass is None: 361 raise ValueError("could not find model %r in sas.models"%name) 362 return ModelClass() 363 364 # grab the sasview model, or create it if it is a product model 365 if model_info['composition']: 366 composition_type, parts = model_info['composition'] 367 if composition_type == 'product': 368 from sas.models import MultiplicationModel 369 P, S = [get_model(p) for p in model_info['oldname']] 370 model = MultiplicationModel(P, S) 371 else: 372 raise ValueError("mixture models not handled yet") 373 else: 374 model = get_model(model_info['oldname']) 375 376 # build a smearer with which to call the model, if necessary 360 377 smearer = smear_selection(data, model=model) 361 362 378 if hasattr(data, 'qx_data'): 363 379 q = np.sqrt(data.qx_data**2 + data.qy_data**2) … … 382 398 """ 383 399 # paying for parameter conversion each time to keep life simple, if not fast 384 _, pars = revert_model(model_definition, pars)400 pars = revert_pars(model_info, pars) 385 401 for k, v in pars.items(): 386 402 parts = k.split('.') # polydispersity components … … 405 421 'longdouble': '128', 406 422 } 407 def eval_opencl(model_ definition, data, dtype='single', cutoff=0.):423 def eval_opencl(model_info, data, dtype='single', cutoff=0.): 408 424 """ 409 425 Return a model calculator using the OpenCL calculation engine. 410 426 """ 411 try: 412 model = core.load_model(model_definition, dtype=dtype, platform="ocl") 413 except Exception as exc: 414 print(exc) 415 print("... trying again with single precision") 416 dtype = 'single' 417 model = core.load_model(model_definition, dtype=dtype, platform="ocl") 427 def builder(model_info): 428 try: 429 return core.build_model(model_info, dtype=dtype, platform="ocl") 430 except Exception as exc: 431 print(exc) 432 print("... trying again with single precision") 433 dtype = 'single' 434 return core.build_model(model_info, dtype=dtype, platform="ocl") 435 if model_info['composition']: 436 composition_type, parts = model_info['composition'] 437 if composition_type == 'product': 438 P, S = [builder(p) for p in parts] 439 model = product.ProductModel(P, S) 440 else: 441 raise ValueError("mixture models not handled yet") 442 else: 443 model = builder(model_info) 418 444 calculator = DirectModel(data, model, cutoff=cutoff) 419 445 calculator.engine = "OCL%s"%DTYPE_MAP[dtype] 420 446 return calculator 421 447 422 def eval_ctypes(model_ definition, data, dtype='double', cutoff=0.):448 def eval_ctypes(model_info, data, dtype='double', cutoff=0.): 423 449 """ 424 450 Return a model calculator using the DLL calculation engine. … … 426 452 if dtype == 'quad': 427 453 dtype = 'longdouble' 428 model = core.load_model(model_definition, dtype=dtype, platform="dll") 454 def builder(model_info): 455 return core.build_model(model_info, dtype=dtype, platform="dll") 456 457 if model_info['composition']: 458 composition_type, parts = model_info['composition'] 459 if composition_type == 'product': 460 P, S = [builder(p) for p in parts] 461 model = product.ProductModel(P, S) 462 else: 463 raise ValueError("mixture models not handled yet") 464 else: 465 model = builder(model_info) 429 466 calculator = DirectModel(data, model, cutoff=cutoff) 430 467 calculator.engine = "OMP%s"%DTYPE_MAP[dtype] … … 470 507 return data, index 471 508 472 def make_engine(model_ definition, data, dtype, cutoff):509 def make_engine(model_info, data, dtype, cutoff): 473 510 """ 474 511 Generate the appropriate calculation engine for the given datatype. … … 478 515 """ 479 516 if dtype == 'sasview': 480 return eval_sasview(model_ definition, data)517 return eval_sasview(model_info, data) 481 518 elif dtype.endswith('!'): 482 return eval_ctypes(model_definition, data, dtype=dtype[:-1], 483 cutoff=cutoff) 484 else: 485 return eval_opencl(model_definition, data, dtype=dtype, 486 cutoff=cutoff) 519 return eval_ctypes(model_info, data, dtype=dtype[:-1], cutoff=cutoff) 520 else: 521 return eval_opencl(model_info, data, dtype=dtype, cutoff=cutoff) 487 522 488 523 def compare(opts, limits=None): … … 642 677 643 678 644 def get_demo_pars(model_ definition):679 def get_demo_pars(model_info): 645 680 """ 646 681 Extract demo parameters from the model definition. 647 682 """ 648 info = generate.make_info(model_definition)649 683 # Get the default values for the parameters 650 pars = dict((p[0], p[2]) for p in info['parameters'])684 pars = dict((p[0], p[2]) for p in model_info['parameters']) 651 685 652 686 # Fill in default values for the polydispersity parameters 653 for p in info['parameters']:687 for p in model_info['parameters']: 654 688 if p[4] in ('volume', 'orientation'): 655 689 pars[p[0]+'_pd'] = 0.0 … … 659 693 660 694 # Plug in values given in demo 661 pars.update( info['demo'])695 pars.update(model_info['demo']) 662 696 return pars 697 663 698 664 699 def parse_opts(): … … 679 714 print(columnize(MODELS, indent=" ")) 680 715 sys.exit(1) 681 682 name = args[0]683 try:684 model_definition = core.load_model_definition(name)685 except ImportError, exc:686 print(str(exc))687 print("Use one of:\n " + models)688 sys.exit(1)689 716 if len(args) > 3: 690 717 print("expected parameters: model N1 N2") 718 719 def load_model(name): 720 try: 721 model_info = core.load_model_info(name) 722 except ImportError, exc: 723 print(str(exc)) 724 print("Use one of:\n " + models) 725 sys.exit(1) 726 return model_info 727 728 name = args[0] 729 if '*' in name: 730 parts = [load_model(k) for k in name.split('*')] 731 model_info = product.make_product_info(*parts) 732 else: 733 model_info = load_model(name) 691 734 692 735 invalid = [o[1:] for o in flags … … 770 813 # Get demo parameters from model definition, or use default parameters 771 814 # if model does not define demo parameters 772 pars = get_demo_pars(model_ definition)815 pars = get_demo_pars(model_info) 773 816 774 817 # Fill in parameters given on the command line … … 791 834 pars = suppress_pd(pars) 792 835 pars.update(presets) # set value after random to control value 793 constrain_pars(model_ definition, pars)794 constrain_new_to_old(model_ definition, pars)836 constrain_pars(model_info, pars) 837 constrain_new_to_old(model_info, pars) 795 838 if opts['show_pars']: 796 839 print(str(parlist(pars))) … … 799 842 data, _ = make_data(opts) 800 843 if n1: 801 base = make_engine(model_ definition, data, engines[0], opts['cutoff'])844 base = make_engine(model_info, data, engines[0], opts['cutoff']) 802 845 else: 803 846 base = None 804 847 if n2: 805 comp = make_engine(model_ definition, data, engines[1], opts['cutoff'])848 comp = make_engine(model_info, data, engines[1], opts['cutoff']) 806 849 else: 807 850 comp = None … … 811 854 opts.update({ 812 855 'name' : name, 813 'def' : model_ definition,856 'def' : model_info, 814 857 'n1' : n1, 815 858 'n2' : n2, … … 854 897 config_matplotlib() 855 898 self.opts = opts 856 info = generate.make_info(opts['def'])857 pars, pd_types = bumps_model.create_parameters( info, **opts['pars'])899 model_info = opts['def'] 900 pars, pd_types = bumps_model.create_parameters(model_info, **opts['pars']) 858 901 if not opts['is2d']: 859 902 active = [base + ext 860 for base in info['partype']['pd-1d']903 for base in model_info['partype']['pd-1d'] 861 904 for ext in ['', '_pd', '_pd_n', '_pd_nsigma']] 862 active.extend( info['partype']['fixed-1d'])905 active.extend(model_info['partype']['fixed-1d']) 863 906 for k in active: 864 907 v = pars[k] -
sasmodels/compare_many.py
r4f2478e r17bbadd 101 101 102 102 is_2d = hasattr(data, 'qx_data') 103 model_ definition = core.load_model_definition(name)104 pars = get_demo_pars(model_ definition)103 model_info = core.load_model_info(name) 104 pars = get_demo_pars(model_info) 105 105 header = ('\n"Model","%s","Count","%d","Dimension","%s"' 106 106 % (name, N, "2D" if is_2d else "1D")) … … 109 109 110 110 if is_2d: 111 info = generate.make_info(model_definition) 112 partype = info['partype'] 111 partype = model_info['partype'] 113 112 if not partype['orientation'] and not partype['magnetic']: 114 113 print(',"1-D only"') … … 150 149 151 150 152 calc_base = make_engine(model_ definition, data, base, cutoff)153 calc_comp = make_engine(model_ definition, data, comp, cutoff)151 calc_base = make_engine(model_info, data, base, cutoff) 152 calc_comp = make_engine(model_info, data, comp, cutoff) 154 153 expected = max(PRECISION[base], PRECISION[comp]) 155 154 … … 161 160 seed = np.random.randint(1e6) 162 161 pars_i = randomize_pars(pars, seed) 163 constrain_pars(model_ definition, pars_i)164 constrain_new_to_old(model_ definition, pars_i)162 constrain_pars(model_info['id'], pars_i) 163 constrain_new_to_old(model_info['id'], pars_i) 165 164 if mono: 166 165 pars_i = suppress_pd(pars_i) -
sasmodels/convert.py
r0d0aee1 r17bbadd 4 4 import warnings 5 5 6 STRUCTURE_FACTORS = [ 7 'hardsphere', 8 'stickyhardsphere', 9 'squarewell', 10 'HayterMSAsq' 11 ] 6 12 # List of models which SasView versions don't contain the explicit 'scale' argument. 7 13 # When converting such a model, please update this list. 8 MODELS_WITHOUT_SCALE = [14 MODELS_WITHOUT_SCALE = STRUCTURE_FACTORS + [ 9 15 'teubner_strey', 10 16 'broad_peak', … … 15 21 'be_polyelectrolyte', 16 22 'correlation_length', 23 'fractal_core_shell' 17 24 'binary_hard_sphere', 18 'fractal_core_shell'19 25 ] 20 26 21 27 # List of models which SasView versions don't contain the explicit 'background' argument. 22 28 # When converting such a model, please update this list. 23 MODELS_WITHOUT_BACKGROUND = [29 MODELS_WITHOUT_BACKGROUND = STRUCTURE_FACTORS + [ 24 30 'guinier', 25 31 ] … … 52 58 new model definition end with sld. 53 59 """ 54 return dict((p, (v*1e6 if p.endswith('sld') else v*1e-15 if 'ndensity' in p else v)) 60 return dict((p, (v*1e6 if p.endswith('sld') 61 else v*1e-15 if 'ndensity' in p 62 else v)) 55 63 for p, v in pars.items()) 56 64 … … 70 78 new model definition end with sld. 71 79 """ 72 return dict((p, (v*1e-6 if p.endswith('sld') else v*1e15 if 'ndensity' in p else v)) 80 return dict((p, (v*1e-6 if p.endswith('sld') 81 else v*1e15 if 'ndensity' in p 82 else v)) 73 83 for p, v in pars.items()) 74 84 … … 109 119 return newpars 110 120 111 def revert_ model(model_definition, pars):121 def revert_pars(model_info, pars): 112 122 """ 113 123 Convert model from new style parameter names to old style. 114 124 """ 115 mapping = model_definition.oldpars 116 oldname = model_definition.oldname 125 mapping = model_info['oldpars'] 117 126 oldpars = _revert_pars(_unscale_sld(pars), mapping) 118 127 119 128 # Note: update compare.constrain_pars to match 120 name = model_ definition.name129 name = model_info['id'] 121 130 if name in MODELS_WITHOUT_SCALE: 122 131 if oldpars.pop('scale', 1.0) != 1.0: 123 132 warnings.warn("parameter scale not used in sasview %s"%name) 124 elif name in MODELS_WITHOUT_BACKGROUND:133 if name in MODELS_WITHOUT_BACKGROUND: 125 134 if oldpars.pop('background', 0.0) != 0.0: 126 135 warnings.warn("parameter background not used in sasview %s"%name) 127 elif getattr(model_definition, 'category', None) == 'structure-factor':128 if oldpars.pop('scale', 1.0) != 1.0:129 warnings.warn("parameter scale not used in sasview %s"%name)130 if oldpars.pop('background', 0.0) != 0.0:131 warnings.warn("parameter background not used in sasview %s"%name)132 elif name == 'pearl_necklace':133 _remove_pd(oldpars, 'num_pearls', name)134 _remove_pd(oldpars, 'thick_string', name)135 elif name == 'core_shell_parallelepiped':136 _remove_pd(oldpars, 'rimA', name)137 _remove_pd(oldpars, 'rimB', name)138 _remove_pd(oldpars, 'rimC', name)139 elif name == 'rpa':140 # convert scattering lengths from femtometers to centimeters141 for p in "La", "Lb", "Lc", "Ld":142 if p in oldpars: oldpars[p] *= 1e-13143 136 144 return oldname, oldpars 137 # If it is a product model P*S, then check the individual forms for special 138 # cases. Note: despite the structure factor alone not having scale or 139 # background, the product model does, so this is below the test for 140 # models without scale or background. 141 namelist = name.split('*') if '*' in name else [name] 142 for name in namelist: 143 if name == 'pearl_necklace': 144 _remove_pd(oldpars, 'num_pearls', name) 145 _remove_pd(oldpars, 'thick_string', name) 146 elif name == 'core_shell_parallelepiped': 147 _remove_pd(oldpars, 'rimA', name) 148 _remove_pd(oldpars, 'rimB', name) 149 _remove_pd(oldpars, 'rimC', name) 150 elif name == 'rpa': 151 # convert scattering lengths from femtometers to centimeters 152 for p in "La", "Lb", "Lc", "Ld": 153 if p in oldpars: oldpars[p] *= 1e-13 145 154 146 def constrain_new_to_old(model_definition, pars): 155 return oldpars 156 157 def constrain_new_to_old(model_info, pars): 147 158 """ 148 159 Restrict parameter values to those that will match sasview. 149 160 """ 161 name = model_info['id'] 150 162 # Note: update convert.revert_model to match 151 name = model_definition.name152 163 if name in MODELS_WITHOUT_SCALE: 153 164 pars['scale'] = 1 154 elif name in MODELS_WITHOUT_BACKGROUND:165 if name in MODELS_WITHOUT_BACKGROUND: 155 166 pars['background'] = 0 156 elif name == 'pearl_necklace':157 pars['string_thickness_pd_n'] = 0158 pars['number_of_pearls_pd_n'] = 0159 elif name == 'line':160 pars['scale'] = 1161 pars['background'] = 0162 elif name == 'rpa':163 pars['case_num'] = int(pars['case_num'])164 elif getattr(model_definition, 'category', None) == 'structure-factor':165 pars['scale'], pars['background'] = 1, 0166 167 168 # If it is a product model P*S, then check the individual forms for special 169 # cases. Note: despite the structure factor alone not having scale or 170 # background, the product model does, so this is below the test for 171 # models without scale or background. 172 namelist = name.split('*') if '*' in name else [name] 173 for name in namelist: 174 if name == 'pearl_necklace': 175 pars['string_thickness_pd_n'] = 0 176 pars['number_of_pearls_pd_n'] = 0 177 elif name == 'line': 178 pars['scale'] = 1 179 pars['background'] = 0 180 elif name == 'rpa': 181 pars['case_num'] = int(pars['case_num']) -
sasmodels/core.py
rd18582e r17bbadd 21 21 22 22 __all__ = [ 23 "list_models", "load_model_ definition", "precompile_dll",24 " load_model", "make_kernel", "call_kernel", "call_ER", "call_VR",23 "list_models", "load_model_info", "precompile_dll", 24 "build_model", "make_kernel", "call_kernel", "call_ER_VR", 25 25 ] 26 26 … … 35 35 36 36 37 def load_model_ definition(model_name):37 def load_model_info(model_name): 38 38 """ 39 39 Load a model definition given the model name. … … 43 43 """ 44 44 __import__('sasmodels.models.'+model_name) 45 model_definition= getattr(models, model_name, None)46 return model_definition45 kernel_module = getattr(models, model_name, None) 46 return generate.make_model_info(kernel_module) 47 47 48 48 … … 51 51 Precompile the dll for a model. 52 52 53 Returns the path to the compiled model. 53 Returns the path to the compiled model, or None if the model is a pure 54 python model. 54 55 55 56 This can be used when build the windows distribution of sasmodels … … 60 61 dll path and the allowed floating point precision. 61 62 """ 62 model_ definition = load_model_definition(model_name)63 source , info = generate.make(model_definition)64 return kerneldll.make_dll(source, info, dtype=dtype)63 model_info = load_model_info(model_name) 64 source = generate.make_source(model_info) 65 return kerneldll.make_dll(source, model_info, dtype=dtype) if source else None 65 66 66 67 … … 73 74 return True 74 75 75 def load_model(model_definition, dtype=None, platform="ocl"):76 def build_model(model_info, dtype=None, platform="ocl"): 76 77 """ 77 78 Prepare the model for the default execution platform. … … 80 81 on the model and the computing platform. 81 82 82 *model_definition* is the python module which defines the model. If the 83 model name is given instead, then :func:`load_model_definition` will be 84 called with the model name. 83 *model_info* is the model definition structure returned from 84 :func:`load_model_info`. 85 85 86 86 *dtype* indicates whether the model should use single or double precision … … 93 93 otherwise it uses the default "ocl". 94 94 """ 95 if isstr(model_definition): 96 model_definition = load_model_definition(model_definition) 95 source = generate.make_source(model_info) 97 96 if dtype is None: 98 dtype = 'single' if getattr(model_definition, 'single', True) else 'double' 99 source, info = generate.make(model_definition) 100 if callable(info.get('Iq', None)): 101 return kernelpy.PyModel(info) 97 dtype = 'single' if model_info['single'] else 'double' 98 if callable(model_info.get('Iq', None)): 99 return kernelpy.PyModel(model_info) 102 100 103 101 ## for debugging: … … 107 105 ## 4. rerun "python -m sasmodels.direct_model $MODELNAME" 108 106 ## 5. uncomment open().read() so that source will be regenerated from model 109 # open( info['name']+'.c','w').write(source)110 # source = open( info['name']+'.cl','r').read()107 # open(model_info['name']+'.c','w').write(source) 108 # source = open(model_info['name']+'.cl','r').read() 111 109 112 110 if (platform == "dll" 113 111 or not HAVE_OPENCL 114 112 or not kernelcl.environment().has_type(dtype)): 115 return kerneldll.load_dll(source, info, dtype)113 return kerneldll.load_dll(source, model_info, dtype) 116 114 else: 117 return kernelcl.GpuModel(source, info, dtype)115 return kernelcl.GpuModel(source, model_info, dtype) 118 116 119 117 def make_kernel(model, q_vectors): … … 123 121 return model(q_vectors) 124 122 125 def get_weights( info, pars, name):123 def get_weights(model_info, pars, name): 126 124 """ 127 125 Generate the distribution for parameter *name* given the parameter values … … 131 129 from the *pars* dictionary for parameter value and parameter dispersion. 132 130 """ 133 relative = name in info['partype']['pd-rel']134 limits = info['limits'][name]131 relative = name in model_info['partype']['pd-rel'] 132 limits = model_info['limits'][name] 135 133 disperser = pars.get(name+'_pd_type', 'gaussian') 136 value = pars.get(name, info['defaults'][name])134 value = pars.get(name, model_info['defaults'][name]) 137 135 npts = pars.get(name+'_pd_n', 0) 138 136 width = pars.get(name+'_pd', 0.0) … … 173 171 return kernel(fixed_pars, pd_pars, cutoff=cutoff) 174 172 173 def call_ER_VR(model_info, vol_pars): 174 """ 175 Return effect radius and volume ratio for the model. 176 177 *info* is either *kernel.info* for *kernel=make_kernel(model,q)* 178 or *model.info*. 179 180 *pars* are the parameters as expected by :func:`call_kernel`. 181 """ 182 ER = model_info.get('ER', None) 183 VR = model_info.get('VR', None) 184 value, weight = dispersion_mesh(vol_pars) 185 186 individual_radii = ER(*value) if ER else 1.0 187 whole, part = VR(*value) if VR else (1.0, 1.0) 188 189 effect_radius = np.sum(weight*individual_radii) / np.sum(weight) 190 volume_ratio = np.sum(weight*part)/np.sum(weight*whole) 191 return effect_radius, volume_ratio 192 193 175 194 def call_ER(info, pars): 176 195 """ 177 196 Call the model ER function using *pars*. 178 179 197 *info* is either *model.info* if you have a loaded model, or *kernel.info* 180 198 if you have a model kernel prepared for evaluation. … … 194 212 """ 195 213 Call the model VR function using *pars*. 196 197 214 *info* is either *model.info* if you have a loaded model, or *kernel.info* 198 215 if you have a model kernel prepared for evaluation. … … 208 225 return np.sum(weight*part)/np.sum(weight*whole) 209 226 227 # TODO: remove call_ER, call_VR 228 -
sasmodels/direct_model.py
rd18582e r17bbadd 25 25 import numpy as np 26 26 27 from .core import load_model_definition, load_model,make_kernel28 from .core import call_kernel, call_ER , call_VR27 from .core import make_kernel 28 from .core import call_kernel, call_ER_VR 29 29 from . import sesans 30 30 from . import resolution … … 180 180 return self._calc_theory(pars, cutoff=self.cutoff) 181 181 182 def ER(self, **pars): 183 """ 184 Compute the equivalent radius for the model. 185 186 Return 0. if not defined. 187 """ 188 return call_ER(self.model.info, pars) 189 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 """ 197 return call_VR(self.model.info, pars) 182 def ER_VR(self, **pars): 183 """ 184 Compute the equivalent radius and volume ratio for the model. 185 """ 186 return call_ER_VR(self.model.info, pars) 198 187 199 188 def simulate_data(self, noise=None, **pars): … … 210 199 import sys 211 200 from .data import empty_data1D, empty_data2D 201 from .core import load_model_info, build_model 212 202 213 203 if len(sys.argv) < 3: … … 216 206 model_name = sys.argv[1] 217 207 call = sys.argv[2].upper() 218 if call not in ("ER", "VR"):208 if call != "ER_VR": 219 209 try: 220 210 values = [float(v) for v in call.split(',')] … … 233 223 data = empty_data1D([0.001]) # Data not used in ER/VR 234 224 235 model_ definition = load_model_definition(model_name)236 model = load_model(model_definition)225 model_info = load_model_info(model_name) 226 model = build_model(model_info) 237 227 calculator = DirectModel(data, model) 238 228 pars = dict((k, float(v)) 239 229 for pair in sys.argv[3:] 240 230 for k, v in [pair.split('=')]) 241 if call == "ER": 242 print(calculator.ER(**pars)) 243 elif call == "VR": 244 print(calculator.VR(**pars)) 231 if call == "ER_VR": 232 print(calculator.ER_VR(**pars)) 245 233 else: 246 234 Iq = calculator(**pars) -
sasmodels/generate.py
r5ceb7d0 r17bbadd 117 117 are added to the beginning of the parameter list. They will show up 118 118 in the documentation as model parameters, but they are never sent to 119 the kernel functions. 120 121 *category* is the default category for the model. Models in the 122 *structure-factor* category do not have *scale* and *background* 123 added. 119 the kernel functions. Note that *effect_radius* and *volfraction* 120 must occur first in structure factor calculations. 121 122 *category* is the default category for the model. The category is 123 two level structure, with the form "group:section", indicating where 124 in the manual the model will be located. Models are alphabetical 125 within their section. 124 126 125 127 *source* is the list of C-99 source files that must be joined to … … 157 159 158 160 159 An * info* dictionary is constructed from the kernel meta data and161 An *model_info* dictionary is constructed from the kernel meta data and 160 162 returned to the caller. 161 163 … … 190 192 191 193 The function :func:`make` loads the metadata from the module and returns 192 the kernel source. The function :func:` doc` extracts the doc string194 the kernel source. The function :func:`make_doc` extracts the doc string 193 195 and adds the parameter table to the top. The function :func:`model_sources` 194 196 returns a list of files required by the model. … … 217 219 import numpy as np 218 220 219 #__all__ = ["make", "doc", "model_sources", "convert_type"] 221 #TODO: determine which functions are useful outside of generate 222 #__all__ = ["model_info", "make_doc", "make_source", "convert_type"] 220 223 221 224 C_KERNEL_TEMPLATE_PATH = joinpath(dirname(__file__), 'kernel_template.c') … … 327 330 raise ValueError("%r not found in %s" % (filename, search_path)) 328 331 329 def model_sources( info):332 def model_sources(model_info): 330 333 """ 331 334 Return a list of the sources file paths for the module. 332 335 """ 333 search_path = [dirname( info['filename']),336 search_path = [dirname(model_info['filename']), 334 337 abspath(joinpath(dirname(__file__), 'models'))] 335 return [_search(search_path, f) for f in info['source']]338 return [_search(search_path, f) for f in model_info['source']] 336 339 337 340 # Pragmas for enable OpenCL features. Be sure to protect them so that they … … 391 394 392 395 393 def kernel_name( info, is_2d):396 def kernel_name(model_info, is_2d): 394 397 """ 395 398 Name of the exported kernel symbol. 396 399 """ 397 return info['name'] + "_" + ("Iqxy" if is_2d else "Iq") 398 400 return model_info['name'] + "_" + ("Iqxy" if is_2d else "Iq") 401 402 403 def indent(s, depth): 404 """ 405 Indent a string of text with *depth* additional spaces on each line. 406 """ 407 spaces = " "*depth 408 sep = "\n" + spaces 409 return spaces + sep.join(s.split("\n")) 410 411 412 LOOP_OPEN = """\ 413 for (int %(name)s_i=0; %(name)s_i < N%(name)s; %(name)s_i++) { 414 const double %(name)s = loops[2*(%(name)s_i%(offset)s)]; 415 const double %(name)s_w = loops[2*(%(name)s_i%(offset)s)+1];\ 416 """ 417 def build_polydispersity_loops(pd_pars): 418 """ 419 Build polydispersity loops 420 421 Returns loop opening and loop closing 422 """ 423 depth = 4 424 offset = "" 425 loop_head = [] 426 loop_end = [] 427 for name in pd_pars: 428 subst = {'name': name, 'offset': offset} 429 loop_head.append(indent(LOOP_OPEN % subst, depth)) 430 loop_end.insert(0, (" "*depth) + "}") 431 offset += '+N' + name 432 depth += 2 433 return "\n".join(loop_head), "\n".join(loop_end) 434 435 C_KERNEL_TEMPLATE = None 436 def make_source(model_info): 437 """ 438 Generate the OpenCL/ctypes kernel from the module info. 439 440 Uses source files found in the given search path. 441 """ 442 if callable(model_info['Iq']): 443 return None 444 445 # TODO: need something other than volume to indicate dispersion parameters 446 # No volume normalization despite having a volume parameter. 447 # Thickness is labelled a volume in order to trigger polydispersity. 448 # May want a separate dispersion flag, or perhaps a separate category for 449 # disperse, but not volume. Volume parameters also use relative values 450 # for the distribution rather than the absolute values used by angular 451 # dispersion. Need to be careful that necessary parameters are available 452 # for computing volume even if we allow non-disperse volume parameters. 453 454 # Load template 455 global C_KERNEL_TEMPLATE 456 if C_KERNEL_TEMPLATE is None: 457 with open(C_KERNEL_TEMPLATE_PATH) as fid: 458 C_KERNEL_TEMPLATE = fid.read() 459 460 # Load additional sources 461 source = [open(f).read() for f in model_sources(model_info)] 462 463 # Prepare defines 464 defines = [] 465 partype = model_info['partype'] 466 pd_1d = partype['pd-1d'] 467 pd_2d = partype['pd-2d'] 468 fixed_1d = partype['fixed-1d'] 469 fixed_2d = partype['fixed-1d'] 470 471 iq_parameters = [p[0] 472 for p in model_info['parameters'][2:] # skip scale, background 473 if p[0] in set(fixed_1d + pd_1d)] 474 iqxy_parameters = [p[0] 475 for p in model_info['parameters'][2:] # skip scale, background 476 if p[0] in set(fixed_2d + pd_2d)] 477 volume_parameters = [p[0] 478 for p in model_info['parameters'] 479 if p[4] == 'volume'] 480 481 # Fill in defintions for volume parameters 482 if volume_parameters: 483 defines.append(('VOLUME_PARAMETERS', 484 ','.join(volume_parameters))) 485 defines.append(('VOLUME_WEIGHT_PRODUCT', 486 '*'.join(p + '_w' for p in volume_parameters))) 487 488 # Generate form_volume function from body only 489 if model_info['form_volume'] is not None: 490 if volume_parameters: 491 vol_par_decl = ', '.join('double ' + p for p in volume_parameters) 492 else: 493 vol_par_decl = 'void' 494 defines.append(('VOLUME_PARAMETER_DECLARATIONS', 495 vol_par_decl)) 496 fn = """\ 497 double form_volume(VOLUME_PARAMETER_DECLARATIONS); 498 double form_volume(VOLUME_PARAMETER_DECLARATIONS) { 499 %(body)s 500 } 501 """ % {'body':model_info['form_volume']} 502 source.append(fn) 503 504 # Fill in definitions for Iq parameters 505 defines.append(('IQ_KERNEL_NAME', model_info['name'] + '_Iq')) 506 defines.append(('IQ_PARAMETERS', ', '.join(iq_parameters))) 507 if fixed_1d: 508 defines.append(('IQ_FIXED_PARAMETER_DECLARATIONS', 509 ', \\\n '.join('const double %s' % p for p in fixed_1d))) 510 if pd_1d: 511 defines.append(('IQ_WEIGHT_PRODUCT', 512 '*'.join(p + '_w' for p in pd_1d))) 513 defines.append(('IQ_DISPERSION_LENGTH_DECLARATIONS', 514 ', \\\n '.join('const int N%s' % p for p in pd_1d))) 515 defines.append(('IQ_DISPERSION_LENGTH_SUM', 516 '+'.join('N' + p for p in pd_1d))) 517 open_loops, close_loops = build_polydispersity_loops(pd_1d) 518 defines.append(('IQ_OPEN_LOOPS', 519 open_loops.replace('\n', ' \\\n'))) 520 defines.append(('IQ_CLOSE_LOOPS', 521 close_loops.replace('\n', ' \\\n'))) 522 if model_info['Iq'] is not None: 523 defines.append(('IQ_PARAMETER_DECLARATIONS', 524 ', '.join('double ' + p for p in iq_parameters))) 525 fn = """\ 526 double Iq(double q, IQ_PARAMETER_DECLARATIONS); 527 double Iq(double q, IQ_PARAMETER_DECLARATIONS) { 528 %(body)s 529 } 530 """ % {'body':model_info['Iq']} 531 source.append(fn) 532 533 # Fill in definitions for Iqxy parameters 534 defines.append(('IQXY_KERNEL_NAME', model_info['name'] + '_Iqxy')) 535 defines.append(('IQXY_PARAMETERS', ', '.join(iqxy_parameters))) 536 if fixed_2d: 537 defines.append(('IQXY_FIXED_PARAMETER_DECLARATIONS', 538 ', \\\n '.join('const double %s' % p for p in fixed_2d))) 539 if pd_2d: 540 defines.append(('IQXY_WEIGHT_PRODUCT', 541 '*'.join(p + '_w' for p in pd_2d))) 542 defines.append(('IQXY_DISPERSION_LENGTH_DECLARATIONS', 543 ', \\\n '.join('const int N%s' % p for p in pd_2d))) 544 defines.append(('IQXY_DISPERSION_LENGTH_SUM', 545 '+'.join('N' + p for p in pd_2d))) 546 open_loops, close_loops = build_polydispersity_loops(pd_2d) 547 defines.append(('IQXY_OPEN_LOOPS', 548 open_loops.replace('\n', ' \\\n'))) 549 defines.append(('IQXY_CLOSE_LOOPS', 550 close_loops.replace('\n', ' \\\n'))) 551 if model_info['Iqxy'] is not None: 552 defines.append(('IQXY_PARAMETER_DECLARATIONS', 553 ', '.join('double ' + p for p in iqxy_parameters))) 554 fn = """\ 555 double Iqxy(double qx, double qy, IQXY_PARAMETER_DECLARATIONS); 556 double Iqxy(double qx, double qy, IQXY_PARAMETER_DECLARATIONS) { 557 %(body)s 558 } 559 """ % {'body':model_info['Iqxy']} 560 source.append(fn) 561 562 # Need to know if we have a theta parameter for Iqxy; it is not there 563 # for the magnetic sphere model, for example, which has a magnetic 564 # orientation but no shape orientation. 565 if 'theta' in pd_2d: 566 defines.append(('IQXY_HAS_THETA', '1')) 567 568 #for d in defines: print(d) 569 defines = '\n'.join('#define %s %s' % (k, v) for k, v in defines) 570 sources = '\n\n'.join(source) 571 return C_KERNEL_TEMPLATE % { 572 'DEFINES': defines, 573 'SOURCES': sources, 574 } 399 575 400 576 def categorize_parameters(pars): … … 403 579 404 580 Returns a dictionary of categories. 581 582 Note: these categories are subject to change, depending on the needs of 583 the UI and the needs of the kernel calling function. 584 585 The categories are as follows: 586 587 * *volume* list of volume parameter names 588 * *orientation* list of orientation parameters 589 * *magnetic* list of magnetic parameters 590 * *<empty string>* list of parameters that have no type info 591 592 Each parameter is in one and only one category. 593 594 The following derived categories are created: 595 596 * *fixed-1d* list of non-polydisperse parameters for 1D models 597 * *pd-1d* list of polydisperse parameters for 1D models 598 * *fixed-2d* list of non-polydisperse parameters for 2D models 599 * *pd-d2* list of polydisperse parameters for 2D models 405 600 """ 406 601 partype = { … … 429 624 return partype 430 625 431 def indent(s, depth): 432 """ 433 Indent a string of text with *depth* additional spaces on each line. 434 """ 435 spaces = " "*depth 436 sep = "\n" + spaces 437 return spaces + sep.join(s.split("\n")) 438 439 440 LOOP_OPEN = """\ 441 for (int %(name)s_i=0; %(name)s_i < N%(name)s; %(name)s_i++) { 442 const double %(name)s = loops[2*(%(name)s_i%(offset)s)]; 443 const double %(name)s_w = loops[2*(%(name)s_i%(offset)s)+1];\ 444 """ 445 def build_polydispersity_loops(pd_pars): 446 """ 447 Build polydispersity loops 448 449 Returns loop opening and loop closing 450 """ 451 depth = 4 452 offset = "" 453 loop_head = [] 454 loop_end = [] 455 for name in pd_pars: 456 subst = {'name': name, 'offset': offset} 457 loop_head.append(indent(LOOP_OPEN % subst, depth)) 458 loop_end.insert(0, (" "*depth) + "}") 459 offset += '+N' + name 460 depth += 2 461 return "\n".join(loop_head), "\n".join(loop_end) 462 463 C_KERNEL_TEMPLATE = None 464 def make_model(info): 465 """ 466 Generate the code for the kernel defined by info, using source files 467 found in the given search path. 468 """ 469 # TODO: need something other than volume to indicate dispersion parameters 470 # No volume normalization despite having a volume parameter. 471 # Thickness is labelled a volume in order to trigger polydispersity. 472 # May want a separate dispersion flag, or perhaps a separate category for 473 # disperse, but not volume. Volume parameters also use relative values 474 # for the distribution rather than the absolute values used by angular 475 # dispersion. Need to be careful that necessary parameters are available 476 # for computing volume even if we allow non-disperse volume parameters. 477 478 # Load template 479 global C_KERNEL_TEMPLATE 480 if C_KERNEL_TEMPLATE is None: 481 with open(C_KERNEL_TEMPLATE_PATH) as fid: 482 C_KERNEL_TEMPLATE = fid.read() 483 484 # Load additional sources 485 source = [open(f).read() for f in model_sources(info)] 486 487 # Prepare defines 488 defines = [] 489 partype = info['partype'] 490 pd_1d = partype['pd-1d'] 491 pd_2d = partype['pd-2d'] 492 fixed_1d = partype['fixed-1d'] 493 fixed_2d = partype['fixed-1d'] 494 495 iq_parameters = [p[0] 496 for p in info['parameters'][2:] # skip scale, background 497 if p[0] in set(fixed_1d + pd_1d)] 498 iqxy_parameters = [p[0] 499 for p in info['parameters'][2:] # skip scale, background 500 if p[0] in set(fixed_2d + pd_2d)] 501 volume_parameters = [p[0] 502 for p in info['parameters'] 503 if p[4] == 'volume'] 504 505 # Fill in defintions for volume parameters 506 if volume_parameters: 507 defines.append(('VOLUME_PARAMETERS', 508 ','.join(volume_parameters))) 509 defines.append(('VOLUME_WEIGHT_PRODUCT', 510 '*'.join(p + '_w' for p in volume_parameters))) 511 512 # Generate form_volume function from body only 513 if info['form_volume'] is not None: 514 if volume_parameters: 515 vol_par_decl = ', '.join('double ' + p for p in volume_parameters) 516 else: 517 vol_par_decl = 'void' 518 defines.append(('VOLUME_PARAMETER_DECLARATIONS', 519 vol_par_decl)) 520 fn = """\ 521 double form_volume(VOLUME_PARAMETER_DECLARATIONS); 522 double form_volume(VOLUME_PARAMETER_DECLARATIONS) { 523 %(body)s 524 } 525 """ % {'body':info['form_volume']} 526 source.append(fn) 527 528 # Fill in definitions for Iq parameters 529 defines.append(('IQ_KERNEL_NAME', info['name'] + '_Iq')) 530 defines.append(('IQ_PARAMETERS', ', '.join(iq_parameters))) 531 if fixed_1d: 532 defines.append(('IQ_FIXED_PARAMETER_DECLARATIONS', 533 ', \\\n '.join('const double %s' % p for p in fixed_1d))) 534 if pd_1d: 535 defines.append(('IQ_WEIGHT_PRODUCT', 536 '*'.join(p + '_w' for p in pd_1d))) 537 defines.append(('IQ_DISPERSION_LENGTH_DECLARATIONS', 538 ', \\\n '.join('const int N%s' % p for p in pd_1d))) 539 defines.append(('IQ_DISPERSION_LENGTH_SUM', 540 '+'.join('N' + p for p in pd_1d))) 541 open_loops, close_loops = build_polydispersity_loops(pd_1d) 542 defines.append(('IQ_OPEN_LOOPS', 543 open_loops.replace('\n', ' \\\n'))) 544 defines.append(('IQ_CLOSE_LOOPS', 545 close_loops.replace('\n', ' \\\n'))) 546 if info['Iq'] is not None: 547 defines.append(('IQ_PARAMETER_DECLARATIONS', 548 ', '.join('double ' + p for p in iq_parameters))) 549 fn = """\ 550 double Iq(double q, IQ_PARAMETER_DECLARATIONS); 551 double Iq(double q, IQ_PARAMETER_DECLARATIONS) { 552 %(body)s 553 } 554 """ % {'body':info['Iq']} 555 source.append(fn) 556 557 # Fill in definitions for Iqxy parameters 558 defines.append(('IQXY_KERNEL_NAME', info['name'] + '_Iqxy')) 559 defines.append(('IQXY_PARAMETERS', ', '.join(iqxy_parameters))) 560 if fixed_2d: 561 defines.append(('IQXY_FIXED_PARAMETER_DECLARATIONS', 562 ', \\\n '.join('const double %s' % p for p in fixed_2d))) 563 if pd_2d: 564 defines.append(('IQXY_WEIGHT_PRODUCT', 565 '*'.join(p + '_w' for p in pd_2d))) 566 defines.append(('IQXY_DISPERSION_LENGTH_DECLARATIONS', 567 ', \\\n '.join('const int N%s' % p for p in pd_2d))) 568 defines.append(('IQXY_DISPERSION_LENGTH_SUM', 569 '+'.join('N' + p for p in pd_2d))) 570 open_loops, close_loops = build_polydispersity_loops(pd_2d) 571 defines.append(('IQXY_OPEN_LOOPS', 572 open_loops.replace('\n', ' \\\n'))) 573 defines.append(('IQXY_CLOSE_LOOPS', 574 close_loops.replace('\n', ' \\\n'))) 575 if info['Iqxy'] is not None: 576 defines.append(('IQXY_PARAMETER_DECLARATIONS', 577 ', '.join('double ' + p for p in iqxy_parameters))) 578 fn = """\ 579 double Iqxy(double qx, double qy, IQXY_PARAMETER_DECLARATIONS); 580 double Iqxy(double qx, double qy, IQXY_PARAMETER_DECLARATIONS) { 581 %(body)s 582 } 583 """ % {'body':info['Iqxy']} 584 source.append(fn) 585 586 # Need to know if we have a theta parameter for Iqxy; it is not there 587 # for the magnetic sphere model, for example, which has a magnetic 588 # orientation but no shape orientation. 589 if 'theta' in pd_2d: 590 defines.append(('IQXY_HAS_THETA', '1')) 591 592 #for d in defines: print(d) 593 defines = '\n'.join('#define %s %s' % (k, v) for k, v in defines) 594 sources = '\n\n'.join(source) 595 return C_KERNEL_TEMPLATE % { 596 'DEFINES': defines, 597 'SOURCES': sources, 598 } 599 600 def make_info(kernel_module): 626 def process_parameters(model_info): 627 """ 628 Process parameter block, precalculating parameter details. 629 """ 630 # Fill in the derived attributes 631 model_info['limits'] = dict((p[0], p[3]) for p in model_info['parameters']) 632 model_info['partype'] = categorize_parameters(model_info['parameters']) 633 model_info['defaults'] = dict((p[0], p[2]) for p in model_info['parameters']) 634 if model_info.get('demo', None) is None: 635 model_info['demo'] = model_info['defaults'] 636 637 def make_model_info(kernel_module): 601 638 """ 602 639 Interpret the model definition file, categorizing the parameters. 603 """ 640 641 The module can be loaded with a normal python import statement if you 642 know which module you need, or with __import__('sasmodels.model.'+name) 643 if the name is in a string. 644 645 The *model_info* structure contains the following fields: 646 647 * *id* is the id of the kernel 648 * *name* is the display name of the kernel 649 * *title* is a short description of the kernel 650 * *description* is a long description of the kernel (this doesn't seem 651 very useful since the Help button on the model page brings you directly 652 to the documentation page) 653 * *docs* is the docstring from the module. Use :func:`make_doc` to 654 * *category* specifies the model location in the docs 655 * *parameters* is the model parameter table 656 * *single* is True if the model allows single precision 657 * *defaults* is the *{parameter: value}* table built from the parameter 658 description table. 659 * *limits* is the *{parameter: [min, max]}* table built from the 660 parameter description table. 661 * *partypes* categorizes the model parameters. See 662 :func:`categorize_parameters` for details. 663 * *demo* contains the *{parameter: value}* map used in compare (and maybe 664 for the demo plot, if plots aren't set up to use the default values). 665 If *demo* is not given in the file, then the default values will be used. 666 * *tests* is a set of tests that must pass 667 * *source* is the list of library files to include in the C model build 668 * *Iq*, *Iqxy*, *form_volume*, *ER*, and *VR* are python functions 669 implementing the kernel for the module, or None if they are not 670 defined in python 671 * *oldname* is the model name in pre-4.0 Sasview 672 * *oldpars* is the *{new: old}* parameter translation table 673 from pre-4.0 Sasview 674 * *composition* is None if the model is independent, otherwise it is a 675 tuple with composition type ('product' or 'mixture') and a list of 676 *model_info* blocks for the composition objects. This allows us to 677 build complete product and mixture models from just the info. 678 """ 679 # TODO: maybe turn model_info into a class ModelDefinition 604 680 #print(kernelfile) 605 681 category = getattr(kernel_module, 'category', None) … … 608 684 # parameters if an explicit demo parameter set has not been specified. 609 685 demo_parameters = getattr(kernel_module, 'demo', None) 610 if demo_parameters is None:611 demo_parameters = dict((p[0], p[2]) for p in parameters)612 686 filename = abspath(kernel_module.__file__) 613 687 kernel_id = splitext(basename(filename))[0] 614 688 name = getattr(kernel_module, 'name', None) 689 single = getattr(kernel_module, 'single', True) 615 690 if name is None: 616 691 name = " ".join(w.capitalize() for w in kernel_id.split('_')) 617 info = dict(692 model_info = dict( 618 693 id=kernel_id, # string used to load the kernel 619 694 filename=abspath(kernel_module.__file__), … … 621 696 title=kernel_module.title, 622 697 description=kernel_module.description, 698 docs=kernel_module.__doc__, 623 699 category=category, 624 700 parameters=parameters, 701 composition=None, 702 single=single, 625 703 demo=demo_parameters, 626 704 source=getattr(kernel_module, 'source', []), 627 oldname=kernel_module.oldname, 628 oldpars=kernel_module.oldpars, 705 oldname=getattr(kernel_module, 'oldname', None), 706 oldpars=getattr(kernel_module, 'oldpars', {}), 707 tests=getattr(kernel_module, 'tests', []), 629 708 ) 709 process_parameters(model_info) 630 710 # Fill in attributes which default to None 631 info.update((k, getattr(kernel_module, k, None)) 632 for k in ('ER', 'VR', 'form_volume', 'Iq', 'Iqxy')) 633 # Fill in the derived attributes 634 info['limits'] = dict((p[0], p[3]) for p in info['parameters']) 635 info['partype'] = categorize_parameters(info['parameters']) 636 info['defaults'] = dict((p[0], p[2]) for p in info['parameters']) 637 return info 638 639 def make(kernel_module): 640 """ 641 Build an OpenCL/ctypes function from the definition in *kernel_module*. 642 643 The module can be loaded with a normal python import statement if you 644 know which module you need, or with __import__('sasmodels.model.'+name) 645 if the name is in a string. 646 """ 647 info = make_info(kernel_module) 648 # Assume if one part of the kernel is python then all parts are. 649 source = make_model(info) if not callable(info['Iq']) else None 650 return source, info 711 model_info.update((k, getattr(kernel_module, k, None)) 712 for k in ('ER', 'VR', 'form_volume', 'Iq', 'Iqxy')) 713 return model_info 651 714 652 715 section_marker = re.compile(r'\A(?P<first>[%s])(?P=first)*\Z' … … 683 746 return "\n".join(_convert_section_titles_to_boldface(s.split('\n'))) 684 747 685 def doc(kernel_module):748 def make_doc(model_info): 686 749 """ 687 750 Return the documentation for the model. … … 689 752 Iq_units = "The returned value is scaled to units of |cm^-1| |sr^-1|, absolute scale." 690 753 Sq_units = "The returned value is a dimensionless structure factor, $S(q)$." 691 info = make_info(kernel_module) 692 is_Sq = ("structure-factor" in info['category']) 754 is_Sq = ("structure-factor" in model_info['category']) 693 755 #docs = kernel_module.__doc__ 694 docs = convert_section_titles_to_boldface( kernel_module.__doc__)695 subst = dict(id= info['id'].replace('_', '-'),696 name= info['name'],697 title= info['title'],698 parameters=make_partable( info['parameters']),756 docs = convert_section_titles_to_boldface(model_info['docs']) 757 subst = dict(id=model_info['id'].replace('_', '-'), 758 name=model_info['name'], 759 title=model_info['title'], 760 parameters=make_partable(model_info['parameters']), 699 761 returns=Sq_units if is_Sq else Iq_units, 700 762 docs=docs) … … 710 772 import datetime 711 773 tic = datetime.datetime.now() 712 make (cylinder)774 make_source(make_model_info(cylinder)) 713 775 toc = (datetime.datetime.now() - tic).total_seconds() 714 776 print("time: %g"%toc) … … 725 787 __import__('sasmodels.models.' + name) 726 788 model = getattr(sasmodels.models, name) 727 source, _ = make(model) 789 model_info = make_model_info(model) 790 source = make_source(model_info) 728 791 print(source) 729 792 -
sasmodels/kernelcl.py
re6a5556 r17bbadd 289 289 GPU wrapper for a single model. 290 290 291 *source* and * info* are the model source and interface as returned292 from :func:`gen .make`.291 *source* and *model_info* are the model source and interface as returned 292 from :func:`generate.make_source` and :func:`generate.make_model_info`. 293 293 294 294 *dtype* is the desired model precision. Any numpy dtype for single … … 300 300 that the compiler is allowed to take shortcuts. 301 301 """ 302 def __init__(self, source, info, dtype=generate.F32):303 self.info = info302 def __init__(self, source, model_info, dtype=generate.F32): 303 self.info = model_info 304 304 self.source = source 305 305 self.dtype = generate.F32 if dtype == 'fast' else np.dtype(dtype) … … 356 356 """ 357 357 def __init__(self, q_vectors, dtype=generate.F32): 358 # TODO: do we ever need double precision q? 358 359 env = environment() 359 360 self.nq = q_vectors[0].size … … 389 390 *kernel* is the GpuKernel object to call 390 391 391 * info* is the module information392 *model_info* is the module information 392 393 393 394 *q_vectors* is the q vectors at which the kernel should be evaluated … … 403 404 Call :meth:`release` when done with the kernel instance. 404 405 """ 405 def __init__(self, kernel, info, q_vectors, dtype):406 def __init__(self, kernel, model_info, q_vectors, dtype): 406 407 q_input = GpuInput(q_vectors, dtype) 407 408 self.kernel = kernel 408 self.info = info409 self.info = model_info 409 410 self.res = np.empty(q_input.nq, q_input.dtype) 410 411 dim = '2d' if q_input.is_2d else '1d' 411 self.fixed_pars = info['partype']['fixed-' + dim]412 self.pd_pars = info['partype']['pd-' + dim]412 self.fixed_pars = model_info['partype']['fixed-' + dim] 413 self.pd_pars = model_info['partype']['pd-' + dim] 413 414 414 415 # Inputs and outputs for each kernel call … … 430 431 else np.float32) # will never get here, so use np.float32 431 432 433 #print "pars", fixed_pars, pd_pars 432 434 res_bi = self.res_b 433 435 nq = np.uint32(self.q_input.nq) -
sasmodels/kerneldll.py
reafc9fa r17bbadd 89 89 90 90 91 def dll_path( info, dtype="double"):92 """ 93 Path to the compiled model defined by * info*.91 def dll_path(model_info, dtype="double"): 92 """ 93 Path to the compiled model defined by *model_info*. 94 94 """ 95 95 from os.path import join as joinpath, split as splitpath, splitext 96 basename = splitext(splitpath( info['filename'])[1])[0]96 basename = splitext(splitpath(model_info['filename'])[1])[0] 97 97 if np.dtype(dtype) == generate.F32: 98 98 basename += "32" … … 104 104 105 105 106 def make_dll(source, info, dtype="double"):106 def make_dll(source, model_info, dtype="double"): 107 107 """ 108 108 Load the compiled model defined by *kernel_module*. … … 123 123 models are allowed as DLLs. 124 124 """ 125 if callable( info.get('Iq', None)):126 return PyModel( info)125 if callable(model_info.get('Iq', None)): 126 return PyModel(model_info) 127 127 128 128 dtype = np.dtype(dtype) … … 133 133 134 134 if dtype == generate.F32: # 32-bit dll 135 tempfile_prefix = 'sas_' +info['name']+'32_'135 tempfile_prefix = 'sas_' + model_info['name'] + '32_' 136 136 elif dtype == generate.F64: 137 tempfile_prefix = 'sas_' +info['name']+'64_'137 tempfile_prefix = 'sas_' + model_info['name'] + '64_' 138 138 else: 139 tempfile_prefix = 'sas_' +info['name']+'128_'139 tempfile_prefix = 'sas_' + model_info['name'] + '128_' 140 140 141 141 source = generate.convert_type(source, dtype) 142 source_files = generate.model_sources( info) + [info['filename']]143 dll = dll_path( info, dtype)142 source_files = generate.model_sources(model_info) + [model_info['filename']] 143 dll = dll_path(model_info, dtype) 144 144 newest = max(os.path.getmtime(f) for f in source_files) 145 145 if not os.path.exists(dll) or os.path.getmtime(dll) < newest: … … 159 159 160 160 161 def load_dll(source, info, dtype="double"):161 def load_dll(source, model_info, dtype="double"): 162 162 """ 163 163 Create and load a dll corresponding to the source, info pair returned … … 167 167 allowed floating point precision. 168 168 """ 169 filename = make_dll(source, info, dtype=dtype)170 return DllModel(filename, info, dtype=dtype)169 filename = make_dll(source, model_info, dtype=dtype) 170 return DllModel(filename, model_info, dtype=dtype) 171 171 172 172 … … 178 178 ctypes wrapper for a single model. 179 179 180 *source* and * info* are the model source and interface as returned180 *source* and *model_info* are the model source and interface as returned 181 181 from :func:`gen.make`. 182 182 … … 188 188 Call :meth:`release` when done with the kernel. 189 189 """ 190 def __init__(self, dllpath, info, dtype=generate.F32):191 self.info = info190 def __init__(self, dllpath, model_info, dtype=generate.F32): 191 self.info = model_info 192 192 self.dllpath = dllpath 193 193 self.dll = None … … 244 244 *kernel* is the c function to call. 245 245 246 * info* is the module information246 *model_info* is the module information 247 247 248 248 *q_input* is the DllInput q vectors at which the kernel should be … … 257 257 Call :meth:`release` when done with the kernel instance. 258 258 """ 259 def __init__(self, kernel, info, q_input):260 self.info = info259 def __init__(self, kernel, model_info, q_input): 260 self.info = model_info 261 261 self.q_input = q_input 262 262 self.kernel = kernel 263 263 self.res = np.empty(q_input.nq, q_input.dtype) 264 264 dim = '2d' if q_input.is_2d else '1d' 265 self.fixed_pars = info['partype']['fixed-'+dim]266 self.pd_pars = info['partype']['pd-'+dim]265 self.fixed_pars = model_info['partype']['fixed-' + dim] 266 self.pd_pars = model_info['partype']['pd-' + dim] 267 267 268 268 # In dll kernel, but not in opencl kernel -
sasmodels/kernelpy.py
reafc9fa r17bbadd 16 16 Wrapper for pure python models. 17 17 """ 18 def __init__(self, info):19 self.info = info18 def __init__(self, model_info): 19 self.info = model_info 20 20 21 21 def __call__(self, q_vectors): … … 68 68 *kernel* is the DllKernel object to call. 69 69 70 * info* is the module information70 *model_info* is the module information 71 71 72 72 *q_input* is the DllInput q vectors at which the kernel should be … … 81 81 Call :meth:`release` when done with the kernel instance. 82 82 """ 83 def __init__(self, kernel, info, q_input):84 self.info = info83 def __init__(self, kernel, model_info, q_input): 84 self.info = model_info 85 85 self.q_input = q_input 86 86 self.res = np.empty(q_input.nq, q_input.dtype) … … 106 106 else: 107 107 self.kernel = kernel 108 fixed_pars = info['partype']['fixed-' + dim]109 pd_pars = info['partype']['pd-' + dim]110 vol_pars = info['partype']['volume']108 fixed_pars = model_info['partype']['fixed-' + dim] 109 pd_pars = model_info['partype']['pd-' + dim] 110 vol_pars = model_info['partype']['volume'] 111 111 112 112 # First two fixed pars are scale and background 113 pars = [p[0] for p in info['parameters'][2:]]113 pars = [p[0] for p in model_info['parameters'][2:]] 114 114 offset = len(self.q_input.q_vectors) 115 115 self.args = self.q_input.q_vectors + [None] * len(pars) -
sasmodels/list_pars.py
r5c962df r17bbadd 13 13 import sys 14 14 15 from .core import load_model_definition 16 from .generate import make_info 15 from .core import load_model_info 17 16 from .compare import MODELS, columnize 18 17 … … 25 24 partable = {} 26 25 for name in sorted(MODELS): 27 definition = load_model_definition(name) 28 info = make_info(definition) 29 for p in info['parameters']: 26 model_info = load_model_info(name) 27 for p in model_info['parameters']: 30 28 pname = p[0] 31 29 partable.setdefault(pname, []) -
sasmodels/model_test.py
r13ed84c r17bbadd 50 50 import numpy as np 51 51 52 from .core import list_models, load_model_ definition, load_model, HAVE_OPENCL52 from .core import list_models, load_model_info, build_model, HAVE_OPENCL 53 53 from .core import make_kernel, call_kernel, call_ER, call_VR 54 54 from .exception import annotate_exception 55 55 56 #TODO: rename to tests so that tab completion works better for models directory 56 57 57 58 def make_suite(loaders, models): … … 76 77 for model_name in models: 77 78 if model_name in skip: continue 78 model_ definition = load_model_definition(model_name)79 model_info = load_model_info(model_name) 79 80 80 81 #print('------') … … 85 86 # don't try to call cl kernel since it will not be 86 87 # available in some environmentes. 87 is_py = callable( getattr(model_definition, 'Iq', None))88 is_py = callable(model_info['Iq']) 88 89 89 90 if is_py: # kernel implemented in python 90 91 test_name = "Model: %s, Kernel: python"%model_name 91 92 test_method_name = "test_%s_python" % model_name 92 test = ModelTestCase(test_name, model_ definition,93 test = ModelTestCase(test_name, model_info, 93 94 test_method_name, 94 95 platform="dll", # so that … … 104 105 # single precision. The choice is determined by the 105 106 # presence of *single=False* in the model file. 106 test = ModelTestCase(test_name, model_ definition,107 test = ModelTestCase(test_name, model_info, 107 108 test_method_name, 108 109 platform="ocl", dtype=None) … … 114 115 test_name = "Model: %s, Kernel: dll"%model_name 115 116 test_method_name = "test_%s_dll" % model_name 116 test = ModelTestCase(test_name, model_ definition,117 test = ModelTestCase(test_name, model_info, 117 118 test_method_name, 118 119 platform="dll", … … 132 133 description file. 133 134 """ 134 def __init__(self, test_name, definition, test_method_name,135 def __init__(self, test_name, model_info, test_method_name, 135 136 platform, dtype): 136 137 self.test_name = test_name 137 self. definition = definition138 self.info = model_info 138 139 self.platform = platform 139 140 self.dtype = dtype … … 150 151 ] 151 152 152 tests = getattr(self.definition, 'tests', [])153 tests = self.info['tests'] 153 154 try: 154 model = load_model(self.definition, dtype=self.dtype,155 platform=self.platform)155 model = build_model(self.info, dtype=self.dtype, 156 platform=self.platform) 156 157 for test in smoke_tests + tests: 157 158 self._run_one_test(model, test) -
sasmodels/resolution.py
r5925e90 r17bbadd 1061 1061 else: 1062 1062 pars = {} 1063 defn = core.load_model_definition(name)1064 model = core. load_model(defn)1063 model_info = core.load_model_info(name) 1064 model = core.build_model(model_info) 1065 1065 1066 1066 kernel = core.make_kernel(model, [resolution.q_calc]) -
sasmodels/sasview_model.py
reafc9fa r17bbadd 22 22 from . import core 23 23 24 def make_class(model_ definition, dtype='single', namestyle='name'):24 def make_class(model_info, dtype='single', namestyle='name'): 25 25 """ 26 26 Load the sasview model defined in *kernel_module*. … … 32 32 compatible with SasView. 33 33 """ 34 model = core. load_model(model_definition, dtype=dtype)34 model = core.build_model(model_info, dtype=dtype) 35 35 def __init__(self, multfactor=1): 36 36 SasviewModel.__init__(self, model)
Note: See TracChangeset
for help on using the changeset viewer.