Changes in / [38d2c97:cb97bff] in sasmodels


Ignore:
Files:
37 added
27 deleted
44 edited

Legend:

Unmodified
Added
Removed
  • doc/genmodel.py

    rd138d43 r91c5fdc  
    1 import sys 
    2 sys.path.insert(0,'..') 
     1import sys, os 
     2sys.path.insert(0, os.path.abspath('..')) 
     3from sasmodels import generate, core 
    34 
    4 # Convert ../sasmodels/models/name.py to sasmodels.models.name 
    5 module_name = sys.argv[1][3:-3].replace('/','.').replace('\\','.') 
    6 #print module_name 
    7 module = __import__(module_name) 
    8 for part in module_name.split('.')[1:]: 
    9     module = getattr(module, part) 
    10 #print module 
     5# Convert ../sasmodels/models/name.py to name 
     6model_name = os.path.basename(sys.argv[1])[:-3] 
    117 
    128# Load the doc string from the module definition file and store it in rst 
    13 from sasmodels import generate 
    14 docstr = generate.doc(module) 
     9docstr = generate.make_doc(core.load_model_info(model_name)) 
    1510open(sys.argv[2],'w').write(docstr) 
  • doc/gentoc.py

    r9404dd3 r5041682  
    77from os import mkdir 
    88from os.path import basename, exists, join as joinpath 
    9 from sasmodels.core import load_model_definition 
     9from sasmodels.core import load_model_info 
    1010 
    1111 
     
    5555        model_name = basename(item)[:-3] 
    5656        if model_name.startswith('_'): continue 
    57         model_definition = load_model_definition(model_name) 
    58         if not hasattr(model_definition, 'category'): 
     57        model_info = load_model_info(model_name) 
     58        if model_info['category'] is None: 
    5959            print("Missing category for", item, file=sys.stderr) 
    6060        else: 
    61             category.setdefault(model_definition.category,[]).append(model_name) 
     61            category.setdefault(model_info['category'],[]).append(model_name) 
    6262 
    6363    # Check category names 
  • example/sesansfit.py

    r346bc88 ra98958b  
     1#TODO: Convert units properly (nm -> A) 
     2#TODO: Implement constraints 
     3 
    14from bumps.names import * 
    2  
    35from sasmodels import core, bumps_model 
    46 
    5 if True: # fix when data loader exists 
    6 #    from sas.dataloader.readers\ 
    7     from sas.dataloader.loader import Loader 
    8     loader = Loader() 
    9     filename = 'testsasview1.ses' 
    10     data = loader.load(filename) 
    11     if data is None: raise IOError("Could not load file %r"%(filename,)) 
    12     data.x /= 10 
    13 #    print data 
    14 #    data = load_sesans('mydatfile.pz') 
    15 #    sans_data = load_sans('mysansfile.xml') 
     7HAS_CONVERTER = True 
     8try: 
     9    from sas.sascalc.data_util.nxsunit import Converter 
     10except ImportError: 
     11    HAS_CONVERTER = False 
    1612 
    17 else: 
    18     SElength = np.linspace(0, 2400, 61) # [A] 
    19     data = np.ones_like(SElength) 
    20     err_data = np.ones_like(SElength)*0.03 
     13def sesans_fit(file, model_name, initial_vals={}, custom_params={}, param_range=[]): 
     14    """ 
    2115 
    22     class Sample: 
    23         zacceptance = 0.1 # [A^-1] 
    24         thickness = 0.2 # [cm] 
    25          
    26     class SESANSData1D: 
    27         #q_zmax = 0.23 # [A^-1] 
    28         lam = 0.2 # [nm] 
    29         x = SElength 
    30         y = data 
    31         dy = err_data 
    32         sample = Sample() 
    33     data = SESANSData1D() 
     16    @param file: SESANS file location 
     17    @param model_name: model name string - can be model, model_1 * model_2, and/or model_1 + model_2 
     18    @param initial_vals: dictionary of {param_name : initial_value} 
     19    @param custom_params: dictionary of {custom_parameter_name : Parameter() object} 
     20    @param param_range: dictionary of {parameter_name : [minimum, maximum]} 
     21    @return: FitProblem for Bumps usage 
     22    """ 
     23    try: 
     24        from sas.sascalc.dataloader.loader import Loader 
     25        loader = Loader() 
     26        data = loader.load(file) 
     27        if data is None: raise IOError("Could not load file %r"%(file)) 
     28        if HAS_CONVERTER == True: 
     29            default_unit = "A" 
     30            data_conv_q = Converter(data._xunit) 
     31            data.x = data_conv_q(data.x, units=default_unit) 
     32            data._xunit = default_unit 
    3433 
    35 radius = 1000 
    36 data.Rmax = 3*radius # [A] 
     34    except: 
     35        # If no loadable data file, generate random data 
     36        SElength = np.linspace(0, 2400, 61) # [A] 
     37        data = np.ones_like(SElength) 
     38        err_data = np.ones_like(SElength)*0.03 
    3739 
    38 ##  Sphere parameters 
     40        class Sample: 
     41            zacceptance = 0.1 # [A^-1] 
     42            thickness = 0.2 # [cm] 
    3943 
    40 kernel = core.load_model("sphere", dtype='single') 
    41 phi = Parameter(0.1, name="phi") 
    42 model = bumps_model.Model(kernel, 
    43     scale=phi*(1-phi), sld=7.0, solvent_sld=1.0, radius=radius, 
    44     ) 
    45 phi.range(0.001,0.5) 
    46 #model.radius.pmp(40) 
    47 model.radius.range(1,10000) 
    48 #model.sld.pm(5) 
    49 #model.background 
    50 #model.radius_pd=0 
    51 #model.radius_pd_n=0 
     44        class SESANSData1D: 
     45            #q_zmax = 0.23 # [A^-1] 
     46            lam = 0.2 # [nm] 
     47            x = SElength 
     48            y = data 
     49            dy = err_data 
     50            sample = Sample() 
     51        data = SESANSData1D() 
    5252 
    53 ### Tri-Axial Ellipsoid 
    54 # 
    55 #kernel = core.load_model("triaxial_ellipsoid", dtype='single') 
    56 #phi = Parameter(0.1, name='phi') 
    57 #model = bumps_model.Model(kernel, 
    58 #    scale=phi*(1-phi), sld=7.0, solvent_sld=1.0, radius=radius, 
    59 #    ) 
    60 #phi.range(0.001,0.90) 
    61 ##model.radius.pmp(40) 
    62 #model.radius.range(100,10000) 
    63 ##model.sld.pmp(5) 
    64 ##model.background 
    65 ##model.radius_pd = 0 
    66 ##model.radius_pd_n = 0 
     53    radius = 1000 
     54    data.Rmax = 3*radius # [A] 
    6755 
    68 if False: # have sans data 
    69     M_sesans = bumps_model.Experiment(data=data, model=model) 
    70     M_sans = bumps_model.Experiment(data=sans_data, model=model) 
    71     problem = FitProblem([M_sesans, M_sans]) 
    72 else: 
    73     M_sesans = bumps_model.Experiment(data=data, model=model) 
    74     problem = FitProblem(M_sesans) 
     56    kernel = core.load_model(model_name) 
     57    model = bumps_model.Model(kernel) 
    7558 
     59    # Load custom parameters, initial values and parameter constraints 
     60    for k, v in custom_params.items(): 
     61        setattr(model, k, v) 
     62        model._parameter_names.append(k) 
     63    for k, v in initial_vals.items(): 
     64        param = model.parameters().get(k) 
     65        setattr(param, "value", v) 
     66    for k, v in param_range.items(): 
     67        param = model.parameters().get(k) 
     68        if param is not None: 
     69            setattr(param.bounds, "limits", v) 
     70 
     71    if False: # have sans data 
     72        M_sesans = bumps_model.Experiment(data=data, model=model) 
     73        M_sans = bumps_model.Experiment(data=sans_data, model=model) 
     74        problem = FitProblem([M_sesans, M_sans]) 
     75    else: 
     76        M_sesans = bumps_model.Experiment(data=data, model=model) 
     77        problem = FitProblem(M_sesans) 
     78    return problem 
  • sasmodels/compare.py

    r6869ceb r91c5fdc  
    3838from . import core 
    3939from . import kerneldll 
    40 from . import generate 
     40from . import product 
    4141from .data import plot_theory, empty_data1D, empty_data2D 
    4242from .direct_model import DirectModel 
    43 from .convert import revert_model, constrain_new_to_old 
     43from .convert import revert_pars, constrain_new_to_old 
    4444 
    4545USAGE = """ 
     
    264264    return pars 
    265265 
    266 def constrain_pars(model_definition, pars): 
     266def constrain_pars(model_info, pars): 
    267267    """ 
    268268    Restrict parameters to valid values. 
     
    272272    cylinder radius in this case). 
    273273    """ 
    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 
    275280    if name == 'capped_cylinder' and pars['cap_radius'] < pars['radius']: 
    276281        pars['radius'], pars['cap_radius'] = pars['cap_radius'], pars['radius'] 
     
    340345    return pars 
    341346 
    342 def eval_sasview(model_definition, data): 
     347def eval_sasview(model_info, data): 
    343348    """ 
    344349    Return a model calculator using the SasView fitting engine. 
     
    349354    from sas.models.qsmearing import smear_selection 
    350355 
    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.MultiplicationModel 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 
    360377    smearer = smear_selection(data, model=model) 
    361  
    362378    if hasattr(data, 'qx_data'): 
    363379        q = np.sqrt(data.qx_data**2 + data.qy_data**2) 
     
    382398        """ 
    383399        # 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) 
    385401        for k, v in pars.items(): 
    386402            parts = k.split('.')  # polydispersity components 
     
    405421    'longdouble': '128', 
    406422} 
    407 def eval_opencl(model_definition, data, dtype='single', cutoff=0.): 
     423def eval_opencl(model_info, data, dtype='single', cutoff=0.): 
    408424    """ 
    409425    Return a model calculator using the OpenCL calculation engine. 
    410426    """ 
    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            return core.build_model(model_info, dtype='single', platform="ocl") 
     434    if model_info['composition']: 
     435        composition_type, parts = model_info['composition'] 
     436        if composition_type == 'product': 
     437            P, S = [builder(p) for p in parts] 
     438            model = product.ProductModel(P, S) 
     439        else: 
     440            raise ValueError("mixture models not handled yet") 
     441    else: 
     442        model = builder(model_info) 
    418443    calculator = DirectModel(data, model, cutoff=cutoff) 
    419444    calculator.engine = "OCL%s"%DTYPE_MAP[dtype] 
    420445    return calculator 
    421446 
    422 def eval_ctypes(model_definition, data, dtype='double', cutoff=0.): 
     447def eval_ctypes(model_info, data, dtype='double', cutoff=0.): 
    423448    """ 
    424449    Return a model calculator using the DLL calculation engine. 
     
    426451    if dtype == 'quad': 
    427452        dtype = 'longdouble' 
    428     model = core.load_model(model_definition, dtype=dtype, platform="dll") 
     453    def builder(model_info): 
     454        return core.build_model(model_info, dtype=dtype, platform="dll") 
     455 
     456    if model_info['composition']: 
     457        composition_type, parts = model_info['composition'] 
     458        if composition_type == 'product': 
     459            P, S = [builder(p) for p in parts] 
     460            model = product.ProductModel(P, S) 
     461        else: 
     462            raise ValueError("mixture models not handled yet") 
     463    else: 
     464        model = builder(model_info) 
    429465    calculator = DirectModel(data, model, cutoff=cutoff) 
    430466    calculator.engine = "OMP%s"%DTYPE_MAP[dtype] 
     
    470506    return data, index 
    471507 
    472 def make_engine(model_definition, data, dtype, cutoff): 
     508def make_engine(model_info, data, dtype, cutoff): 
    473509    """ 
    474510    Generate the appropriate calculation engine for the given datatype. 
     
    478514    """ 
    479515    if dtype == 'sasview': 
    480         return eval_sasview(model_definition, data) 
     516        return eval_sasview(model_info, data) 
    481517    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) 
     518        return eval_ctypes(model_info, data, dtype=dtype[:-1], cutoff=cutoff) 
     519    else: 
     520        return eval_opencl(model_info, data, dtype=dtype, cutoff=cutoff) 
    487521 
    488522def compare(opts, limits=None): 
     
    642676 
    643677 
    644 def get_demo_pars(model_definition): 
     678def get_demo_pars(model_info): 
    645679    """ 
    646680    Extract demo parameters from the model definition. 
    647681    """ 
    648     info = generate.make_info(model_definition) 
    649682    # Get the default values for the parameters 
    650     pars = dict((p[0], p[2]) for p in info['parameters']) 
     683    pars = dict((p[0], p[2]) for p in model_info['parameters']) 
    651684 
    652685    # Fill in default values for the polydispersity parameters 
    653     for p in info['parameters']: 
     686    for p in model_info['parameters']: 
    654687        if p[4] in ('volume', 'orientation'): 
    655688            pars[p[0]+'_pd'] = 0.0 
     
    659692 
    660693    # Plug in values given in demo 
    661     pars.update(info['demo']) 
     694    pars.update(model_info['demo']) 
    662695    return pars 
     696 
    663697 
    664698def parse_opts(): 
     
    679713        print(columnize(MODELS, indent="  ")) 
    680714        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) 
    689715    if len(args) > 3: 
    690716        print("expected parameters: model N1 N2") 
     717 
     718    def _get_info(name): 
     719        try: 
     720            model_info = core.load_model_info(name) 
     721        except ImportError, exc: 
     722            print(str(exc)) 
     723            print("Use one of:\n    " + models) 
     724            sys.exit(1) 
     725        return model_info 
     726 
     727    name = args[0] 
     728    if '*' in name: 
     729        parts = [_get_info(k) for k in name.split('*')] 
     730        model_info = product.make_product_info(*parts) 
     731    else: 
     732        model_info = _get_info(name) 
    691733 
    692734    invalid = [o[1:] for o in flags 
     
    770812    # Get demo parameters from model definition, or use default parameters 
    771813    # if model does not define demo parameters 
    772     pars = get_demo_pars(model_definition) 
     814    pars = get_demo_pars(model_info) 
    773815 
    774816    # Fill in parameters given on the command line 
     
    791833        pars = suppress_pd(pars) 
    792834    pars.update(presets)  # set value after random to control value 
    793     constrain_pars(model_definition, pars) 
    794     constrain_new_to_old(model_definition, pars) 
     835    constrain_pars(model_info, pars) 
     836    constrain_new_to_old(model_info, pars) 
    795837    if opts['show_pars']: 
    796838        print(str(parlist(pars))) 
     
    799841    data, _ = make_data(opts) 
    800842    if n1: 
    801         base = make_engine(model_definition, data, engines[0], opts['cutoff']) 
     843        base = make_engine(model_info, data, engines[0], opts['cutoff']) 
    802844    else: 
    803845        base = None 
    804846    if n2: 
    805         comp = make_engine(model_definition, data, engines[1], opts['cutoff']) 
     847        comp = make_engine(model_info, data, engines[1], opts['cutoff']) 
    806848    else: 
    807849        comp = None 
     
    811853    opts.update({ 
    812854        'name'      : name, 
    813         'def'       : model_definition, 
     855        'def'       : model_info, 
    814856        'n1'        : n1, 
    815857        'n2'        : n2, 
     
    854896        config_matplotlib() 
    855897        self.opts = opts 
    856         info = generate.make_info(opts['def']) 
    857         pars, pd_types = bumps_model.create_parameters(info, **opts['pars']) 
     898        model_info = opts['def'] 
     899        pars, pd_types = bumps_model.create_parameters(model_info, **opts['pars']) 
    858900        if not opts['is2d']: 
    859901            active = [base + ext 
    860                       for base in info['partype']['pd-1d'] 
     902                      for base in model_info['partype']['pd-1d'] 
    861903                      for ext in ['', '_pd', '_pd_n', '_pd_nsigma']] 
    862             active.extend(info['partype']['fixed-1d']) 
     904            active.extend(model_info['partype']['fixed-1d']) 
    863905            for k in active: 
    864906                v = pars[k] 
  • sasmodels/compare_many.py

    r4f2478e rb8e5e21  
    101101 
    102102    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) 
    105105    header = ('\n"Model","%s","Count","%d","Dimension","%s"' 
    106106              % (name, N, "2D" if is_2d else "1D")) 
     
    109109 
    110110    if is_2d: 
    111         info = generate.make_info(model_definition) 
    112         partype = info['partype'] 
    113         if not partype['orientation'] and not partype['magnetic']: 
     111        if not model_info['has_2d']: 
    114112            print(',"1-D only"') 
    115113            return 
     
    150148 
    151149 
    152     calc_base = make_engine(model_definition, data, base, cutoff) 
    153     calc_comp = make_engine(model_definition, data, comp, cutoff) 
     150    calc_base = make_engine(model_info, data, base, cutoff) 
     151    calc_comp = make_engine(model_info, data, comp, cutoff) 
    154152    expected = max(PRECISION[base], PRECISION[comp]) 
    155153 
     
    161159        seed = np.random.randint(1e6) 
    162160        pars_i = randomize_pars(pars, seed) 
    163         constrain_pars(model_definition, pars_i) 
    164         constrain_new_to_old(model_definition, pars_i) 
     161        constrain_pars(model_info['id'], pars_i) 
     162        constrain_new_to_old(model_info['id'], pars_i) 
    165163        if mono: 
    166164            pars_i = suppress_pd(pars_i) 
  • sasmodels/convert.py

    r0d0aee1 r667a6f2  
    44import warnings 
    55 
     6STRUCTURE_FACTORS = [ 
     7    'hardsphere', 
     8    'stickyhardsphere', 
     9    'squarewell', 
     10    'HayterMSAsq' 
     11] 
    612# List of models which SasView versions don't contain the explicit 'scale' argument. 
    713# When converting such a model, please update this list. 
    8 MODELS_WITHOUT_SCALE = [ 
     14MODELS_WITHOUT_SCALE = STRUCTURE_FACTORS + [ 
    915    'teubner_strey', 
    1016    'broad_peak', 
     
    1521    'be_polyelectrolyte', 
    1622    'correlation_length', 
     23    'fractal_core_shell' 
    1724    'binary_hard_sphere', 
    18     'fractal_core_shell' 
    1925] 
    2026 
    2127# List of models which SasView versions don't contain the explicit 'background' argument. 
    2228# When converting such a model, please update this list. 
    23 MODELS_WITHOUT_BACKGROUND = [ 
     29MODELS_WITHOUT_BACKGROUND = STRUCTURE_FACTORS + [ 
    2430    'guinier', 
    2531] 
     
    5258    new model definition end with sld. 
    5359    """ 
    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)) 
    5563                for p, v in pars.items()) 
    5664 
     
    7078    new model definition end with sld. 
    7179    """ 
    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)) 
    7383                for p, v in pars.items()) 
    7484 
     
    109119    return newpars 
    110120 
    111 def revert_model(model_definition, pars): 
     121def revert_pars(model_info, pars): 
    112122    """ 
    113123    Convert model from new style parameter names to old style. 
    114124    """ 
    115     mapping = model_definition.oldpars 
    116     oldname = model_definition.oldname 
     125    mapping = model_info['oldpars'] 
    117126    oldpars = _revert_pars(_unscale_sld(pars), mapping) 
    118127 
    119128    # Note: update compare.constrain_pars to match 
    120     name = model_definition.name 
     129    name = model_info['id'] 
    121130    if name in MODELS_WITHOUT_SCALE: 
    122131        if oldpars.pop('scale', 1.0) != 1.0: 
    123132            warnings.warn("parameter scale not used in sasview %s"%name) 
    124     elif name in MODELS_WITHOUT_BACKGROUND: 
     133    if name in MODELS_WITHOUT_BACKGROUND: 
    125134        if oldpars.pop('background', 0.0) != 0.0: 
    126135            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 centimeters 
    141         for p in "La", "Lb", "Lc", "Ld": 
    142             if p in oldpars: oldpars[p] *= 1e-13 
    143136 
    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 
    145154 
    146 def constrain_new_to_old(model_definition, pars): 
     155    return oldpars 
     156 
     157def constrain_new_to_old(model_info, pars): 
    147158    """ 
    148159    Restrict parameter values to those that will match sasview. 
    149160    """ 
     161    name = model_info['id'] 
    150162    # Note: update convert.revert_model to match 
    151     name = model_definition.name 
    152163    if name in MODELS_WITHOUT_SCALE: 
    153164        pars['scale'] = 1 
    154     elif name in MODELS_WITHOUT_BACKGROUND: 
     165    if name in MODELS_WITHOUT_BACKGROUND: 
    155166        pars['background'] = 0 
    156     elif name == 'pearl_necklace': 
    157         pars['string_thickness_pd_n'] = 0 
    158         pars['number_of_pearls_pd_n'] = 0 
    159     elif name == 'line': 
    160         pars['scale'] = 1 
     167    # sasview multiplies background by structure factor 
     168    if '*' in name: 
    161169        pars['background'] = 0 
    162     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, 0 
    166170 
     171    # If it is a product model P*S, then check the individual forms for special 
     172    # cases.  Note: despite the structure factor alone not having scale or 
     173    # background, the product model does, so this is below the test for 
     174    # models without scale or background. 
     175    namelist = name.split('*') if '*' in name else [name] 
     176    for name in namelist: 
     177        if name == 'pearl_necklace': 
     178            pars['string_thickness_pd_n'] = 0 
     179            pars['number_of_pearls_pd_n'] = 0 
     180        elif name == 'line': 
     181            pars['scale'] = 1 
     182            pars['background'] = 0 
     183        elif name == 'rpa': 
     184            pars['case_num'] = int(pars['case_num']) 
  • sasmodels/core.py

    rd18582e r7b3e62c  
    2121 
    2222__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", 
    2525] 
    2626 
     
    3434    return available_models 
    3535 
    36  
    37 def load_model_definition(model_name): 
    38     """ 
    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. 
    43     """ 
    44     __import__('sasmodels.models.'+model_name) 
    45     model_definition = getattr(models, model_name, None) 
    46     return model_definition 
    47  
    48  
    49 def precompile_dll(model_name, dtype="double"): 
    50     """ 
    51     Precompile the dll for a model. 
    52  
    53     Returns the path to the compiled model. 
    54  
    55     This can be used when build the windows distribution of sasmodels 
    56     (which may be missing the OpenCL driver and the dll compiler), or 
    57     otherwise sharing models with windows users who do not have a compiler. 
    58  
    59     See :func:`sasmodels.kerneldll.make_dll` for details on controlling the 
    60     dll path and the allowed floating point precision. 
    61     """ 
    62     model_definition = load_model_definition(model_name) 
    63     source, info = generate.make(model_definition) 
    64     return kerneldll.make_dll(source, info, dtype=dtype) 
    65  
    66  
    6736def isstr(s): 
    6837    """ 
     
    7342    return True 
    7443 
    75 def load_model(model_definition, dtype=None, platform="ocl"): 
     44def load_model(model_name, **kw): 
     45    """ 
     46    Load model info and build model. 
     47    """ 
     48    parts = model_name.split('+') 
     49    if len(parts) > 1: 
     50        from .mixture import MixtureModel 
     51        models = [load_model(p, **kw) for p in parts] 
     52        return MixtureModel(models) 
     53 
     54    parts = model_name.split('*') 
     55    if len(parts) > 1: 
     56        # Note: currently have circular reference 
     57        from .product import ProductModel 
     58        if len(parts) > 2: 
     59            raise ValueError("use P*S to apply structure factor S to model P") 
     60        P, Q = [load_model(p, **kw) for p in parts] 
     61        return ProductModel(P, Q) 
     62 
     63    return build_model(load_model_info(model_name), **kw) 
     64 
     65def load_model_info(model_name): 
     66    """ 
     67    Load a model definition given the model name. 
     68 
     69    This returns a handle to the module defining the model.  This can be 
     70    used with functions in generate to build the docs or extract model info. 
     71    """ 
     72    #import sys; print "\n".join(sys.path) 
     73    __import__('sasmodels.models.'+model_name) 
     74    kernel_module = getattr(models, model_name, None) 
     75    return generate.make_model_info(kernel_module) 
     76 
     77 
     78def build_model(model_info, dtype=None, platform="ocl"): 
    7679    """ 
    7780    Prepare the model for the default execution platform. 
     
    8083    on the model and the computing platform. 
    8184 
    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. 
     85    *model_info* is the model definition structure returned from 
     86    :func:`load_model_info`. 
    8587 
    8688    *dtype* indicates whether the model should use single or double precision 
     
    9395    otherwise it uses the default "ocl". 
    9496    """ 
    95     if isstr(model_definition): 
    96         model_definition = load_model_definition(model_definition) 
     97    source = generate.make_source(model_info) 
    9798    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) 
     99        dtype = 'single' if model_info['single'] else 'double' 
     100    if callable(model_info.get('Iq', None)): 
     101        return kernelpy.PyModel(model_info) 
    102102 
    103103    ## for debugging: 
     
    107107    ##  4. rerun "python -m sasmodels.direct_model $MODELNAME" 
    108108    ##  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() 
     109    # open(model_info['name']+'.c','w').write(source) 
     110    # source = open(model_info['name']+'.cl','r').read() 
    111111 
    112112    if (platform == "dll" 
    113113            or not HAVE_OPENCL 
    114114            or not kernelcl.environment().has_type(dtype)): 
    115         return kerneldll.load_dll(source, info, dtype) 
     115        return kerneldll.load_dll(source, model_info, dtype) 
    116116    else: 
    117         return kernelcl.GpuModel(source, info, dtype) 
     117        return kernelcl.GpuModel(source, model_info, dtype) 
     118 
     119def precompile_dll(model_name, dtype="double"): 
     120    """ 
     121    Precompile the dll for a model. 
     122 
     123    Returns the path to the compiled model, or None if the model is a pure 
     124    python model. 
     125 
     126    This can be used when build the windows distribution of sasmodels 
     127    (which may be missing the OpenCL driver and the dll compiler), or 
     128    otherwise sharing models with windows users who do not have a compiler. 
     129 
     130    See :func:`sasmodels.kerneldll.make_dll` for details on controlling the 
     131    dll path and the allowed floating point precision. 
     132    """ 
     133    model_info = load_model_info(model_name) 
     134    source = generate.make_source(model_info) 
     135    return kerneldll.make_dll(source, model_info, dtype=dtype) if source else None 
     136 
    118137 
    119138def make_kernel(model, q_vectors): 
     
    123142    return model(q_vectors) 
    124143 
    125 def get_weights(info, pars, name): 
     144def get_weights(model_info, pars, name): 
    126145    """ 
    127146    Generate the distribution for parameter *name* given the parameter values 
     
    131150    from the *pars* dictionary for parameter value and parameter dispersion. 
    132151    """ 
    133     relative = name in info['partype']['pd-rel'] 
    134     limits = info['limits'][name] 
     152    relative = name in model_info['partype']['pd-rel'] 
     153    limits = model_info['limits'][name] 
    135154    disperser = pars.get(name+'_pd_type', 'gaussian') 
    136     value = pars.get(name, info['defaults'][name]) 
     155    value = pars.get(name, model_info['defaults'][name]) 
    137156    npts = pars.get(name+'_pd_n', 0) 
    138157    width = pars.get(name+'_pd', 0.0) 
     
    173192    return kernel(fixed_pars, pd_pars, cutoff=cutoff) 
    174193 
     194def call_ER_VR(model_info, vol_pars): 
     195    """ 
     196    Return effect radius and volume ratio for the model. 
     197 
     198    *info* is either *kernel.info* for *kernel=make_kernel(model,q)* 
     199    or *model.info*. 
     200 
     201    *pars* are the parameters as expected by :func:`call_kernel`. 
     202    """ 
     203    ER = model_info.get('ER', None) 
     204    VR = model_info.get('VR', None) 
     205    value, weight = dispersion_mesh(vol_pars) 
     206 
     207    individual_radii = ER(*value) if ER else 1.0 
     208    whole, part = VR(*value) if VR else (1.0, 1.0) 
     209 
     210    effect_radius = np.sum(weight*individual_radii) / np.sum(weight) 
     211    volume_ratio = np.sum(weight*part)/np.sum(weight*whole) 
     212    return effect_radius, volume_ratio 
     213 
     214 
    175215def call_ER(info, pars): 
    176216    """ 
    177217    Call the model ER function using *pars*. 
    178  
    179218    *info* is either *model.info* if you have a loaded model, or *kernel.info* 
    180219    if you have a model kernel prepared for evaluation. 
     
    194233    """ 
    195234    Call the model VR function using *pars*. 
    196  
    197235    *info* is either *model.info* if you have a loaded model, or *kernel.info* 
    198236    if you have a model kernel prepared for evaluation. 
     
    208246        return np.sum(weight*part)/np.sum(weight*whole) 
    209247 
     248# TODO: remove call_ER, call_VR 
     249 
  • sasmodels/direct_model.py

    rd18582e r17bbadd  
    2525import numpy as np 
    2626 
    27 from .core import load_model_definition, load_model, make_kernel 
    28 from .core import call_kernel, call_ER, call_VR 
     27from .core import make_kernel 
     28from .core import call_kernel, call_ER_VR 
    2929from . import sesans 
    3030from . import resolution 
     
    180180        return self._calc_theory(pars, cutoff=self.cutoff) 
    181181 
    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) 
    198187 
    199188    def simulate_data(self, noise=None, **pars): 
     
    210199    import sys 
    211200    from .data import empty_data1D, empty_data2D 
     201    from .core import load_model_info, build_model 
    212202 
    213203    if len(sys.argv) < 3: 
     
    216206    model_name = sys.argv[1] 
    217207    call = sys.argv[2].upper() 
    218     if call not in ("ER", "VR"): 
     208    if call != "ER_VR": 
    219209        try: 
    220210            values = [float(v) for v in call.split(',')] 
     
    233223        data = empty_data1D([0.001])  # Data not used in ER/VR 
    234224 
    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) 
    237227    calculator = DirectModel(data, model) 
    238228    pars = dict((k, float(v)) 
    239229                for pair in sys.argv[3:] 
    240230                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)) 
    245233    else: 
    246234        Iq = calculator(**pars) 
  • sasmodels/generate.py

    r4a4ae41 r2f0c07d  
    117117    are added to the beginning of the parameter list.  They will show up 
    118118    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. 
    124126 
    125127    *source* is the list of C-99 source files that must be joined to 
     
    157159 
    158160 
    159 An *info* dictionary is constructed from the kernel meta data and 
     161An *model_info* dictionary is constructed from the kernel meta data and 
    160162returned to the caller. 
    161163 
     
    190192 
    191193The function :func:`make` loads the metadata from the module and returns 
    192 the kernel source.  The function :func:`doc` extracts the doc string 
     194the kernel source.  The function :func:`make_doc` extracts the doc string 
    193195and adds the parameter table to the top.  The function :func:`model_sources` 
    194196returns a list of files required by the model. 
     
    217219import numpy as np 
    218220 
    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"] 
    220223 
    221224C_KERNEL_TEMPLATE_PATH = joinpath(dirname(__file__), 'kernel_template.c') 
     
    232235COMMON_PARAMETERS = [ 
    233236    ["scale", "", 1, [0, np.inf], "", "Source intensity"], 
    234     ["background", "1/cm", 0, [0, np.inf], "", "Source background"], 
     237    ["background", "1/cm", 1e-3, [0, np.inf], "", "Source background"], 
    235238    ] 
    236239 
     
    327330    raise ValueError("%r not found in %s" % (filename, search_path)) 
    328331 
    329 def model_sources(info): 
     332def model_sources(model_info): 
    330333    """ 
    331334    Return a list of the sources file paths for the module. 
    332335    """ 
    333     search_path = [dirname(info['filename']), 
     336    search_path = [dirname(model_info['filename']), 
    334337                   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']] 
    336339 
    337340# Pragmas for enable OpenCL features.  Be sure to protect them so that they 
     
    391394 
    392395 
    393 def kernel_name(info, is_2d): 
     396def kernel_name(model_info, is_2d): 
    394397    """ 
    395398    Name of the exported kernel symbol. 
    396399    """ 
    397     return info['name'] + "_" + ("Iqxy" if is_2d else "Iq") 
    398  
     400    return model_info['name'] + "_" + ("Iqxy" if is_2d else "Iq") 
     401 
     402 
     403def 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 
     412LOOP_OPEN = """\ 
     413for (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""" 
     417def 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 
     435C_KERNEL_TEMPLATE = None 
     436def 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 = """\ 
     497double form_volume(VOLUME_PARAMETER_DECLARATIONS); 
     498double 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 = """\ 
     526double Iq(double q, IQ_PARAMETER_DECLARATIONS); 
     527double 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 = """\ 
     555double Iqxy(double qx, double qy, IQXY_PARAMETER_DECLARATIONS); 
     556double 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        } 
    399575 
    400576def categorize_parameters(pars): 
     
    403579 
    404580    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 
    405600    """ 
    406601    partype = { 
     
    429624    return partype 
    430625 
    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): 
     626def process_parameters(model_info): 
     627    """ 
     628    Process parameter block, precalculating parameter details. 
     629    """ 
     630    # Fill in the derived attributes 
     631    partype = categorize_parameters(model_info['parameters']) 
     632    model_info['limits'] = dict((p[0], p[3]) for p in model_info['parameters']) 
     633    model_info['partype'] = partype 
     634    model_info['defaults'] = dict((p[0], p[2]) for p in model_info['parameters']) 
     635    if model_info.get('demo', None) is None: 
     636        model_info['demo'] = model_info['defaults'] 
     637    model_info['has_2d'] = partype['orientation'] or partype['magnetic'] 
     638 
     639def make_model_info(kernel_module): 
    601640    """ 
    602641    Interpret the model definition file, categorizing the parameters. 
    603     """ 
    604     #print(kernelfile) 
    605     category = getattr(kernel_module, 'category', None) 
     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    The *model_info* structure contains the following fields: 
     648 
     649    * *id* is the id of the kernel 
     650    * *name* is the display name of the kernel 
     651    * *title* is a short description of the kernel 
     652    * *description* is a long description of the kernel (this doesn't seem 
     653      very useful since the Help button on the model page brings you directly 
     654      to the documentation page) 
     655    * *docs* is the docstring from the module.  Use :func:`make_doc` to 
     656    * *category* specifies the model location in the docs 
     657    * *parameters* is the model parameter table 
     658    * *single* is True if the model allows single precision 
     659    * *structure_factor* is True if the model is useable in a product 
     660    * *variant_info* contains the information required to select between 
     661      model variants (e.g., the list of cases) or is None if there are no 
     662      model variants 
     663    * *defaults* is the *{parameter: value}* table built from the parameter 
     664      description table. 
     665    * *limits* is the *{parameter: [min, max]}* table built from the 
     666      parameter description table. 
     667    * *partypes* categorizes the model parameters. See 
     668      :func:`categorize_parameters` for details. 
     669    * *demo* contains the *{parameter: value}* map used in compare (and maybe 
     670      for the demo plot, if plots aren't set up to use the default values). 
     671      If *demo* is not given in the file, then the default values will be used. 
     672    * *tests* is a set of tests that must pass 
     673    * *source* is the list of library files to include in the C model build 
     674    * *Iq*, *Iqxy*, *form_volume*, *ER*, *VR* and *sesans* are python functions 
     675      implementing the kernel for the module, or None if they are not 
     676      defined in python 
     677    * *oldname* is the model name in pre-4.0 Sasview 
     678    * *oldpars* is the *{new: old}* parameter translation table 
     679      from pre-4.0 Sasview 
     680    * *composition* is None if the model is independent, otherwise it is a 
     681      tuple with composition type ('product' or 'mixture') and a list of 
     682      *model_info* blocks for the composition objects.  This allows us to 
     683      build complete product and mixture models from just the info. 
     684 
     685    """ 
     686    # TODO: maybe turn model_info into a class ModelDefinition 
    606687    parameters = COMMON_PARAMETERS + kernel_module.parameters 
    607     # Default the demo parameters to the starting values for the individual 
    608     # parameters if an explicit demo parameter set has not been specified. 
    609     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) 
    612688    filename = abspath(kernel_module.__file__) 
    613689    kernel_id = splitext(basename(filename))[0] 
     
    615691    if name is None: 
    616692        name = " ".join(w.capitalize() for w in kernel_id.split('_')) 
    617     info = dict( 
     693    model_info = dict( 
    618694        id=kernel_id,  # string used to load the kernel 
    619695        filename=abspath(kernel_module.__file__), 
     
    621697        title=kernel_module.title, 
    622698        description=kernel_module.description, 
    623         category=category, 
    624699        parameters=parameters, 
    625         demo=demo_parameters, 
     700        composition=None, 
     701        docs=kernel_module.__doc__, 
     702        category=getattr(kernel_module, 'category', None), 
     703        single=getattr(kernel_module, 'single', True), 
     704        structure_factor=getattr(kernel_module, 'structure_factor', False), 
     705        variant_info=getattr(kernel_module, 'invariant_info', None), 
     706        demo=getattr(kernel_module, 'demo', None), 
    626707        source=getattr(kernel_module, 'source', []), 
    627         oldname=kernel_module.oldname, 
    628         oldpars=kernel_module.oldpars, 
     708        oldname=getattr(kernel_module, 'oldname', None), 
     709        oldpars=getattr(kernel_module, 'oldpars', {}), 
     710        tests=getattr(kernel_module, 'tests', []), 
    629711        ) 
    630     # 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 
     712    process_parameters(model_info) 
     713    # Check for optional functions 
     714    functions = "ER VR form_volume Iq Iqxy shape sesans".split() 
     715    model_info.update((k, getattr(kernel_module, k, None)) for k in functions) 
     716    return model_info 
    651717 
    652718section_marker = re.compile(r'\A(?P<first>[%s])(?P=first)*\Z' 
     
    683749    return "\n".join(_convert_section_titles_to_boldface(s.split('\n'))) 
    684750 
    685 def doc(kernel_module): 
     751def make_doc(model_info): 
    686752    """ 
    687753    Return the documentation for the model. 
     
    689755    Iq_units = "The returned value is scaled to units of |cm^-1| |sr^-1|, absolute scale." 
    690756    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']) 
    693     #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']), 
    699                  returns=Sq_units if is_Sq else Iq_units, 
     757    docs = convert_section_titles_to_boldface(model_info['docs']) 
     758    subst = dict(id=model_info['id'].replace('_', '-'), 
     759                 name=model_info['name'], 
     760                 title=model_info['title'], 
     761                 parameters=make_partable(model_info['parameters']), 
     762                 returns=Sq_units if model_info['structure_factor'] else Iq_units, 
    700763                 docs=docs) 
    701764    return DOC_HEADER % subst 
     
    710773    import datetime 
    711774    tic = datetime.datetime.now() 
    712     make(cylinder) 
     775    make_source(make_model_info(cylinder)) 
    713776    toc = (datetime.datetime.now() - tic).total_seconds() 
    714777    print("time: %g"%toc) 
     
    725788        __import__('sasmodels.models.' + name) 
    726789        model = getattr(sasmodels.models, name) 
    727         source, _ = make(model) 
     790        model_info = make_model_info(model) 
     791        source = make_source(model_info) 
    728792        print(source) 
    729793 
  • sasmodels/kernelcl.py

    re6a5556 r17bbadd  
    289289    GPU wrapper for a single model. 
    290290 
    291     *source* and *info* are the model source and interface as returned 
    292     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`. 
    293293 
    294294    *dtype* is the desired model precision.  Any numpy dtype for single 
     
    300300    that the compiler is allowed to take shortcuts. 
    301301    """ 
    302     def __init__(self, source, info, dtype=generate.F32): 
    303         self.info = info 
     302    def __init__(self, source, model_info, dtype=generate.F32): 
     303        self.info = model_info 
    304304        self.source = source 
    305305        self.dtype = generate.F32 if dtype == 'fast' else np.dtype(dtype) 
     
    356356    """ 
    357357    def __init__(self, q_vectors, dtype=generate.F32): 
     358        # TODO: do we ever need double precision q? 
    358359        env = environment() 
    359360        self.nq = q_vectors[0].size 
     
    389390    *kernel* is the GpuKernel object to call 
    390391 
    391     *info* is the module information 
     392    *model_info* is the module information 
    392393 
    393394    *q_vectors* is the q vectors at which the kernel should be evaluated 
     
    403404    Call :meth:`release` when done with the kernel instance. 
    404405    """ 
    405     def __init__(self, kernel, info, q_vectors, dtype): 
     406    def __init__(self, kernel, model_info, q_vectors, dtype): 
    406407        q_input = GpuInput(q_vectors, dtype) 
    407408        self.kernel = kernel 
    408         self.info = info 
     409        self.info = model_info 
    409410        self.res = np.empty(q_input.nq, q_input.dtype) 
    410411        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] 
    413414 
    414415        # Inputs and outputs for each kernel call 
     
    430431                else np.float32)  # will never get here, so use np.float32 
    431432 
     433        #print "pars", fixed_pars, pd_pars 
    432434        res_bi = self.res_b 
    433435        nq = np.uint32(self.q_input.nq) 
  • sasmodels/kerneldll.py

    reafc9fa r17bbadd  
    8989 
    9090 
    91 def dll_path(info, dtype="double"): 
    92     """ 
    93     Path to the compiled model defined by *info*. 
     91def dll_path(model_info, dtype="double"): 
     92    """ 
     93    Path to the compiled model defined by *model_info*. 
    9494    """ 
    9595    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] 
    9797    if np.dtype(dtype) == generate.F32: 
    9898        basename += "32" 
     
    104104 
    105105 
    106 def make_dll(source, info, dtype="double"): 
     106def make_dll(source, model_info, dtype="double"): 
    107107    """ 
    108108    Load the compiled model defined by *kernel_module*. 
     
    123123    models are allowed as DLLs. 
    124124    """ 
    125     if callable(info.get('Iq', None)): 
    126         return PyModel(info) 
     125    if callable(model_info.get('Iq', None)): 
     126        return PyModel(model_info) 
    127127 
    128128    dtype = np.dtype(dtype) 
     
    133133 
    134134    if dtype == generate.F32: # 32-bit dll 
    135         tempfile_prefix = 'sas_'+info['name']+'32_' 
     135        tempfile_prefix = 'sas_' + model_info['name'] + '32_' 
    136136    elif dtype == generate.F64: 
    137         tempfile_prefix = 'sas_'+info['name']+'64_' 
     137        tempfile_prefix = 'sas_' + model_info['name'] + '64_' 
    138138    else: 
    139         tempfile_prefix = 'sas_'+info['name']+'128_' 
     139        tempfile_prefix = 'sas_' + model_info['name'] + '128_' 
    140140 
    141141    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) 
    144144    newest = max(os.path.getmtime(f) for f in source_files) 
    145145    if not os.path.exists(dll) or os.path.getmtime(dll) < newest: 
     
    159159 
    160160 
    161 def load_dll(source, info, dtype="double"): 
     161def load_dll(source, model_info, dtype="double"): 
    162162    """ 
    163163    Create and load a dll corresponding to the source, info pair returned 
     
    167167    allowed floating point precision. 
    168168    """ 
    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) 
    171171 
    172172 
     
    178178    ctypes wrapper for a single model. 
    179179 
    180     *source* and *info* are the model source and interface as returned 
     180    *source* and *model_info* are the model source and interface as returned 
    181181    from :func:`gen.make`. 
    182182 
     
    188188    Call :meth:`release` when done with the kernel. 
    189189    """ 
    190     def __init__(self, dllpath, info, dtype=generate.F32): 
    191         self.info = info 
     190    def __init__(self, dllpath, model_info, dtype=generate.F32): 
     191        self.info = model_info 
    192192        self.dllpath = dllpath 
    193193        self.dll = None 
     
    244244    *kernel* is the c function to call. 
    245245 
    246     *info* is the module information 
     246    *model_info* is the module information 
    247247 
    248248    *q_input* is the DllInput q vectors at which the kernel should be 
     
    257257    Call :meth:`release` when done with the kernel instance. 
    258258    """ 
    259     def __init__(self, kernel, info, q_input): 
    260         self.info = info 
     259    def __init__(self, kernel, model_info, q_input): 
     260        self.info = model_info 
    261261        self.q_input = q_input 
    262262        self.kernel = kernel 
    263263        self.res = np.empty(q_input.nq, q_input.dtype) 
    264264        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] 
    267267 
    268268        # In dll kernel, but not in opencl kernel 
  • sasmodels/kernelpy.py

    reafc9fa r17bbadd  
    1616    Wrapper for pure python models. 
    1717    """ 
    18     def __init__(self, info): 
    19         self.info = info 
     18    def __init__(self, model_info): 
     19        self.info = model_info 
    2020 
    2121    def __call__(self, q_vectors): 
     
    6868    *kernel* is the DllKernel object to call. 
    6969 
    70     *info* is the module information 
     70    *model_info* is the module information 
    7171 
    7272    *q_input* is the DllInput q vectors at which the kernel should be 
     
    8181    Call :meth:`release` when done with the kernel instance. 
    8282    """ 
    83     def __init__(self, kernel, info, q_input): 
    84         self.info = info 
     83    def __init__(self, kernel, model_info, q_input): 
     84        self.info = model_info 
    8585        self.q_input = q_input 
    8686        self.res = np.empty(q_input.nq, q_input.dtype) 
     
    106106        else: 
    107107            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'] 
    111111 
    112112        # 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:]] 
    114114        offset = len(self.q_input.q_vectors) 
    115115        self.args = self.q_input.q_vectors + [None] * len(pars) 
  • sasmodels/list_pars.py

    r5c962df r17bbadd  
    1313import sys 
    1414 
    15 from .core import load_model_definition 
    16 from .generate import make_info 
     15from .core import load_model_info 
    1716from .compare import MODELS, columnize 
    1817 
     
    2524    partable = {} 
    2625    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']: 
    3028            pname = p[0] 
    3129            partable.setdefault(pname, []) 
  • sasmodels/model_test.py

    r13ed84c r17bbadd  
    5050import numpy as np 
    5151 
    52 from .core import list_models, load_model_definition, load_model, HAVE_OPENCL 
     52from .core import list_models, load_model_info, build_model, HAVE_OPENCL 
    5353from .core import make_kernel, call_kernel, call_ER, call_VR 
    5454from .exception import annotate_exception 
    5555 
     56#TODO: rename to tests so that tab completion works better for models directory 
    5657 
    5758def make_suite(loaders, models): 
     
    7677    for model_name in models: 
    7778        if model_name in skip: continue 
    78         model_definition = load_model_definition(model_name) 
     79        model_info = load_model_info(model_name) 
    7980 
    8081        #print('------') 
     
    8586        # don't try to call cl kernel since it will not be 
    8687        # available in some environmentes. 
    87         is_py = callable(getattr(model_definition, 'Iq', None)) 
     88        is_py = callable(model_info['Iq']) 
    8889 
    8990        if is_py:  # kernel implemented in python 
    9091            test_name = "Model: %s, Kernel: python"%model_name 
    9192            test_method_name = "test_%s_python" % model_name 
    92             test = ModelTestCase(test_name, model_definition, 
     93            test = ModelTestCase(test_name, model_info, 
    9394                                 test_method_name, 
    9495                                 platform="dll",  # so that 
     
    104105                # single precision.  The choice is determined by the 
    105106                # presence of *single=False* in the model file. 
    106                 test = ModelTestCase(test_name, model_definition, 
     107                test = ModelTestCase(test_name, model_info, 
    107108                                     test_method_name, 
    108109                                     platform="ocl", dtype=None) 
     
    114115                test_name = "Model: %s, Kernel: dll"%model_name 
    115116                test_method_name = "test_%s_dll" % model_name 
    116                 test = ModelTestCase(test_name, model_definition, 
     117                test = ModelTestCase(test_name, model_info, 
    117118                                     test_method_name, 
    118119                                     platform="dll", 
     
    132133        description file. 
    133134        """ 
    134         def __init__(self, test_name, definition, test_method_name, 
     135        def __init__(self, test_name, model_info, test_method_name, 
    135136                     platform, dtype): 
    136137            self.test_name = test_name 
    137             self.definition = definition 
     138            self.info = model_info 
    138139            self.platform = platform 
    139140            self.dtype = dtype 
     
    150151                ] 
    151152 
    152             tests = getattr(self.definition, 'tests', []) 
     153            tests = self.info['tests'] 
    153154            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) 
    156157                for test in smoke_tests + tests: 
    157158                    self._run_one_test(model, test) 
  • sasmodels/models/_onion.py

    rfdb1487 r2f0c07d  
    146146            \frac{j_1(qr_\text{in})}{qr_\text{in}} 
    147147 
    148 .. figure:: img/onion_annotated_profile.gif 
     148.. figure:: img/onion_geometry.gif 
    149149 
    150150    Example of an onion model profile. 
     
    159159NB: The outer most radius is used as the effective radius for $S(q)$ 
    160160when $P(q) S(q)$ is applied. 
    161  
    162 .. figure:: img/onion_1d.jpg 
    163  
    164     1D plot using the default values (w/400 point) 
    165  
    166 .. figure:: img/onion_profile.jpg 
    167  
    168     SLD profile from the default values. 
    169161 
    170162References 
     
    321313 
    322314 
    323 def profile(core_sld, core_radius, solvent_sld, n, in_sld, out_sld, thickness, A): 
     315def shape(core_sld, core_radius, solvent_sld, n, in_sld, out_sld, thickness, A): 
    324316    """ 
    325     Get SLD profile 
    326  
    327     Returns *(r, rho(r))* where *r* is the radius (Ang) and *rho(r)* is the 
    328     SLD (1/Ang^2). 
     317    SLD profile 
    329318    """ 
    330319 
  • sasmodels/models/adsorbed_layer.py

    r5b2930f r2f0c07d  
    2020 
    2121Note that all parameters except the |sigma| are correlated so fitting more than one of these parameters will generally fail. Also note that unlike other shape models, no volume normalization is applied to this model (the calculation is exact). 
    22  
    23 .. figure:: img/adsorbed_layer_1d.jpg 
    24  
    25     1D plot using the default values. 
    26  
    27 The 2D scattering intensity is calculated in the same way as the 1D, but where the *q* vector is redefined as 
    28  
    29 .. image:: img/2d_q_vector.gif 
    3022 
    3123References 
  • sasmodels/models/barbell.py

    r50e1e40 r2f0c07d  
    6868    up to you to restrict this during analysis. 
    6969 
    70 .. figure:: img/barbell_1d.jpg 
     70The 2D scattering intensity is calculated similar to the 2D cylinder model. 
    7171 
    72     1D plot using the default values (w/256 data point). 
    73  
    74 For 2D data, the scattering intensity is calculated similar to the 2D 
    75 cylinder model. 
    76  
    77 .. figure:: img/barbell_2d.jpg 
    78  
    79     2D plot (w/(256X265) data points) for $\theta = 45^\circ$ and 
    80     $\phi = 0^\circ$ with default values for the remaining parameters. 
    81  
    82 .. figure:: img/orientation.jpg 
     72.. figure:: img/cylinder_angle_definition.jpg 
    8373 
    8474    Definition of the angles for oriented 2D barbells. 
    8575 
    86 .. figure:: img/orientation2.jpg 
     76.. figure:: img/cylinder_angle_projection.jpg 
    8777 
    8878    Examples of the angles for oriented pp against the detector plane. 
  • sasmodels/models/bcc.py

    rad90df9 r2f0c07d  
    4545 
    4646 
    47 .. figure:: img/bcc_lattice.jpg 
     47.. figure:: img/bcc_geometry.jpg 
    4848 
    4949    Body-centered cubic lattice. 
     
    7777*qmin* = 0.001 |Ang^-1|, *qmax* = 0.1 |Ang^-1| and the above default values. 
    7878 
    79 .. figure:: img/bcc_1d.jpg 
    80  
    81     1D plot in the linear scale using the default values (w/200 data point). 
    82  
    8379The 2D (Anisotropic model) is based on the reference below where $I(q)$ is 
    8480approximated for 1d scattering. Thus the scattering pattern for 2D may not 
     
    8682model computation. 
    8783 
    88 .. figure:: img/crystal_orientation.png 
     84.. figure:: img/bcc_angle_definition.png 
    8985 
    9086    Orientation of the crystal with respect to the scattering plane. 
    91  
    92 .. figure:: img/bcc_2d.jpg 
    93  
    94     2D plot using the default values (w/200X200 pixels).* 
    9587 
    9688References 
  • sasmodels/models/be_polyelectrolyte.py

    r0e86967 r2f0c07d  
    3030    q = \sqrt{q_x^2 + q_y^2} 
    3131 
    32  
    33 .. figure:: img/be_polyelectrolyte_1d.jpg 
    34  
    35     1D plot using the default values (w/500 data point). 
    3632 
    3733NB: $1 barn = 10^{-24} cm^2$ 
  • sasmodels/models/broad_peak.py

    rdcdf29d r2f0c07d  
    2828    q = \sqrt{q_x^2 + q_y^2} 
    2929 
    30  
    31 .. figure:: img/broad_peak_1d.jpg 
    32  
    33     1D plot using the default values (w/200 data point). 
    3430 
    3531References 
  • sasmodels/models/capped_cylinder.py

    r50e1e40 r2f0c07d  
    6969    It is up to you to restrict this during analysis. 
    7070 
    71 :num:`Figure #capped-cylinder-1d` shows the output produced by 
    72 a running the 1D capped cylinder model, using *qmin* = 0.001 |Ang^-1|, 
    73 *qmax* = 0.7 |Ang^-1| and  the default values of the parameters. 
     71The 2D scattering intensity is calculated similar to the 2D cylinder model. 
    7472 
    75 .. _capped-cylinder-1d: 
    76  
    77 .. figure:: img/capped_cylinder_1d.jpg 
    78  
    79     1D plot using the default values (w/256 data point). 
    80  
    81 The 2D scattering intensity is calculated similar to the 2D cylinder model. 
    82 :num:`Figure #capped-cylinder-2d` shows the output for $\theta=45^\circ$ 
    83 and $\phi=0^\circ$ with default values for the other parameters. 
    84  
    85 .. _capped-cylinder-2d: 
    86  
    87 .. figure:: img/capped_cylinder_2d.jpg 
    88  
    89     2D plot (w/(256X265) data points). 
    90  
    91 .. figure:: img/orientation.jpg 
     73.. figure:: img/cylinder_angle_definition.jpg 
    9274 
    9375    Definition of the angles for oriented 2D cylinders. 
    9476 
    95 .. figure:: img/orientation2.jpg 
     77.. figure:: img/cylinder_angle_projection.jpg 
    9678 
    97     Examples of the angles for oriented pp against the detector plane. 
     79    Examples of the angles for oriented 2D cylinders against the detector plane. 
    9880 
    9981References 
  • sasmodels/models/core_shell_bicelle.py

    re7678b2 r2f0c07d  
    44---------- 
    55This model provides the form factor for a circular cylinder with a core-shell 
    6 scattering length density profile. 
    7 The form factor is normalized by the particle volume. 
     6scattering length density profile. The form factor is normalized by the 
     7particle volume. 
    88 
    99.. _core-shell-bicelle-geometry: 
     
    2121use the c-library from NIST. 
    2222 
    23 .. figure:: img/core_shell_bicelle_1d.jpg 
     23.. figure:: img/cylinder_angle_definition.jpg 
    2424 
    25     1D plot using the default values (w/200 data point). 
     25    Definition of the angles for the oriented core shell bicelle tmodel. 
    2626 
    27 .. figure:: img/core_shell_bicelle_fig1.jpg 
    28  
    29     Definition of the angles for the oriented CoreShellBicelleModel. 
    30  
    31 .. figure:: img/core_shell_bicelle_fig2.jpg 
     27.. figure:: img/cylinder_angle_projection.jpg 
    3228 
    3329    Examples of the angles for oriented pp against the detector plane. 
  • sasmodels/models/core_shell_cylinder.py

    rf0aa7f8 r2f0c07d  
    6767Validation of our code was done by comparing the output of the 1D model to 
    6868the output of the software provided by the NIST (Kline, 2006). 
    69 :num:`Figure #core-shell-cylinder-1d` shows a comparison 
    70 of the 1D output of our model and the output of the NIST software. 
    71  
    72 .. _core-shell-cylinder-1d: 
    73  
    74 .. figure:: img/core_shell_cylinder_1d.jpg 
    75  
    76     Comparison of the SasView scattering intensity for a core-shell cylinder 
    77     with the output of the NIST SANS analysis software. The parameters were 
    78     set to: *scale* = 1.0 |Ang|, *radius* = 20 |Ang|, *thickness* = 10 |Ang|, 
    79     *length* =400 |Ang|, *core_sld* =1e-6 |Ang^-2|, *shell_sld* = 4e-6 |Ang^-2|, 
    80     *solvent_sld* = 1e-6 |Ang^-2|, and *background* = 0.01 |cm^-1|. 
    8169 
    8270Averaging over a distribution of orientation is done by evaluating the 
    8371equation above. Since we have no other software to compare the 
    84 implementation of the intensity for fully oriented cylinders, we can 
    85 compare the result of averaging our 2D output using a uniform 
     72implementation of the intensity for fully oriented cylinders, we 
     73compared the result of averaging our 2D output using a uniform 
    8674distribution $p(\theta,\phi) = 1.0$. 
    87 :num:`Figure #core-shell-cylinder-2d` shows the result 
    88 of such a cross-check. 
    89  
    90 .. _core-shell-cylinder-2d: 
    91  
    92 .. figure:: img/core_shell_cylinder_2d.jpg 
    93  
    94     Comparison of the intensity for uniformly distributed core-shell 
    95     cylinders calculated from our 2D model and the intensity from the 
    96     NIST SANS analysis software. The parameters used were: *scale* = 1.0, 
    97     *radius* = 20 |Ang|, *thickness* = 10 |Ang|, *length* = 400 |Ang|, 
    98     *core_sld* = 1e-6 |Ang^-2|, *shell_sld* = 4e-6 |Ang^-2|, 
    99     *solvent_sld* = 1e-6 |Ang^-2|, and *background* = 0.0 |cm^-1|. 
    10075 
    101762013/11/26 - Description reviewed by Heenan, R. 
  • sasmodels/models/core_shell_ellipsoid.py

    r177c1a1 r2f0c07d  
    1010applied over all orientations for 1D. 
    1111 
    12 .. figure:: img/core_shell_ellipsoid_fig1.gif 
     12.. figure:: img/core_shell_ellipsoid_geometry.gif 
    1313 
    1414    The returned value is in units of $cm^{-1}$, on absolute scale. 
     
    3636To provide easy access to the orientation of the core-shell ellipsoid, 
    3737we define the axis of the solid ellipsoid using two angles $\theta$ and $\phi$. 
    38 These angles are defined on Figure 2 of the CylinderModel. 
     38These angles are defined as for 
     39:ref:`cylinder orientation <cylinder-angle-definition>`. 
    3940The contrast is defined as SLD(core) - SLD(shell) and SLD(shell) - SLD(solvent). 
    4041 
     
    4849    and used as the effective radius for *S(Q)* when $P(Q) * S(Q)$ is applied. 
    4950 
    50 .. figure:: img/core_shell_ellipsoid_1d.jpg 
    51  
    52     1D plot using the default values (w/200 data point). 
    53  
    54 .. figure:: img/core_shell_ellipsoid_fig2.jpg 
     51.. figure:: img/core_shell_ellipsoid_angle_projection.jpg 
    5552 
    5653    The angles for oriented core_shell_ellipsoid. 
  • sasmodels/models/core_shell_ellipsoid_xt.py

    r3882eeb r2f0c07d  
    1010---------- 
    1111 
    12 .. figure:: img/core_shell_ellipsoid_fig1.gif 
    13  
     12.. figure:: img/core_shell_ellipsoid_geometry.gif 
    1413 
    1514The geometric parameters of this model are 
  • sasmodels/models/core_shell_parallelepiped.py

    r44bd2be r2f0c07d  
    2222*A* < *B* < *C*. 
    2323 
    24 .. image:: img/core_shell_parallelepiped.jpg 
     24.. image:: img/core_shell_parallelepiped_geometry.jpg 
    2525 
    2626There are rectangular "slabs" of thickness $t_A$ that add to the *A* dimension 
     
    7272To provide easy access to the orientation of the parallelepiped, we define the 
    7373axis of the cylinder using three angles |theta|, |phi| and |bigpsi|. 
    74 These angles are defined on Figure 2 of the :ref:`cylinder` model. 
     74(see :ref:`cylinder orientation <cylinder-angle-definition>`). 
    7575The angle |bigpsi| is the rotational angle around the *long_c* axis against the 
    7676*q* plane. For example, |bigpsi| = 0 when the *short_b* axis is parallel to the 
    7777*x*-axis of the detector. 
    7878 
    79 .. figure:: img/parallelepiped_angles_definition.jpg 
     79.. figure:: img/parallelepiped_angle_definition.jpg 
    8080 
    8181    Definition of the angles for oriented core-shell parallelepipeds. 
    8282 
    83 .. figure:: img/parallelepiped_angles_examples.jpg 
     83.. figure:: img/parallelepiped_angle_projection.jpg 
    8484 
    8585    Examples of the angles for oriented core-shell parallelepipeds against the 
  • sasmodels/models/cylinder.py

    r50e1e40 r2f0c07d  
    3131To provide easy access to the orientation of the cylinder, we define the 
    3232axis of the cylinder using two angles $\theta$ and $\phi$. Those angles 
    33 are defined in :num:`figure #cylinder-orientation`. 
     33are defined in :num:`figure #cylinder-angle-definition`. 
    3434 
    35 .. _cylinder-orientation: 
     35.. _cylinder-angle-definition: 
    3636 
    37 .. figure:: img/orientation.jpg 
     37.. figure:: img/cylinder_angle_definition.jpg 
    3838 
    3939    Definition of the angles for oriented cylinders. 
    4040 
    41 .. figure:: img/orientation2.jpg 
     41.. figure:: img/cylinder_angle_projection.jpg 
    4242 
    4343    Examples of the angles for oriented cylinders against the detector plane. 
  • sasmodels/models/ellipsoid.py

    r431caae r2f0c07d  
    4747$S(q)$ when $P(q) \cdot S(q)$ is applied. 
    4848 
    49 .. _ellipsoid-1d: 
    50  
    51 .. figure:: img/ellipsoid_1d.jpg 
    52  
    53     The output of the 1D scattering intensity function for randomly oriented 
    54     ellipsoids given by the equation above. 
    55  
    5649 
    5750The $\theta$ and $\phi$ parameters are not used for the 1D output. 
     
    5952.. _ellipsoid-geometry: 
    6053 
    61 .. figure:: img/ellipsoid_geometry.jpg 
     54.. figure:: img/ellipsoid_angle_projection.jpg 
    6255 
    6356    The angles for oriented ellipsoid. 
  • sasmodels/models/elliptical_cylinder.py

    rfa8011eb r2f0c07d  
    4343 
    4444To provide easy access to the orientation of the elliptical cylinder, we define the axis of the cylinder using two 
    45 angles |theta|, |phi| and |bigpsi|. As for the case of the cylinder, the angles |theta| and |phi| are defined on 
    46 Figure 2 of CylinderModel. The angle |bigpsi| is the rotational angle around its own long_c axis against the *q* plane. 
     45angles |theta|, |phi| and |bigpsi| (see :ref:`cylinder orientation <cylinder-angle-definition>`). 
     46The angle |bigpsi| is the rotational angle around its own long_c axis against the *q* plane. 
    4747For example, |bigpsi| = 0 when the *r_minor* axis is parallel to the *x*\ -axis of the detector. 
    4848 
    4949All angle parameters are valid and given only for 2D calculation; ie, an oriented system. 
    5050 
    51 .. figure:: img/elliptical_cylinder_geometry_2d.jpg 
     51.. figure:: img/elliptical_cylinder_angle_definition.jpg 
    5252 
    5353    Definition of angles for 2D 
    5454 
    55 .. figure:: img/core_shell_bicelle_fig2.jpg 
     55.. figure:: img/cylinder_angle_projection.jpg 
    5656 
    5757    Examples of the angles for oriented elliptical cylinders against the detector plane. 
     
    6060and length values, and used as the effective radius for *S(Q)* when *P(Q)* \* *S(Q)* is applied. 
    6161 
    62  
    63 .. figure:: img/elliptical_cylinder_comparison_1d.jpg 
    64  
    65     1D plot using the default values (w/1000 data point). 
    6662 
    6763Validation 
  • sasmodels/models/fcc.py

    rad90df9 r2f0c07d  
    4343where $g$ is a fractional distortion based on the nearest neighbor distance. 
    4444 
    45 .. figure:: img/fcc_lattice.jpg 
     45.. figure:: img/fcc_geometry.jpg 
    4646 
    4747    Face-centered cubic lattice. 
     
    7171integral. Very, very slow. Go get lunch! 
    7272 
    73 This example dataset is produced using 200 data points, *qmin* = 0.01 |Ang^-1|, 
    74 *qmax* = 0.1 |Ang^-1| and the above default values. 
    75  
    76 .. figure:: img/fcc_1d.jpg 
    77  
    78     1D plot in the linear scale using the default values (w/200 data point). 
    79  
    8073The 2D (Anisotropic model) is based on the reference below where $I(q)$ is 
    8174approximated for 1d scattering. Thus the scattering pattern for 2D may not 
     
    83762D model computation. 
    8477 
    85 .. figure:: img/crystal_orientation.png 
     78.. figure:: img/bcc_angle_definition.png 
    8679 
    8780    Orientation of the crystal with respect to the scattering plane. 
    88  
    89 .. figure:: img/fcc_2d.jpg 
    90  
    91     2D plot using the default values (w/200X200 pixels). 
    9281 
    9382References 
  • sasmodels/models/hardsphere.py

    r97e6d3c r8e45182  
    3535from numpy import inf 
    3636 
    37 name = "hardsphere_fish" 
    38 title = "Hard sphere structure factor from FISH, with Percus-Yevick closure" 
     37name = "hardsphere" 
     38title = "Hard sphere structure factor, with Percus-Yevick closure" 
    3939description = """\ 
    4040    [Hard sphere structure factor, with Percus-Yevick closure] 
     
    4848""" 
    4949category = "structure-factor" 
     50structure_factor = True 
    5051 
    5152#             ["name", "units", default, [lower, upper], "type","description"], 
  • sasmodels/models/hollow_cylinder.py

    re0fd913 r2f0c07d  
    3434Bessel function. 
    3535 
    36 To provide easy access to the orientation of the core-shell cylinder, we define 
    37 the axis of the cylinder using two angles $\theta$ and $\phi$. As for the case 
    38 of the cylinder, those angles are defined in Figure 2 of the CylinderModel. 
    39  
    4036**NB**: The 2nd virial coefficient of the cylinder is calculated 
    4137based on the radius and 2 length values, and used as the effective radius 
     
    4541and the *radius* is $R_\text{shell}$ while *core_radius* is $R_\text{core}$. 
    4642 
    47 .. figure:: img/hollow_cylinder_1d.jpg 
    48  
    49     1D plot using the default values (w/1000 data point). 
    50  
    51 .. figure:: img/orientation.jpg 
    52  
    53     Definition of the angles for the oriented hollow_cylinder model. 
    54  
    55 .. figure:: img/orientation2.jpg 
    56  
    57     Examples of the angles for oriented pp against the detector plane. 
     43To provide easy access to the orientation of the core-shell cylinder, we define 
     44the axis of the cylinder using two angles $\theta$ and $\phi$ 
     45(see :ref:`cylinder model <cylinder-angle-definition>`). 
    5846 
    5947References 
  • sasmodels/models/lamellar.py

    reb69cce r348557a  
    9999oldname = 'LamellarModel' 
    100100oldpars = dict(sld='sld_bi', solvent_sld='sld_sol', thickness='bi_thick') 
    101  
     101tests = [ 
     102        [ {'scale': 1.0, 'background' : 0.0, 'thickness' : 50.0, 'sld' : 1.0,'solvent_sld' : 6.3, 'thickness_pd' : 0.0,  
     103           }, [0.001], [882289.54309]] 
     104        ] 
     105# ADDED by: converted by PAK? (or RKH?)     ON: 16Mar2016 - RKH adding unit tests from sasview to early 2015 conversion 
     106#  [(qx1, qy1), (qx2, qy2), ...], [I(qx1,qy1), I(qx2,qy2), ...]], 
  • sasmodels/models/linear_pearls.py

    r32c743d r2f0c07d  
    55The thickness of each string is assumed to be negligible. 
    66 
    7 .. figure:: img/linear_pearls_fig1.jpg 
     7.. figure:: img/linear_pearls_geometry.jpg 
    88 
    99 
     
    2525The 2D scattering intensity is the same as P(q) above, 
    2626regardless of the orientation of the q vector. 
    27  
    28 .. figure:: img/linear_pearls_1d.jpg 
    29  
    30     1D plot using the default values (w/500 data point). 
    3127 
    3228References 
  • sasmodels/models/mono_gauss_coil.py

    r38d2c97 r38d2c97  
    66 
    77r""" 
    8 This model strictly describes the scattering from *monodisperse* polymer chains in theta solvents or polymer melts, conditions under which the distances between segments follow a Gaussian distribution. Provided the number of segments is large (ie, high molecular weight polymers) the single-chain Form Factor P(Q) is that described by Debye (1947). 
     8This model strictly describes the scattering from *monodisperse* polymer chains in theta solvents or polymer melts, conditions under which the distances between segments follow a Gaussian distribution. Provided the number of segments is large (ie, high molecular weight polymers) the single-chain form factor P(Q) is that described by Debye (1947). 
    99 
    1010To describe the scattering from *polydisperse* polymer chains, see the poly_gauss_coil model. 
     
    1313---------- 
    1414 
    15      *I(q)* = *scale* x *P(q)* + *background* 
     15     *I(q)* = *scale* |cdot| *P(q)* + *background* 
    1616          
    1717where 
    1818 
    19      *scale* = |phi|\ :sub:`poly` x *V* x (|rho|\ :sub:`poly` - |rho|\ :sub:`solv`)\ :sup:'2' 
     19     *scale* = |phi|\ :sub:`poly` |cdot| *V* |cdot| (|rho|\ :sub:`poly` - |rho|\ :sub:`solv`)\  :sup:`2` 
    2020 
    21      *P(q)* = 2 [exp(-Z) + Z - 1] / Z\ :sup:'2' 
     21     *P(q)* = 2 [exp(-Z) + Z - 1] / Z \ :sup:`2` 
    2222          
    23          *Z* = (*q R*\ :sub:'g')\ :sup:'2' 
     23         *Z* = (*q R* \ :sub:`g`)\ :sup:`2` 
    2424 
    2525and 
    2626 
    27          *V* = *M* / (*N*\ :sub:'A' |delta|) 
     27         *V* = *M* / (*N*\ :sub:`A` |delta|) 
    2828          
    29 Here, |phi|\ :sub:`poly`, is the volume fraction of polymer, *V* is the volume of a polymer coil, *M* is the molecular weight of the polymer, *N*\ :sub:'A' is Avogadro's Number, |delta| is the bulk density of the polymer, |rho|\ :sub:`poly` is the sld of the polymer, |rho|\ :sub:`solv` is the sld of the solvent, and *R*\ :sub:'g' is the radius of gyration of the polymer coil. 
     29Here, |phi|\ :sub:`poly` is the volume fraction of polymer, *V* is the volume of a polymer coil, *M* is the molecular weight of the polymer, *N*\ :sub:`A` is Avogadro's Number, |delta| is the bulk density of the polymer, |rho|\ :sub:`poly` is the sld of the polymer, |rho|\ :sub:`solv` is the sld of the solvent, and *R*\ :sub:`g` is the radius of gyration of the polymer coil. 
    3030 
    3131.. figure:: img/mono_gauss_coil_1d.jpg 
  • sasmodels/models/multi_shell.py

    rd51ea74 r2f0c07d  
    1919parameters fixed as possible. 
    2020 
    21 .. figure:: img/multi_shell_fig1.jpg 
     21.. figure:: img/multi_shell_geometry.jpg 
    2222 
    2323The 2D scattering intensity is the same as 1D, regardless of the orientation 
     
    3333    is used as the effective radius for *S(Q)* when $P(Q) * S(Q)$ is applied. 
    3434 
    35  
    36 .. figure:: img/multi_shell_1d.jpg 
    37  
    38     1D plot using the default values (with 200 data point). 
    3935 
    4036Our model uses the form factor calculations implemented in a c-library provided 
  • sasmodels/models/parallelepiped.py

    rdeb7ee0 r2f0c07d  
    9999.. _parallelepiped-orientation: 
    100100 
    101 .. figure:: img/parallelepiped_angles_definition.jpg 
     101.. figure:: img/parallelepiped_angle_definition.jpg 
    102102 
    103103    Definition of the angles for oriented parallelepipeds. 
    104104 
    105 .. figure:: img/parallelepiped_angles_examples.jpg 
     105.. figure:: img/parallelepiped_angle_projection.jpg 
    106106 
    107107    Examples of the angles for oriented parallelepipeds against the detector plane. 
     
    156156This model is based on form factor calculations implemented in a c-library 
    157157provided by the NIST Center for Neutron Research (Kline, 2006). 
    158  
    159158""" 
    160159 
  • sasmodels/models/pearl_necklace.py

    rd18582e r2f0c07d  
    66(= *A* - 2\ *R*)). *A* is the center-to-center pearl separation distance. 
    77 
    8 .. figure:: img/pearl_fig.jpg 
     8.. figure:: img/pearl_necklace_geometry.jpg 
    99 
    1010    Pearl Necklace schematic 
     
    4848NB: *number_of_pearls* must be an integer. 
    4949 
    50 .. figure:: img/pearl_plot.jpg 
    51  
    52     1D plot using the default values (w/1000 data point). 
    53  
    54 REFERENCE 
     50References 
     51---------- 
    5552 
    5653R Schweins and K Huber, *Particle Scattering Factor of Pearl Necklace Chains*, 
  • sasmodels/models/sc_crystal.py

    rad90df9 r2f0c07d  
    4141The simple cubic lattice is 
    4242 
    43 .. figure:: img/sc_crystal_fig1.jpg 
     43.. figure:: img/sc_crystal_geometry.jpg 
    4444 
    4545For a crystal, diffraction peaks appear at reduced q-values given by 
     
    7777    Go get lunch! 
    7878 
    79 This example dataset is produced using 200 data points, 
    80 $q_{min} = 0.01A^{-1}, q_{max} = 0.1A^{-1}$ and the above default values. 
    81  
    82 .. figure:: img/sc_crystal_1d.jpg 
    83  
    84     1D plot in the linear scale using the default values (w/200 data point). 
    85  
    8679The 2D (Anisotropic model) is based on the reference below where *I(q)* is 
    8780approximated for 1d scattering. Thus the scattering pattern for 2D may not 
     
    8982model computation. 
    9083 
    91 .. figure:: img/sc_crystal_fig2.jpg 
    92 .. figure:: img/sc_crystal_fig3.jpg 
    93  
    94     2D plot using the default values (w/200X200 pixels). 
     84.. figure:: img/sc_crystal_angle_definition.jpg 
    9585 
    9686Reference 
  • sasmodels/models/stacked_disks.py

    rd507c3a r2f0c07d  
    2121---------- 
    2222 
    23 .. figure:: img/stacked_disks_fig1.gif 
     23.. figure:: img/stacked_disks_geometry.gif 
    2424 
    2525The scattered intensity $I(q)$ is calculated as 
     
    6868and $\sigma_D$ = the Gaussian standard deviation of the d-spacing (sigma_d). 
    6969 
    70 To provide easy access to the orientation of the stacked disks, we define 
    71 the axis of the cylinder using two angles $\theta$ and $\varphi$. 
    72 These angles are defined on Figure 2 of cylinder_model. 
    73  
    7470.. note:: 
    7571    The 2nd virial coefficient of the cylinder is calculated based on the 
     
    7874    is applied. 
    7975 
    80 .. figure:: img/stacked_disks_1d.jpg 
    81  
    82     1D plot using the default values (w/1000 data point). 
    83  
    84 .. figure:: img/stacked_disks_fig2.jpg 
     76To provide easy access to the orientation of the stacked disks, we define 
     77the axis of the cylinder using two angles $\theta$ and $\varphi$. 
     78 
     79.. figure:: img/stacked_disks_angle_definition.jpg 
    8580 
    8681    Examples of the angles for oriented stacked disks against 
    8782    the detector plane. 
    8883 
    89 .. figure:: img/stacked_disks_fig3.jpg 
     84.. figure:: img/stacked_disks_angle_projection.jpg 
    9085 
    9186    Examples of the angles for oriented pp against the detector plane. 
  • sasmodels/models/stickyhardsphere.py

    r13ed84c r8e45182  
    8484""" 
    8585category = "structure-factor" 
     86structure_factor = True 
    8687 
    8788single = False 
     
    122123    //C  SOLVE QUADRATIC FOR LAMBDA 
    123124    //C 
    124     qa = eta/12.0; 
    125     qb = -1.0*(stickiness + eta/etam1); 
     125    qa = eta/6.0; 
     126    qb = stickiness + eta/etam1; 
    126127    qc = (1.0 + eta/2.0)/etam1sq; 
    127     radic = qb*qb - 4.0*qa*qc; 
     128    radic = qb*qb - 2.0*qa*qc; 
    128129    if(radic<0) { 
    129130        //if(x>0.01 && x<0.015) 
     
    133134    } 
    134135    //C   KEEP THE SMALLER ROOT, THE LARGER ONE IS UNPHYSICAL 
    135     lam = (-1.0*qb-sqrt(radic))/(2.0*qa); 
    136     lam2 = (-1.0*qb+sqrt(radic))/(2.0*qa); 
     136    radic = sqrt(radic); 
     137    lam = (qb-radic)/qa; 
     138    lam2 = (qb+radic)/qa; 
    137139    if(lam2<lam) { 
    138140        lam = lam2; 
     
    186188tests = [ 
    187189        [ {'scale': 1.0, 'background' : 0.0, 'effect_radius' : 50.0, 'perturb' : 0.05, 'stickiness' : 0.2, 'volfraction' : 0.1, 
    188            'effect_radius_pd' : 0}, [0.001], [1.09718]] 
     190           'effect_radius_pd' : 0}, [0.001, 0.003], [1.09718, 1.087830]] 
    189191        ] 
    190192 
  • sasmodels/models/triaxial_ellipsoid.py

    r469e763 r2f0c07d  
    4343.. _triaxial-ellipsoid-angles: 
    4444 
    45 .. figure:: img/triaxial_ellipsoid_angles.jpg 
     45.. figure:: img/triaxial_ellipsoid_angle_projection.jpg 
    4646 
    4747    The angles for oriented ellipsoid. 
     
    5757radius $R_e = \sqrt{R_a R_b}$, and used as the effective radius for 
    5858$S(q)$ when $P(q) \cdot S(q)$ is applied. 
    59  
    60 .. figure:: img/triaxial_ellipsoid_1d.jpg 
    61  
    62     1D plot using the default values (w/1000 data point). 
    6359 
    6460Validation 
  • sasmodels/resolution.py

    r5925e90 r17bbadd  
    10611061    else: 
    10621062        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) 
    10651065 
    10661066    kernel = core.make_kernel(model, [resolution.q_calc]) 
  • sasmodels/sasview_model.py

    reafc9fa r28da77d  
    2222from . import core 
    2323 
    24 def make_class(model_definition, dtype='single', namestyle='name'): 
     24def make_class(model_info, dtype='single', namestyle='name'): 
    2525    """ 
    2626    Load the sasview model defined in *kernel_module*. 
     
    3232    compatible with SasView. 
    3333    """ 
    34     model = core.load_model(model_definition, dtype=dtype) 
     34    model = core.build_model(model_info, dtype=dtype) 
    3535    def __init__(self, multfactor=1): 
    3636        SasviewModel.__init__(self, model) 
     
    287287        pd_pars = [self._get_weights(p) for p in fn.pd_pars] 
    288288        result = fn(pars, pd_pars, self.cutoff) 
    289         fn.input.release() 
     289        fn.q_input.release() 
    290290        fn.release() 
    291291        return result 
     
    373373            self.params[par], limits[par], par in relative) 
    374374        return value, weight / np.sum(weight) 
    375  
Note: See TracChangeset for help on using the changeset viewer.