source: sasmodels/sasmodels/core.py @ fa5fd8d

core_shell_microgelscostrafo411magnetic_modelrelease_v0.94release_v0.95ticket-1257-vesicle-productticket_1156ticket_1265_superballticket_822_more_unit_tests
Last change on this file since fa5fd8d was fa5fd8d, checked in by Paul Kienzle <pkienzle@…>, 8 years ago

support number of shells selection in sasview wrapper for onion model

  • Property mode set to 100644
File size: 6.1 KB
Line 
1"""
2Core model handling routines.
3"""
4from __future__ import print_function
5
6__all__ = [
7    "list_models", "load_model", "load_model_info",
8    "build_model", "precompile_dll",
9    ]
10
11from os.path import basename, dirname, join as joinpath
12from glob import glob
13
14import numpy as np # type: ignore
15
16from . import generate
17from . import modelinfo
18from . import product
19from . import mixture
20from . import kernelpy
21from . import kerneldll
22try:
23    from . import kernelcl
24    HAVE_OPENCL = True
25except Exception:
26    HAVE_OPENCL = False
27
28try:
29    from typing import List, Union, Optional, Any
30    DType = Union[None, str, np.dtype]
31    from .kernel import KernelModel
32except ImportError:
33    pass
34
35
36# TODO: refactor composite model support
37# The current load_model_info/build_model does not reuse existing model
38# definitions when loading a composite model, instead reloading and
39# rebuilding the kernel for each component model in the expression.  This
40# is fine in a scripting environment where the model is built when the script
41# starts and is thrown away when the script ends, but may not be the best
42# solution in a long-lived application.  This affects the following functions:
43#
44#    load_model
45#    load_model_info
46#    build_model
47
48def list_models():
49    # type: () -> List[str]
50    """
51    Return the list of available models on the model path.
52    """
53    root = dirname(__file__)
54    files = sorted(glob(joinpath(root, 'models', "[a-zA-Z]*.py")))
55    available_models = [basename(f)[:-3] for f in files]
56    return available_models
57
58def isstr(s):
59    # type: (Any) -> bool
60    """
61    Return True if *s* is a string-like object.
62    """
63    try: s + ''
64    except Exception: return False
65    return True
66
67def load_model(model_name, dtype=None, platform='ocl'):
68    # type: (str, DType, str) -> KernelModel
69    """
70    Load model info and build model.
71
72    *model_name* is the name of the model as used by :func:`load_model_info`.
73    Additional keyword arguments are passed directly to :func:`build_model`.
74    """
75    return build_model(load_model_info(model_name),
76                       dtype=dtype, platform=platform)
77
78
79def load_model_info(model_name):
80    # type: (str) -> modelinfo.ModelInfo
81    """
82    Load a model definition given the model name.
83
84    This returns a handle to the module defining the model.  This can be
85    used with functions in generate to build the docs or extract model info.
86    """
87    parts = model_name.split('+')
88    if len(parts) > 1:
89        model_info_list = [load_model_info(p) for p in parts]
90        return mixture.make_mixture_info(model_info_list)
91
92    parts = model_name.split('*')
93    if len(parts) > 1:
94        if len(parts) > 2:
95            raise ValueError("use P*S to apply structure factor S to model P")
96        P_info, Q_info = [load_model_info(p) for p in parts]
97        return product.make_product_info(P_info, Q_info)
98
99    kernel_module = generate.load_kernel_module(model_name)
100    return modelinfo.make_model_info(kernel_module)
101
102
103def build_model(model_info, dtype=None, platform="ocl"):
104    # type: (modelinfo.ModelInfo, np.dtype, str) -> KernelModel
105    """
106    Prepare the model for the default execution platform.
107
108    This will return an OpenCL model, a DLL model or a python model depending
109    on the model and the computing platform.
110
111    *model_info* is the model definition structure returned from
112    :func:`load_model_info`.
113
114    *dtype* indicates whether the model should use single or double precision
115    for the calculation. Any valid numpy single or double precision identifier
116    is valid, such as 'single', 'f', 'f32', or np.float32 for single, or
117    'double', 'd', 'f64'  and np.float64 for double.  If *None*, then use
118    'single' unless the model defines single=False.
119
120    *platform* should be "dll" to force the dll to be used for C models,
121    otherwise it uses the default "ocl".
122    """
123    composition = model_info.composition
124    if composition is not None:
125        composition_type, parts = composition
126        models = [build_model(p, dtype=dtype, platform=platform) for p in parts]
127        if composition_type == 'mixture':
128            return mixture.MixtureModel(model_info, models)
129        elif composition_type == 'product':
130            from . import product
131            P, S = models
132            return product.ProductModel(model_info, P, S)
133        else:
134            raise ValueError('unknown mixture type %s'%composition_type)
135
136    # If it is a python model, return it immediately
137    if callable(model_info.Iq):
138        return kernelpy.PyModel(model_info)
139
140    ## for debugging:
141    ##  1. uncomment open().write so that the source will be saved next time
142    ##  2. run "python -m sasmodels.direct_model $MODELNAME" to save the source
143    ##  3. recomment the open.write() and uncomment open().read()
144    ##  4. rerun "python -m sasmodels.direct_model $MODELNAME"
145    ##  5. uncomment open().read() so that source will be regenerated from model
146    # open(model_info.name+'.c','w').write(source)
147    # source = open(model_info.name+'.cl','r').read()
148    source = generate.make_source(model_info)
149    if dtype is None:
150        dtype = generate.F32 if model_info.single else generate.F64
151    if (platform == "dll"
152            or not HAVE_OPENCL
153            or not kernelcl.environment().has_type(dtype)):
154        return kerneldll.load_dll(source, model_info, dtype)
155    else:
156        return kernelcl.GpuModel(source, model_info, dtype)
157
158def precompile_dll(model_name, dtype="double"):
159    # type: (str, DType) -> Optional[str]
160    """
161    Precompile the dll for a model.
162
163    Returns the path to the compiled model, or None if the model is a pure
164    python model.
165
166    This can be used when build the windows distribution of sasmodels
167    (which may be missing the OpenCL driver and the dll compiler), or
168    otherwise sharing models with windows users who do not have a compiler.
169
170    See :func:`sasmodels.kerneldll.make_dll` for details on controlling the
171    dll path and the allowed floating point precision.
172    """
173    model_info = load_model_info(model_name)
174    source = generate.make_source(model_info)
175    return kerneldll.make_dll(source, model_info, dtype=dtype) if source else None
Note: See TracBrowser for help on using the repository browser.