source: sasmodels/sasmodels/core.py @ 6d6508e

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

refactor model_info from dictionary to class

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