Changeset a5b8477 in sasmodels


Ignore:
Timestamp:
Apr 13, 2016 6:17:10 PM (8 years ago)
Author:
Paul Kienzle <pkienzle@…>
Branches:
master, core_shell_microgels, costrafo411, magnetic_model, release_v0.94, release_v0.95, ticket-1257-vesicle-product, ticket_1156, ticket_1265_superball, ticket_822_more_unit_tests
Children:
0ce5710
Parents:
60f03de
Message:

update docs to work with the new ModelInfo/ParameterTable? classes

Files:
11 edited

Legend:

Unmodified
Added
Removed
  • doc/genapi.py

    r3d5c6f8 ra5b8477  
    5959    #('alignment', 'GPU data alignment [unused]'), 
    6060    ('bumps_model', 'Bumps interface'), 
     61    ('compare', 'Compare models on different compute engines'), 
    6162    ('convert', 'Sasview to sasmodel converter'), 
    6263    ('core', 'Model access'), 
     64    ('data', 'Data layout and plotting routines'), 
     65    ('details', 'Parameter packing for kernel calls'), 
    6366    ('direct_model', 'Simple interface'), 
    6467    ('exception', 'Annotate exceptions'), 
     68    #('frozendict', 'Freeze a dictionary to make it immutable'), 
    6569    ('generate', 'Model parser'), 
     70    ('kernel', 'Evaluator type definitions'), 
    6671    ('kernelcl', 'OpenCL model evaluator'), 
    6772    ('kerneldll', 'Ctypes model evaluator'), 
    6873    ('kernelpy', 'Python model evaluator'), 
     74    ('list_pars', 'Identify all parameters in all models'), 
     75    ('mixture', 'Mixture model evaluator'), 
    6976    ('model_test', 'Unit test support'), 
     77    ('modelinfo', 'Parameter and model definitions'), 
     78    ('product', 'Product model evaluator'), 
    7079    ('resolution', '1-D resolution functions'), 
    7180    ('resolution2d', '2-D resolution functions'), 
    7281    ('sasview_model', 'Sasview interface'), 
    73     ('sesans', 'SESANS model evaluator'), 
     82    ('sesans', 'SESANS calculation routines'), 
     83    #('transition', 'Model stepper for automatic model selection'), 
    7484    ('weights', 'Distribution functions'), 
    75     #('transition', 'Model stepper for automatic model selection'), 
    7685] 
    7786package='sasmodels' 
  • doc/genmodel.py

    r89f4163 ra5b8477  
     1from __future__ import print_function 
     2 
    13import sys, os, math, re 
    24import numpy as np 
    35import matplotlib.pyplot as plt 
    4 import pylab 
    56sys.path.insert(0, os.path.abspath('..')) 
    67from sasmodels import generate, core 
     
    89from sasmodels.data import empty_data1D, empty_data2D 
    910 
    10  
    11 # Convert ../sasmodels/models/name.py to name 
    12 model_name = os.path.basename(sys.argv[1])[:-3] 
    13 model_info = core.load_model_info(model_name) 
    14 model = core.build_model(model_info) 
    15  
    16 # Load the doc string from the module definition file and store it in rst 
    17 docstr = generate.make_doc(model_info) 
    18  
    19  
    20 # Calculate 1D curve for default parameters 
    21 pars = dict((p.name, p.default) for p in model_info['parameters']) 
    22  
    23 # Plotting ranges and options 
    24 opts = { 
    25     'xscale'    : 'log', 
    26     'yscale'    : 'log' if not model_info['structure_factor'] else 'linear', 
    27     'zscale'    : 'log' if not model_info['structure_factor'] else 'linear', 
    28     'q_min'     : 0.001, 
    29     'q_max'     : 1.0, 
    30     'nq'        : 1000, 
    31     'nq2d'      : 1000, 
    32     'vmin'      : 1e-3,  # floor for the 2D data results 
    33     'qx_max'    : 0.5, 
    34     #'colormap'  : 'gist_ncar', 
    35     'colormap'  : 'nipy_spectral', 
    36     #'colormap'  : 'jet', 
    37 } 
    38  
     11try: 
     12    from typing import Dict, Any 
     13except ImportError: 
     14    pass 
     15else: 
     16    from matplotlib.axes import Axes 
     17    from sasmodels.kernel import KernelModel 
     18    from sasmodels.modelinfo import ModelInfo 
    3919 
    4020def plot_1d(model, opts, ax): 
     21    # type: (KernelModel, Dict[str, Any], Axes) -> None 
     22    """ 
     23    Create a 1-D image. 
     24    """ 
    4125    q_min, q_max, nq = opts['q_min'], opts['q_max'], opts['nq'] 
    4226    q_min = math.log10(q_min) 
     
    4731    Iq1D = calculator() 
    4832 
    49     ax.plot(q, Iq1D, color='blue', lw=2, label=model_info['name']) 
     33    ax.plot(q, Iq1D, color='blue', lw=2, label=model.info.name) 
    5034    ax.set_xlabel(r'$Q \/(\AA^{-1})$') 
    5135    ax.set_ylabel(r'$I(Q) \/(\mathrm{cm}^{-1})$') 
     
    5539 
    5640def plot_2d(model, opts, ax): 
     41    # type: (KernelModel, Dict[str, Any], Axes) -> None 
     42    """ 
     43    Create a 2-D image. 
     44    """ 
    5745    qx_max, nq2d = opts['qx_max'], opts['nq2d'] 
    58     q = np.linspace(-qx_max, qx_max, nq2d) 
     46    q = np.linspace(-qx_max, qx_max, nq2d) # type: np.ndarray 
    5947    data2d = empty_data2D(q, resolution=0.0) 
    6048    calculator = DirectModel(data2d, model) 
     
    6452        Iq2D = np.log(np.clip(Iq2D, opts['vmin'], np.inf)) 
    6553    ax.imshow(Iq2D, interpolation='nearest', aspect=1, origin='lower', 
    66         extent=[-qx_max, qx_max, -qx_max, qx_max], cmap=opts['colormap']) 
     54              extent=[-qx_max, qx_max, -qx_max, qx_max], cmap=opts['colormap']) 
    6755    ax.set_xlabel(r'$Q_x \/(\AA^{-1})$') 
    6856    ax.set_ylabel(r'$Q_y \/(\AA^{-1})$') 
    6957 
    70 # Generate image  
    71 fig_height = 3.0 # in 
    72 fig_left = 0.6 # in 
    73 fig_right = 0.5 # in 
    74 fig_top = 0.6*0.25 # in 
    75 fig_bottom = 0.6*0.75 
    76 if model_info['has_2d']: 
    77     plot_height = fig_height - (fig_top+fig_bottom) 
    78     plot_width = plot_height 
    79     fig_width = 2*(plot_width + fig_left + fig_right) 
    80     aspect = (fig_width, fig_height) 
    81     ratio = aspect[0]/aspect[1] 
    82     ax_left = fig_left/fig_width 
    83     ax_bottom = fig_bottom/fig_height 
    84     ax_height = plot_height/fig_height 
    85     ax_width = ax_height/ratio # square axes 
    86     fig = plt.figure(figsize=aspect) 
    87     ax2d = fig.add_axes([0.5+ax_left, ax_bottom, ax_width, ax_height]) 
    88     plot_2d(model, opts, ax2d) 
    89     ax1d = fig.add_axes([ax_left, ax_bottom, ax_width, ax_height]) 
    90     plot_1d(model, opts, ax1d) 
    91     #ax.set_aspect('square') 
    92 else: 
    93     plot_height = fig_height - (fig_top+fig_bottom) 
    94     plot_width = (1+np.sqrt(5))/2*fig_height 
    95     fig_width = plot_width + fig_left + fig_right 
    96     ax_left = fig_left/fig_width 
    97     ax_bottom = fig_bottom/fig_height 
    98     ax_width = plot_width/fig_width 
    99     ax_height = plot_height/fig_height 
    100     aspect = (fig_width, fig_height) 
    101     fig = plt.figure(figsize=aspect) 
    102     ax1d = fig.add_axes([ax_left, ax_bottom, ax_width, ax_height]) 
    103     plot_1d(model, opts, ax1d) 
     58def figfile(model_info): 
     59    # type: (ModelInfo) -> str 
     60    return model_info.id + '_autogenfig.png' 
    10461 
    105 # Save image in model/img 
    106 figname = model_name + '_autogenfig.png' 
    107 filename = os.path.join('model', 'img', figname) 
    108 plt.savefig(filename, bbox_inches='tight') 
    109 #print "figure saved in",filename 
     62def make_figure(model_info, opts): 
     63    # type: (ModelInfo, Dict[str, Any]) -> None 
     64    """ 
     65    Generate the figure file to include in the docs. 
     66    """ 
     67    model = core.build_model(model_info) 
    11068 
    111 # Auto caption for figure 
    112 captionstr = '\n' 
    113 captionstr += '.. figure:: img/' + model_info['id'] + '_autogenfig.png\n' 
    114 captionstr += '\n' 
    115 if model_info['has_2d']: 
    116     captionstr += '    1D and 2D plots corresponding to the default parameters of the model.\n' 
    117 else: 
    118     captionstr += '    1D plot corresponding to the default parameters of the model.\n' 
    119 captionstr += '\n' 
     69    fig_height = 3.0 # in 
     70    fig_left = 0.6 # in 
     71    fig_right = 0.5 # in 
     72    fig_top = 0.6*0.25 # in 
     73    fig_bottom = 0.6*0.75 
     74    if model_info.parameters.has_2d: 
     75        plot_height = fig_height - (fig_top+fig_bottom) 
     76        plot_width = plot_height 
     77        fig_width = 2*(plot_width + fig_left + fig_right) 
     78        aspect = (fig_width, fig_height) 
     79        ratio = aspect[0]/aspect[1] 
     80        ax_left = fig_left/fig_width 
     81        ax_bottom = fig_bottom/fig_height 
     82        ax_height = plot_height/fig_height 
     83        ax_width = ax_height/ratio # square axes 
     84        fig = plt.figure(figsize=aspect) 
     85        ax2d = fig.add_axes([0.5+ax_left, ax_bottom, ax_width, ax_height]) 
     86        plot_2d(model, opts, ax2d) 
     87        ax1d = fig.add_axes([ax_left, ax_bottom, ax_width, ax_height]) 
     88        plot_1d(model, opts, ax1d) 
     89        #ax.set_aspect('square') 
     90    else: 
     91        plot_height = fig_height - (fig_top+fig_bottom) 
     92        plot_width = (1+np.sqrt(5))/2*fig_height 
     93        fig_width = plot_width + fig_left + fig_right 
     94        ax_left = fig_left/fig_width 
     95        ax_bottom = fig_bottom/fig_height 
     96        ax_width = plot_width/fig_width 
     97        ax_height = plot_height/fig_height 
     98        aspect = (fig_width, fig_height) 
     99        fig = plt.figure(figsize=aspect) 
     100        ax1d = fig.add_axes([ax_left, ax_bottom, ax_width, ax_height]) 
     101        plot_1d(model, opts, ax1d) 
    120102 
    121 # Add figure reference and caption to documentation (at end, before References) 
    122 pattern = '\*\*REFERENCE' 
    123 m = re.search(pattern, docstr.upper()) 
     103    # Save image in model/img 
     104    path = os.path.join('model', 'img', figfile(model_info)) 
     105    plt.savefig(path, bbox_inches='tight') 
     106    #print("figure saved in",path) 
    124107 
    125 if m: 
    126     docstr1 = docstr[:m.start()] 
    127     docstr2 = docstr[m.start():] 
    128     docstr = docstr1 + captionstr + docstr2 
    129 else: 
    130     print '------------------------------------------------------------------' 
    131     print 'References NOT FOUND for model: ', model_info['id'] 
    132     print '------------------------------------------------------------------' 
    133     docstr = docstr + captionstr 
     108def gen_docs(model_info): 
     109    # type: (ModelInfo) -> None 
     110    """ 
     111    Generate the doc string with the figure inserted before the references. 
     112    """ 
    134113 
    135 open(sys.argv[2],'w').write(docstr) 
     114    # Load the doc string from the module definition file and store it in rst 
     115    docstr = generate.make_doc(model_info) 
     116 
     117    # Auto caption for figure 
     118    captionstr = '\n' 
     119    captionstr += '.. figure:: img/' + figfile(model_info) + '\n' 
     120    captionstr += '\n' 
     121    if model_info.parameters.has_2d: 
     122        captionstr += '    1D and 2D plots corresponding to the default parameters of the model.\n' 
     123    else: 
     124        captionstr += '    1D plot corresponding to the default parameters of the model.\n' 
     125    captionstr += '\n' 
     126 
     127    # Add figure reference and caption to documentation (at end, before References) 
     128    pattern = '\*\*REFERENCE' 
     129    match = re.search(pattern, docstr.upper()) 
     130 
     131    if match: 
     132        docstr1 = docstr[:match.start()] 
     133        docstr2 = docstr[match.start():] 
     134        docstr = docstr1 + captionstr + docstr2 
     135    else: 
     136        print('------------------------------------------------------------------') 
     137        print('References NOT FOUND for model: ', model_info.id) 
     138        print('------------------------------------------------------------------') 
     139        docstr += captionstr 
     140 
     141    open(sys.argv[2],'w').write(docstr) 
     142 
     143def process_model(path): 
     144    # type: (str) -> None 
     145    """ 
     146    Generate doc file and image file for the given model definition file. 
     147    """ 
     148 
     149    # Load the model file 
     150    model_name = os.path.basename(path)[:-3] 
     151    model_info = core.load_model_info(model_name) 
     152 
     153    # Plotting ranges and options 
     154    opts = { 
     155        'xscale'    : 'log', 
     156        'yscale'    : 'log' if not model_info.structure_factor else 'linear', 
     157        'zscale'    : 'log' if not model_info.structure_factor else 'linear', 
     158        'q_min'     : 0.001, 
     159        'q_max'     : 1.0, 
     160        'nq'        : 1000, 
     161        'nq2d'      : 1000, 
     162        'vmin'      : 1e-3,  # floor for the 2D data results 
     163        'qx_max'    : 0.5, 
     164        #'colormap'  : 'gist_ncar', 
     165        'colormap'  : 'nipy_spectral', 
     166        #'colormap'  : 'jet', 
     167    } 
     168 
     169    # Generate the RST file and the figure.  Order doesn't matter. 
     170    gen_docs(model_info) 
     171    make_figure(model_info, opts) 
     172 
     173if __name__ == "__main__": 
     174    process_model(sys.argv[1]) 
  • doc/gentoc.py

    r5041682 ra5b8477  
    99from sasmodels.core import load_model_info 
    1010 
     11try: 
     12    from typing import Optional, BinaryIO, List, Dict 
     13except ImportError: 
     14    pass 
     15else: 
     16    from sasmodels.modelinfo import ModelInfo 
    1117 
    1218TEMPLATE="""\ 
     
    2733 
    2834def _make_category(category_name, label, title, parent=None): 
     35    # type: (str, str, str, Optional[BinaryIO]) -> BinaryIO 
    2936    file = open(joinpath(MODEL_TOC_PATH, category_name+".rst"), "w") 
    3037    file.write(TEMPLATE%{'label':label, 'title':title, 'bar':'*'*len(title)}) 
     
    3441 
    3542def _add_subcategory(category_name, parent): 
     43    # type: (str, BinaryIO) -> None 
    3644    parent.write("    %s.rst\n"%category_name) 
    3745 
    3846def _add_model(file, model_name): 
     47    # type: (IO[str], str) -> None 
    3948    file.write("    ../../model/%s.rst\n"%model_name) 
    4049 
    4150def _maybe_make_category(category, models, cat_files, model_toc): 
     51    # type: (str, List[str], Dict[str, BinaryIO], BinaryIO) -> None 
    4252    if category not in cat_files: 
    4353        print("Unexpected category %s containing"%category, models, file=sys.stderr) 
     
    4656 
    4757def generate_toc(model_files): 
     58    # type: (List[str]) -> None 
    4859    if not model_files: 
    4960        print("gentoc needs a list of model files", file=sys.stderr) 
    5061 
    5162    # find all categories 
    52     category = {} 
     63    category = {} # type: Dict[str, List[str]] 
    5364    for item in model_files: 
    5465        # assume model is in sasmodels/models/name.py, and ignore the full path 
     
    5667        if model_name.startswith('_'): continue 
    5768        model_info = load_model_info(model_name) 
    58         if model_info['category'] is None: 
     69        if model_info.category is None: 
    5970            print("Missing category for", item, file=sys.stderr) 
    6071        else: 
    61             category.setdefault(model_info['category'],[]).append(model_name) 
     72            category.setdefault(model_info.category,[]).append(model_name) 
    6273 
    6374    # Check category names 
  • sasmodels/data.py

    r7ae2b7f ra5b8477  
    3737import numpy as np  # type: ignore 
    3838 
     39try: 
     40    from typing import Union, Dict, List, Optional 
     41except ImportError: 
     42    pass 
     43else: 
     44    Data = Union["Data1D", "Data2D", "SesansData"] 
     45 
    3946def load_data(filename): 
     47    # type: (str) -> Data 
    4048    """ 
    4149    Load data using a sasview loader. 
     
    5058 
    5159def set_beam_stop(data, radius, outer=None): 
     60    # type: (Data, float, Optional[float]) -> None 
    5261    """ 
    5362    Add a beam stop of the given *radius*.  If *outer*, make an annulus. 
     
    6574 
    6675def set_half(data, half): 
     76    # type: (Data, str) -> None 
    6777    """ 
    6878    Select half of the data, either "right" or "left". 
     
    7888 
    7989def set_top(data, cutoff): 
     90    # type: (Data, float) -> None 
    8091    """ 
    8192    Chop the top off the data, above *cutoff*. 
     
    114125    """ 
    115126    def __init__(self, x=None, y=None, dx=None, dy=None): 
     127        # type: (Optional[np.ndarray], Optional[np.ndarray], Optional[np.ndarray], Optional[np.ndarray]) -> None 
    116128        self.x, self.y, self.dx, self.dy = x, y, dx, dy 
    117129        self.dxl = None 
     
    127139 
    128140    def xaxis(self, label, unit): 
     141        # type: (str, str) -> None 
    129142        """ 
    130143        set the x axis label and unit 
     
    134147 
    135148    def yaxis(self, label, unit): 
     149        # type: (str, str) -> None 
    136150        """ 
    137151        set the y axis label and unit 
     
    140154        self._yunit = unit 
    141155 
    142  
     156class SesansData(Data1D): 
     157    def __init__(self, **kw): 
     158        Data1D.__init__(self, **kw) 
     159        self.lam = None # type: Optional[np.ndarray] 
    143160 
    144161class Data2D(object): 
     
    175192    """ 
    176193    def __init__(self, x=None, y=None, z=None, dx=None, dy=None, dz=None): 
     194        # type: (Optional[np.ndarray], Optional[np.ndarray], Optional[np.ndarray], Optional[np.ndarray], Optional[np.ndarray], Optional[np.ndarray]) -> None 
    177195        self.qx_data, self.dqx_data = x, dx 
    178196        self.qy_data, self.dqy_data = y, dy 
     
    197215 
    198216    def xaxis(self, label, unit): 
     217        # type: (str, str) -> None 
    199218        """ 
    200219        set the x axis label and unit 
     
    204223 
    205224    def yaxis(self, label, unit): 
     225        # type: (str, str) -> None 
    206226        """ 
    207227        set the y axis label and unit 
     
    211231 
    212232    def zaxis(self, label, unit): 
     233        # type: (str, str) -> None 
    213234        """ 
    214235        set the y axis label and unit 
     
    223244    """ 
    224245    def __init__(self, x=None, y=None, z=None): 
     246        # type: (float, float, Optional[float]) -> None 
    225247        self.x, self.y, self.z = x, y, z 
    226248 
     
    230252    """ 
    231253    def __init__(self, pixel_size=(None, None), distance=None): 
     254        # type: (Tuple[float, float], float) -> None 
    232255        self.pixel_size = Vector(*pixel_size) 
    233256        self.distance = distance 
     
    238261    """ 
    239262    def __init__(self): 
     263        # type: () -> None 
    240264        self.wavelength = np.NaN 
    241265        self.wavelength_unit = "A" 
     
    243267 
    244268def empty_data1D(q, resolution=0.0): 
     269    # type: (np.ndarray, float) -> Data1D 
    245270    """ 
    246271    Create empty 1D data using the given *q* as the x value. 
     
    259284 
    260285def empty_data2D(qx, qy=None, resolution=0.0): 
     286    # type: (np.ndarray, Optional[np.ndarray], float) -> Data2D 
    261287    """ 
    262288    Create empty 2D data using the given mesh. 
     
    272298    Qx, Qy = np.meshgrid(qx, qy) 
    273299    Qx, Qy = Qx.flatten(), Qy.flatten() 
    274     Iq = 100 * np.ones_like(Qx) 
     300    Iq = 100 * np.ones_like(Qx)  # type: np.ndarray 
    275301    dIq = np.sqrt(Iq) 
    276302    if resolution != 0: 
     
    300326 
    301327def plot_data(data, view='log', limits=None): 
     328    # type: (Data, str, Optional[Tuple[float, float]]) -> None 
    302329    """ 
    303330    Plot data loaded by the sasview loader. 
     
    323350def plot_theory(data, theory, resid=None, view='log', 
    324351                use_data=True, limits=None, Iq_calc=None): 
     352    # type: (Data, Optional[np.ndarray], Optional[np.ndarray], str, bool, Optional[Tuple[float,float]], Optional[np.ndarray]) -> None 
    325353    """ 
    326354    Plot theory calculation. 
     
    337365    *limits* sets the intensity limits on the plot; if None then the limits 
    338366    are inferred from the data. 
     367 
     368    *Iq_calc* is the raw theory values without resolution smearing 
    339369    """ 
    340370    if hasattr(data, 'lam'): 
     
    348378 
    349379def protect(fn): 
     380    # type: (Callable) -> Callable 
    350381    """ 
    351382    Decorator to wrap calls in an exception trapper which prints the 
     
    367398def _plot_result1D(data, theory, resid, view, use_data, 
    368399                   limits=None, Iq_calc=None): 
     400    # type: (Data1D, Optional[np.ndarray], Optional[np.ndarray], str, bool, Optional[Tuple[float, float]], Optional[np.ndarray]) -> None 
    369401    """ 
    370402    Plot the data and residuals for 1D data. 
     
    444476@protect 
    445477def _plot_result_sesans(data, theory, resid, use_data, limits=None): 
     478    # type: (SesansData, Optional[np.ndarray], Optional[np.ndarray], bool, Optional[Tuple[float, float]]) -> None 
    446479    """ 
    447480    Plot SESANS results. 
     
    454487 
    455488    if use_data or use_theory: 
    456         is_tof = np.any(data.lam!=data.lam[0]) 
     489        is_tof = (data.lam != data.lam[0]).any() 
    457490        if num_plots > 1: 
    458491            plt.subplot(1, num_plots, 1) 
    459492        if use_data: 
    460493            if is_tof: 
    461                 plt.errorbar(data.x, np.log(data.y)/(data.lam*data.lam), yerr=data.dy/data.y/(data.lam*data.lam)) 
     494                plt.errorbar(data.x, np.log(data.y)/(data.lam*data.lam), 
     495                             yerr=data.dy/data.y/(data.lam*data.lam)) 
    462496            else: 
    463497                plt.errorbar(data.x, data.y, yerr=data.dy) 
     
    487521@protect 
    488522def _plot_result2D(data, theory, resid, view, use_data, limits=None): 
     523    # type: (Data2D, Optional[np.ndarray], Optional[np.ndarray], str, bool, Optional[Tuple[float,float]]) -> None 
    489524    """ 
    490525    Plot the data and residuals for 2D data. 
     
    498533    # Put theory and data on a common colormap scale 
    499534    vmin, vmax = np.inf, -np.inf 
     535    target = None # type: Optional[np.ndarray] 
    500536    if use_data: 
    501537        target = data.data[~data.mask] 
     
    546582@protect 
    547583def _plot_2d_signal(data, signal, vmin=None, vmax=None, view='log'): 
     584    # type: (Data2D, np.ndarray, Optional[float], Optional[float], str) -> Tuple[float, float] 
    548585    """ 
    549586    Plot the target value for the data.  This could be the data itself, 
     
    587624 
    588625def demo(): 
     626    # type: () -> None 
    589627    """ 
    590628    Load and plot a SAS dataset. 
  • sasmodels/direct_model.py

    r7ae2b7f ra5b8477  
    3232from . import details 
    3333 
    34  
    35 def call_kernel(kernel, pars, cutoff=0, mono=False): 
     34try: 
     35    from typing import Optional, Dict, Tuple 
     36except ImportError: 
     37    pass 
     38else: 
     39    from .data import Data 
     40    from .kernel import Kernel, KernelModel 
     41    from .modelinfo import Parameter, ParameterSet 
     42 
     43def call_kernel(kernel, pars, cutoff=0., mono=False): 
     44    # type: (Kernel, ParameterSet, float, bool) -> np.ndarray 
    3645    """ 
    3746    Call *kernel* returned from *model.make_kernel* with parameters *pars*. 
     
    6473 
    6574def get_weights(parameter, values): 
     75    # type: (Parameter, Dict[str, float]) -> Tuple[np.ndarray, np.ndarray] 
    6676    """ 
    6777    Generate the distribution for parameter *name* given the parameter values 
     
    106116    """ 
    107117    def _interpret_data(self, data, model): 
     118        # type: (Data, KernelModel) -> None 
    108119        # pylint: disable=attribute-defined-outside-init 
    109120 
     
    206217 
    207218    def _set_data(self, Iq, noise=None): 
     219        # type: (np.ndarray, Optional[float]) -> None 
    208220        # pylint: disable=attribute-defined-outside-init 
    209221        if noise is not None: 
     
    223235 
    224236    def _calc_theory(self, pars, cutoff=0.0): 
     237        # type: (ParameterSet, float) -> np.ndarray 
    225238        if self._kernel is None: 
    226239            self._kernel = self._model.make_kernel(self._kernel_inputs) 
     
    258271    """ 
    259272    def __init__(self, data, model, cutoff=1e-5): 
     273        # type: (Data, KernelModel, float) -> None 
    260274        self.model = model 
    261275        self.cutoff = cutoff 
     
    264278 
    265279    def __call__(self, **pars): 
     280        # type: (**float) -> np.ndarray 
    266281        return self._calc_theory(pars, cutoff=self.cutoff) 
    267282 
    268283    def simulate_data(self, noise=None, **pars): 
     284        # type: (Optional[float], **float) -> None 
    269285        """ 
    270286        Generate simulated data for the model. 
     
    274290 
    275291def main(): 
     292    # type: () -> None 
    276293    """ 
    277294    Program to evaluate a particular model at a set of q values. 
  • sasmodels/generate.py

    r7ae2b7f ra5b8477  
    123123    polydispersity values for tests. 
    124124 
    125 An *model_info* dictionary is constructed from the kernel meta data and 
    126 returned to the caller. 
     125A :class:`modelinfo.ModelInfo` structure is constructed from the kernel meta 
     126data and returned to the caller. 
    127127 
    128128The doc string at the start of the kernel module will be used to 
     
    132132file systems are case-sensitive, so only use lower case characters for 
    133133file names and extensions. 
    134  
    135  
    136 The function :func:`make` loads the metadata from the module and returns 
    137 the kernel source.  The function :func:`make_doc` extracts the doc string 
    138 and adds the parameter table to the top.  The function :func:`model_sources` 
    139 returns a list of files required by the model. 
    140134 
    141135Code follows the C99 standard with the following extensions and conditions:: 
     
    149143    all double declarations may be converted to half, float, or long double 
    150144    FLOAT_SIZE is the number of bytes in the converted variables 
     145 
     146:func:`load_kernel_module` loads the model definition file and 
     147:modelinfo:`make_model_info` parses it. :func:`make_source` 
     148converts C-based model definitions to C source code, including the 
     149polydispersity integral.  :func:`model_sources` returns the list of 
     150source files the model depends on, and :func:`timestamp` returns 
     151the latest time stamp amongst the source files (so you can check if 
     152the model needs to be rebuilt). 
     153 
     154The function :func:`make_doc` extracts the doc string and adds the 
     155parameter table to the top.  *make_figure* in *sasmodels/doc/genmodel* 
     156creates the default figure for the model.  [These two sets of code 
     157should mignrate into docs.py so docs can be updated in one place]. 
    151158""" 
    152159from __future__ import print_function 
     
    585592    Sq_units = "The returned value is a dimensionless structure factor, $S(q)$." 
    586593    docs = convert_section_titles_to_boldface(model_info.docs) 
     594    pars = make_partable(model_info.parameters.COMMON 
     595                         + model_info.parameters.kernel_parameters) 
    587596    subst = dict(id=model_info.id.replace('_', '-'), 
    588597                 name=model_info.name, 
    589598                 title=model_info.title, 
    590                  parameters=make_partable(model_info.parameters.kernel_parameters), 
     599                 parameters=pars, 
    591600                 returns=Sq_units if model_info.structure_factor else Iq_units, 
    592601                 docs=docs) 
  • sasmodels/kernel.py

    r04dc697 ra5b8477  
    2020class KernelModel(object): 
    2121    info = None  # type: ModelInfo 
     22    dtype = None # type: np.dtype 
    2223    def make_kernel(self, q_vectors): 
    2324        # type: (List[np.ndarray]) -> "Kernel" 
  • sasmodels/kernelcl.py

    r7ae2b7f ra5b8477  
    4949""" 
    5050from __future__ import print_function 
     51 
    5152import os 
    5253import warnings 
     
    6869from . import generate 
    6970from .kernel import KernelModel, Kernel 
     71 
     72try: 
     73    from typing import Tuple, Callable, Any 
     74    from .modelinfo import ModelInfo 
     75    from .details import CallDetails 
     76except ImportError: 
     77    pass 
    7078 
    7179# The max loops number is limited by the amount of local memory available 
     
    441449    Call :meth:`release` when done with the kernel instance. 
    442450    """ 
    443     def __init__(self, kernel, model_info, q_vectors, dtype): 
    444         max_pd = model_info.max_pd 
    445         npars = len(model_info.parameters)-2 
    446         q_input = GpuInput(q_vectors, dtype) 
    447         self.dtype = dtype 
    448         self.dim = '2d' if q_input.is_2d else '1d' 
     451    def __init__(self, kernel, model_info, q_vectors): 
     452        # type: (KernelModel, ModelInfo, List[np.ndarray]) -> None 
     453        max_pd = model_info.parameters.max_pd 
     454        npars = len(model_info.parameters.kernel_parameters)-2 
     455        q_input = GpuInput(q_vectors, kernel.dtype) 
    449456        self.kernel = kernel 
    450457        self.info = model_info 
     458        self.dtype = kernel.dtype 
     459        self.dim = '2d' if q_input.is_2d else '1d' 
    451460        self.pd_stop_index = 4*max_pd-1 
    452461        # plus three for the normalization values 
     
    456465        # Note: res may be shorter than res_b if global_size != nq 
    457466        env = environment() 
    458         self.queue = env.get_queue(dtype) 
     467        self.queue = env.get_queue(kernel.dtype) 
    459468 
    460469        # details is int32 data, padded to an 8 integer boundary 
    461470        size = ((max_pd*5 + npars*3 + 2 + 7)//8)*8 
    462471        self.result_b = cl.Buffer(self.queue.context, mf.READ_WRITE, 
    463                                q_input.global_size[0] * q_input.dtype.itemsize) 
     472                               q_input.global_size[0] * kernel.dtype.itemsize) 
    464473        self.q_input = q_input # allocated by GpuInput above 
    465474 
     
    467476 
    468477    def __call__(self, call_details, weights, values, cutoff): 
     478        # type: (CallDetails, np.ndarray, np.ndarray, float) -> np.ndarray 
    469479        real = (np.float32 if self.q_input.dtype == generate.F32 
    470480                else np.float64 if self.q_input.dtype == generate.F64 
  • sasmodels/kerneldll.py

    r7ae2b7f ra5b8477  
    5555 
    5656from . import generate 
    57 from . import details 
    5857from .kernel import KernelModel, Kernel 
    5958from .kernelpy import PyInput 
     
    279278        self.dtype = q_input.dtype 
    280279        self.dim = '2d' if q_input.is_2d else '1d' 
    281         self.result = np.empty(q_input.nq+3, q_input.dtype) 
     280        self.result = np.empty(q_input.nq+1, q_input.dtype) 
     281        self.real = (np.float32 if self.q_input.dtype == generate.F32 
     282                     else np.float64 if self.q_input.dtype == generate.F64 
     283                     else np.float128) 
    282284 
    283285    def __call__(self, call_details, weights, values, cutoff): 
    284286        # type: (CallDetails, np.ndarray, np.ndarray, float) -> np.ndarray 
    285         real = (np.float32 if self.q_input.dtype == generate.F32 
    286                 else np.float64 if self.q_input.dtype == generate.F64 
    287                 else np.float128) 
    288         assert isinstance(call_details, details.CallDetails) 
    289         assert weights.dtype == real and values.dtype == real 
    290  
    291         start, stop = 0, call_details.total_pd 
     287 
    292288        #print("in kerneldll") 
    293289        #print("weights", weights) 
    294290        #print("values", values) 
     291        start, stop = 0, call_details.total_pd 
    295292        args = [ 
    296293            self.q_input.nq, # nq 
     
    302299            self.q_input.q.ctypes.data, #q 
    303300            self.result.ctypes.data,   # results 
    304             real(cutoff), # cutoff 
     301            self.real(cutoff), # cutoff 
    305302            ] 
    306303        self.kernel(*args) # type: ignore 
    307         return self.result[:-3] 
     304        return self.result[:-1] 
    308305 
    309306    def release(self): 
  • sasmodels/modelinfo.py

    r60f03de ra5b8477  
    103103                limits = (float(low), float(high)) 
    104104            except Exception: 
     105                print("user_limits",user_limits) 
    105106                raise ValueError("invalid limits for %s"%name) 
    106107            else: 
     
    278279    15 degrees). 
    279280 
    280     In the usual process these values are set by :func:`make_parameter_table` 
    281     and :func:`parse_parameter` therein. 
     281    These values are set by :func:`make_parameter_table` and 
     282    :func:`parse_parameter` therein. 
    282283    """ 
    283284    def __init__(self, name, units='', default=None, limits=(-np.inf, np.inf), 
     
    644645    info.structure_factor = getattr(kernel_module, 'structure_factor', False) 
    645646    info.profile_axes = getattr(kernel_module, 'profile_axes', ['x', 'y']) 
    646     info.variant_info = getattr(kernel_module, 'variant_info', None) 
    647647    info.source = getattr(kernel_module, 'source', []) 
    648648    # TODO: check the structure of the tests 
     
    670670    if the name is in a string. 
    671671 
    672     The *model_info* structure contains the following fields: 
    673  
    674     * *id* is the id of the kernel 
    675     * *name* is the display name of the kernel 
    676     * *filename* is the full path to the module defining the file (if any) 
    677     * *title* is a short description of the kernel 
    678     * *description* is a long description of the kernel (this doesn't seem 
    679       very useful since the Help button on the model page brings you directly 
    680       to the documentation page) 
    681     * *docs* is the docstring from the module.  Use :func:`make_doc` to 
    682     * *category* specifies the model location in the docs 
    683     * *parameters* is the model parameter table 
    684     * *single* is True if the model allows single precision 
    685     * *structure_factor* is True if the model is useable in a product 
    686     * *variant_info* contains the information required to select between 
    687       model variants (e.g., the list of cases) or is None if there are no 
    688       model variants 
    689     * *par_type* categorizes the model parameters. See 
    690       :func:`categorize_parameters` for details. 
    691     * *demo* contains the *{parameter: value}* map used in compare (and maybe 
    692       for the demo plot, if plots aren't set up to use the default values). 
    693       If *demo* is not given in the file, then the default values will be used. 
    694     * *tests* is a set of tests that must pass 
    695     * *source* is the list of library files to include in the C model build 
    696     * *Iq*, *Iqxy*, *form_volume*, *ER*, *VR* and *sesans* are python functions 
    697       implementing the kernel for the module, or None if they are not 
    698       defined in python 
    699     * *composition* is None if the model is independent, otherwise it is a 
    700       tuple with composition type ('product' or 'mixture') and a list of 
    701       *model_info* blocks for the composition objects.  This allows us to 
    702       build complete product and mixture models from just the info. 
    703     * *control* is the name of the control parameter if there is one. 
    704     * *hidden* returns the list of hidden parameters given the value of the 
    705       control parameter 
    706  
    707672    The structure should be mostly static, other than the delayed definition 
    708673    of *Iq* and *Iqxy* if they need to be defined. 
    709674    """ 
     675    #: Full path to the file defining the kernel, if any. 
     676    filename = None         # type: Optiona[str] 
     677    #: Id of the kernel used to load it from the filesystem. 
    710678    id = None               # type: str 
    711     filename = None         # type: str 
     679    #: Display name of the model, which defaults to the model id but with 
     680    #: capitalization of the parts so for example core_shell defaults to 
     681    #: "Core Shell". 
    712682    name = None             # type: str 
     683    #: Short description of the model. 
    713684    title = None            # type: str 
     685    #: Long description of the model. 
    714686    description = None      # type: str 
     687    #: Model parameter table. Parameters are defined using a list of parameter 
     688    #: definitions, each of which is contains parameter name, units, 
     689    #: default value, limits, type and description.  See :class:`Parameter` 
     690    #: for details on the individual parameters.  The parameters are gathered 
     691    #: into a :class:`ParameterTable`, which provides various views into the 
     692    #: parameter list. 
    715693    parameters = None       # type: ParameterTable 
     694    #: Demo parameters as a *parameter:value* map used as the default values 
     695    #: for :mod:`compare`.  Any parameters not set in *demo* will use the 
     696    #: defaults from the parameter table.  That means no polydispersity, and 
     697    #: in the case of multiplicity models, a minimal model with no interesting 
     698    #: scattering. 
    716699    demo = None             # type: Dict[str, float] 
     700    #: Composition is None if this is an independent model, or it is a 
     701    #: tuple with comoposition type ('product' or 'misture') and a list of 
     702    #: :class:`ModelInfo` blocks for the composed objects.  This allows us 
     703    #: to rebuild a complete mixture or product model from the info block. 
     704    #: *composition* is not given in the model definition file, but instead 
     705    #: arises when the model is constructed using names such as 
     706    #: *sphere*hardsphere* or *cylinder+sphere*. 
    717707    composition = None      # type: Optional[Tuple[str, List[ModelInfo]]] 
     708    #: Name of the control parameter for a variant model such as :ref:`rpa`. 
     709    #: The *control* parameter should appear in the parameter table, with 
     710    #: limits defined as *[CASES]*, for case names such as 
     711    #: *CASES = ["diblock copolymer", "triblock copolymer", ...]*. 
     712    #: This should give *limits=[[case1, case2, ...]]*, but the 
     713    #: model loader translates this to *limits=[0, len(CASES)-1]*, and adds 
     714    #: *choices=CASES* to the :class:`Parameter` definition. Note that 
     715    #: models can use a list of cases as a parameter without it being a 
     716    #: control parameter.  Either way, the parameter is sent to the model 
     717    #: evaluator as *float(choice_num)*, where choices are numbered from 0. 
     718    #: See also :attr:`hidden`. 
    718719    control = None          # type: str 
     720    #: Different variants require different parameters.  In order to show 
     721    #: just the parameters needed for the variant selected by :attr:`control`, 
     722    #: you should provide a function *hidden(control) -> set(['a', 'b', ...])* 
     723    #: indicating which parameters need to be hidden.  For multiplicity 
     724    #: models, you need to use the complete name of the parameter, including 
     725    #: its number.  So for example, if variant "a" uses only *sld1* and *sld2*, 
     726    #: then *sld3*, *sld4* and *sld5* of multiplicity parameter *sld[5]* 
     727    #: should be in the hidden set. 
     728    hidden = None           # type: Optional[Callable[[int], Set[str]]] 
     729    #: Doc string from the top of the model file.  This should be formatted 
     730    #: using ReStructuredText format, with latex markup in ".. math" 
     731    #: environments, or in dollar signs.  This will be automatically 
     732    #: extracted to a .rst file by :func:`generate.make_docs`, then 
     733    #: converted to HTML or PDF by Sphinx. 
    719734    docs = None             # type: str 
     735    #: Location of the model description in the documentation.  This takes the 
     736    #: form of "section" or "section:subsection".  So for example, 
     737    #: :ref:`porod` uses *category="shape-independent"* so it is in the 
     738    #: :ref:`Shape-independent` section whereas 
     739    #: :ref:`capped_cylinder` uses: *category="shape:cylinder"*, which puts 
     740    #: it in the :ref:`shape-cylinder` section. 
    720741    category = None         # type: Optional[str] 
     742    #: True if the model can be computed accurately with single precision. 
     743    #: This is True by default, but models such as :ref:`bcc_paracrystal` set 
     744    #: it to False because they require double precision calculations. 
    721745    single = None           # type: bool 
     746    #: True if the model is a structure factor used to model the interaction 
     747    #: between form factor models.  This will default to False if it is not 
     748    #: provided in the file. 
    722749    structure_factor = None # type: bool 
     750    #: List of C source files used to define the model.  The source files 
     751    #: should define the *Iq* function, and possibly *Iqxy*, though a default 
     752    #: *Iqxy = Iq(sqrt(qx**2+qy**2)* will be created if no *Iqxy* is provided. 
     753    #: Files containing the most basic functions must appear first in the list, 
     754    #: followed by the files that use those functions.  Form factors are 
     755    #: indicated by providing a :attr:`ER` function. 
     756    source = None           # type: List[str] 
     757    #: The set of tests that must pass.  The format of the tests is described 
     758    #: in :mod:`model_test`. 
     759    tests = None            # type: List[TestCondition] 
     760    #: Returns the effective radius of the model given its volume parameters. 
     761    #: The presence of *ER* indicates that the model is a form factor model 
     762    #: that may be used together with a structure factor to form an implicit 
     763    #: multiplication model. 
     764    #: 
     765    #: The parameters to the *ER* function must be marked with type *volume*. 
     766    #: in the parameter table.  They will appear in the same order as they 
     767    #: do in the table.  The values passed to *ER* will be vectors, with one 
     768    #: value for each polydispersity condition.  For example, if the model 
     769    #: is polydisperse over both length and radius, then both length and 
     770    #: radius will have the same number of values in the vector, with one 
     771    #: value for each *length X radius*.  If only *radius* is polydisperse, 
     772    #: then the value for *length* will be repeated once for each value of 
     773    #: *radius*.  The *ER* function should return one effective radius for 
     774    #: each parameter set.  Multiplicity parameters will be received as 
     775    #: arrays, with one row per polydispersity condition. 
     776    ER = None               # type: Optional[Callable[[np.ndarray], np.ndarray]] 
     777    #: Returns the occupied volume and the total volume for each parameter set. 
     778    #: See :attr:`ER` for details on the parameters. 
     779    VR = None               # type: Optional[Callable[[np.ndarray], Tuple[np.ndarray, np.ndarray]]] 
     780    #: Returns the form volume for python-based models.  Form volume is needed 
     781    #: for volume normalization in the polydispersity integral.  If no 
     782    #: parameters are *volume* parameters, then form volume is not needed. 
     783    #: For C-based models, (with :attr:`sources` defined, or with :attr:`Iq` 
     784    #: defined using a string containing C code), form_volume must also be 
     785    #: C code, either defined as a string, or in the sources. 
     786    form_volume = None      # type: Union[None, str, Callable[[np.ndarray], float]] 
     787    #: Returns *I(q, a, b, ...)* for parameters *a*, *b*, etc. defined 
     788    #: by the parameter table.  *Iq* can be defined as a python function, or 
     789    #: as a C function.  If it is defined in C, then set *Iq* to the body of 
     790    #: the C function, including the return statement.  This function takes 
     791    #: values for *q* and each of the parameters as separate *double* values 
     792    #: (which may be converted to float or long double by sasmodels).  All 
     793    #: source code files listed in :attr:`sources` will be loaded before the 
     794    #: *Iq* function is defined.  If *Iq* is not present, then sources should 
     795    #: define *static double Iq(double q, double a, double b, ...)* which 
     796    #: will return *I(q, a, b, ...)*.  Multiplicity parameters are sent as 
     797    #: pointers to doubles.  Constants in floating point expressions should 
     798    #: include the decimal point. See :mod:`generate` for more details. 
     799    Iq = None               # type: Union[None, str, Callable[[np.ndarray], np.ndarray]] 
     800    #: Returns *I(qx, qy, a, b, ...)*.  The interface follows :attr:`Iq`. 
     801    Iqxy = None             # type: Union[None, str, Callable[[np.ndarray], np.ndarray]] 
     802    #: Returns a model profile curve *x, y*.  If *profile* is defined, this 
     803    #: curve will appear in response to the *Show* button in SasView.  Use 
     804    #: :attr:`profile_axes` to set the axis labels.  Note that *y* values 
     805    #: will be scaled by 1e6 before plotting. 
     806    profile = None          # type: Optional[Callable[[np.ndarray], None]] 
     807    #: Axis labels for the :attr:`profile` plot.  The default is *['x', 'y']*. 
     808    #: Only the *x* component is used for now. 
    723809    profile_axes = None     # type: Tuple[str, str] 
    724     variant_info = None     # type: Optional[List[str]] 
    725     source = None           # type: List[str] 
    726     tests = None            # type: List[TestCondition] 
    727     ER = None               # type: Optional[Callable[[np.ndarray], np.ndarray]] 
    728     VR = None               # type: Optional[Callable[[np.ndarray], Tuple[np.ndarray, np.ndarray]]] 
    729     form_volume = None      # type: Union[None, str, Callable[[np.ndarray], float]] 
    730     Iq = None               # type: Union[None, str, Callable[[np.ndarray], np.ndarray]] 
    731     Iqxy = None             # type: Union[None, str, Callable[[np.ndarray], np.ndarray]] 
    732     profile = None          # type: Optional[Callable[[np.ndarray], None]] 
     810    #: Returns *sesans(z, a, b, ...)* for models which can directly compute 
     811    #: the SESANS correlation function.  Note: not currently implemented. 
    733812    sesans = None           # type: Optional[Callable[[np.ndarray], np.ndarray]] 
    734     hidden = None           # type: Optional[Callable[[int], Set[str]]] 
     813    #: :class:details.CallDetails data for mono-disperse function evaluation. 
     814    #: This field is created automatically by the model loader, and should 
     815    #: not be defined as part of the model definition file. 
    735816    mono_details = None     # type: CallDetails 
    736817 
     
    740821 
    741822    def get_hidden_parameters(self, control): 
     823        """ 
     824        Returns the set of hidden parameters for the model.  *control* is the 
     825        value of the control parameter.  Note that multiplicity models have 
     826        an implicit control parameter, which is the parameter that controls 
     827        the multiplicity. 
     828        """ 
    742829        if self.hidden is not None: 
    743830            hidden = self.hidden(control) 
  • sasmodels/models/rpa.py

    rea05c87 ra5b8477  
    8686#   ["name", "units", default, [lower, upper], "type","description"], 
    8787parameters = [ 
    88     ["case_num", "", 1, CASES, "", "Component organization"], 
     88    ["case_num", "", 1, [CASES], "", "Component organization"], 
    8989 
    9090    ["N[4]", "", 1000.0, [1, inf], "", "Degree of polymerization"], 
Note: See TracChangeset for help on using the changeset viewer.