source: sasmodels/sasmodels/sasview_model.py @ 1a6cd57

core_shell_microgelscostrafo411magnetic_modelticket-1257-vesicle-productticket_1156ticket_1265_superballticket_822_more_unit_tests
Last change on this file since 1a6cd57 was 1a6cd57, checked in by jhbakker, 8 years ago

commit of stuff from master from fast-merge

  • Property mode set to 100644
File size: 26.0 KB
Line 
1"""
2Sasview model constructor.
3
4Given a module defining an OpenCL kernel such as sasmodels.models.cylinder,
5create a sasview model class to run that kernel as follows::
6
7    from sasmodels.sasview_model import load_custom_model
8    CylinderModel = load_custom_model('sasmodels/models/cylinder.py')
9"""
10from __future__ import print_function
11
12import math
13from copy import deepcopy
14import collections
15import traceback
16import logging
17from os.path import basename, splitext
18
19import numpy as np  # type: ignore
20
21from . import core
22from . import custom
23from . import generate
24from . import weights
25from . import modelinfo
26from .details import make_kernel_args, dispersion_mesh
27
28try:
29    from typing import Dict, Mapping, Any, Sequence, Tuple, NamedTuple, List, Optional, Union, Callable
30    from .modelinfo import ModelInfo, Parameter
31    from .kernel import KernelModel
32    MultiplicityInfoType = NamedTuple(
33        'MuliplicityInfo',
34        [("number", int), ("control", str), ("choices", List[str]),
35         ("x_axis_label", str)])
36    SasviewModelType = Callable[[int], "SasviewModel"]
37except ImportError:
38    pass
39
40SUPPORT_OLD_STYLE_PLUGINS = True
41
42def _register_old_models():
43    # type: () -> None
44    """
45    Place the new models into sasview under the old names.
46
47    Monkey patch sas.sascalc.fit as sas.models so that sas.models.pluginmodel
48    is available to the plugin modules.
49    """
50    import sys
51    import sas
52    import sas.sascalc.fit
53    sys.modules['sas.models'] = sas.sascalc.fit
54    sas.models = sas.sascalc.fit
55
56    import sas.models
57    from sasmodels.conversion_table import CONVERSION_TABLE
58    for new_name, conversion in CONVERSION_TABLE.items():
59        old_name = conversion[0]
60        module_attrs = {old_name: find_model(new_name)}
61        ConstructedModule = type(old_name, (), module_attrs)
62        old_path = 'sas.models.' + old_name
63        setattr(sas.models, old_path, ConstructedModule)
64        sys.modules[old_path] = ConstructedModule
65
66
67# TODO: separate x_axis_label from multiplicity info
68MultiplicityInfo = collections.namedtuple(
69    'MultiplicityInfo',
70    ["number", "control", "choices", "x_axis_label"],
71)
72
73MODELS = {}
74def find_model(modelname):
75    # type: (str) -> SasviewModelType
76    """
77    Find a model by name.  If the model name ends in py, try loading it from
78    custom models, otherwise look for it in the list of builtin models.
79    """
80    # TODO: used by sum/product model to load an existing model
81    # TODO: doesn't handle custom models properly
82    if modelname.endswith('.py'):
83        return load_custom_model(modelname)
84    elif modelname in MODELS:
85        return MODELS[modelname]
86    else:
87        raise ValueError("unknown model %r"%modelname)
88
89
90# TODO: figure out how to say that the return type is a subclass
91def load_standard_models():
92    # type: () -> List[SasviewModelType]
93    """
94    Load and return the list of predefined models.
95
96    If there is an error loading a model, then a traceback is logged and the
97    model is not returned.
98    """
99    models = []
100    for name in core.list_models():
101        try:
102            MODELS[name] = _make_standard_model(name)
103            models.append(MODELS[name])
104        except Exception:
105            logging.error(traceback.format_exc())
106    if SUPPORT_OLD_STYLE_PLUGINS:
107        _register_old_models()
108
109    return models
110
111
112def load_custom_model(path):
113    # type: (str) -> SasviewModelType
114    """
115    Load a custom model given the model path.
116    """
117    kernel_module = custom.load_custom_kernel_module(path)
118    try:
119        model = kernel_module.Model
120        # Old style models do not set the name in the class attributes, so
121        # set it here; this name will be overridden when the object is created
122        # with an instance variable that has the same value.
123        if model.name == "":
124            model.name = splitext(basename(path))[0]
125        if not hasattr(model, 'filename'):
126            model.filename = kernel_module.__file__
127            # For old models, treat .pyc and .py files interchangeably.
128            # This is needed because of the Sum|Multi(p1,p2) types of models
129            # and the convoluted way in which they are created.
130            if model.filename.endswith(".py"):
131                logging.info("Loading %s as .pyc", model.filename)
132                model.filename = model.filename+'c'
133        if not hasattr(model, 'id'):
134            model.id = splitext(basename(model.filename))[0]
135    except AttributeError:
136        model_info = modelinfo.make_model_info(kernel_module)
137        model = _make_model_from_info(model_info)
138
139    # If a model name already exists and we are loading a different model,
140    # use the model file name as the model name.
141    if model.name in MODELS and not model.filename == MODELS[model.name].filename:
142        _previous_name = model.name
143        model.name = model.id
144       
145        # If the new model name is still in the model list (for instance,
146        # if we put a cylinder.py in our plug-in directory), then append
147        # an identifier.
148        if model.name in MODELS and not model.filename == MODELS[model.name].filename:
149            model.name = model.id + '_user'
150        logging.info("Model %s already exists: using %s [%s]", _previous_name, model.name, model.filename)
151
152    MODELS[model.name] = model
153    return model
154
155
156def _make_standard_model(name):
157    # type: (str) -> SasviewModelType
158    """
159    Load the sasview model defined by *name*.
160
161    *name* can be a standard model name or a path to a custom model.
162
163    Returns a class that can be used directly as a sasview model.
164    """
165    kernel_module = generate.load_kernel_module(name)
166    model_info = modelinfo.make_model_info(kernel_module)
167    return _make_model_from_info(model_info)
168
169
170def _make_model_from_info(model_info):
171    # type: (ModelInfo) -> SasviewModelType
172    """
173    Convert *model_info* into a SasView model wrapper.
174    """
175    def __init__(self, multiplicity=None):
176        SasviewModel.__init__(self, multiplicity=multiplicity)
177    attrs = _generate_model_attributes(model_info)
178    attrs['__init__'] = __init__
179    attrs['filename'] = model_info.filename
180    ConstructedModel = type(model_info.name, (SasviewModel,), attrs) # type: SasviewModelType
181    return ConstructedModel
182
183def _generate_model_attributes(model_info):
184    # type: (ModelInfo) -> Dict[str, Any]
185    """
186    Generate the class attributes for the model.
187
188    This should include all the information necessary to query the model
189    details so that you do not need to instantiate a model to query it.
190
191    All the attributes should be immutable to avoid accidents.
192    """
193
194    # TODO: allow model to override axis labels input/output name/unit
195
196    # Process multiplicity
197    non_fittable = []  # type: List[str]
198    xlabel = model_info.profile_axes[0] if model_info.profile is not None else ""
199    variants = MultiplicityInfo(0, "", [], xlabel)
200    for p in model_info.parameters.kernel_parameters:
201        if p.name == model_info.control:
202            non_fittable.append(p.name)
203            variants = MultiplicityInfo(
204                len(p.choices) if p.choices else int(p.limits[1]),
205                p.name, p.choices, xlabel
206            )
207            break
208
209    # Only a single drop-down list parameter available
210    fun_list = []
211    for p in model_info.parameters.kernel_parameters:
212        if p.choices:
213            fun_list = p.choices
214            if p.length > 1:
215                non_fittable.extend(p.id+str(k) for k in range(1, p.length+1))
216            break
217
218    # Organize parameter sets
219    orientation_params = []
220    magnetic_params = []
221    fixed = []
222    for p in model_info.parameters.user_parameters():
223        if p.type == 'orientation':
224            orientation_params.append(p.name)
225            orientation_params.append(p.name+".width")
226            fixed.append(p.name+".width")
227        elif p.type == 'magnetic':
228            orientation_params.append(p.name)
229            magnetic_params.append(p.name)
230            fixed.append(p.name+".width")
231
232
233    # Build class dictionary
234    attrs = {}  # type: Dict[str, Any]
235    attrs['_model_info'] = model_info
236    attrs['name'] = model_info.name
237    attrs['id'] = model_info.id
238    attrs['description'] = model_info.description
239    attrs['category'] = model_info.category
240    attrs['is_structure_factor'] = model_info.structure_factor
241    attrs['is_form_factor'] = model_info.ER is not None
242    attrs['is_multiplicity_model'] = variants[0] > 1
243    attrs['multiplicity_info'] = variants
244    attrs['orientation_params'] = tuple(orientation_params)
245    attrs['magnetic_params'] = tuple(magnetic_params)
246    attrs['fixed'] = tuple(fixed)
247    attrs['non_fittable'] = tuple(non_fittable)
248    attrs['fun_list'] = tuple(fun_list)
249
250    return attrs
251
252class SasviewModel(object):
253    """
254    Sasview wrapper for opencl/ctypes model.
255    """
256    # Model parameters for the specific model are set in the class constructor
257    # via the _generate_model_attributes function, which subclasses
258    # SasviewModel.  They are included here for typing and documentation
259    # purposes.
260    _model = None       # type: KernelModel
261    _model_info = None  # type: ModelInfo
262    #: load/save name for the model
263    id = None           # type: str
264    #: display name for the model
265    name = None         # type: str
266    #: short model description
267    description = None  # type: str
268    #: default model category
269    category = None     # type: str
270
271    #: names of the orientation parameters in the order they appear
272    orientation_params = None # type: Sequence[str]
273    #: names of the magnetic parameters in the order they appear
274    magnetic_params = None    # type: Sequence[str]
275    #: names of the fittable parameters
276    fixed = None              # type: Sequence[str]
277    # TODO: the attribute fixed is ill-named
278
279    # Axis labels
280    input_name = "Q"
281    input_unit = "A^{-1}"
282    output_name = "Intensity"
283    output_unit = "cm^{-1}"
284
285    #: default cutoff for polydispersity
286    cutoff = 1e-5
287
288    # Note: Use non-mutable values for class attributes to avoid errors
289    #: parameters that are not fitted
290    non_fittable = ()        # type: Sequence[str]
291
292    #: True if model should appear as a structure factor
293    is_structure_factor = False
294    #: True if model should appear as a form factor
295    is_form_factor = False
296    #: True if model has multiplicity
297    is_multiplicity_model = False
298    #: Mulitplicity information
299    multiplicity_info = None # type: MultiplicityInfoType
300
301    # Per-instance variables
302    #: parameter {name: value} mapping
303    params = None      # type: Dict[str, float]
304    #: values for dispersion width, npts, nsigmas and type
305    dispersion = None  # type: Dict[str, Any]
306    #: units and limits for each parameter
307    details = None     # type: Dict[str, Sequence[Any]]
308    #                  # actual type is Dict[str, List[str, float, float]]
309    #: multiplicity value, or None if no multiplicity on the model
310    multiplicity = None     # type: Optional[int]
311    #: memory for polydispersity array if using ArrayDispersion (used by sasview).
312    _persistency_dict = None # type: Dict[str, Tuple[np.ndarray, np.ndarray]]
313
314    def __init__(self, multiplicity=None):
315        # type: (Optional[int]) -> None
316
317        # TODO: _persistency_dict to persistency_dict throughout sasview
318        # TODO: refactor multiplicity to encompass variants
319        # TODO: dispersion should be a class
320        # TODO: refactor multiplicity info
321        # TODO: separate profile view from multiplicity
322        # The button label, x and y axis labels and scale need to be under
323        # the control of the model, not the fit page.  Maximum flexibility,
324        # the fit page would supply the canvas and the profile could plot
325        # how it wants, but this assumes matplotlib.  Next level is that
326        # we provide some sort of data description including title, labels
327        # and lines to plot.
328
329        # Get the list of hidden parameters given the mulitplicity
330        # Don't include multiplicity in the list of parameters
331        self.multiplicity = multiplicity
332        if multiplicity is not None:
333            hidden = self._model_info.get_hidden_parameters(multiplicity)
334            hidden |= set([self.multiplicity_info.control])
335        else:
336            hidden = set()
337        if self._model_info.structure_factor:
338            hidden.add('scale')
339            hidden.add('background')
340            self._model_info.parameters.defaults['background'] = 0.
341
342        self._persistency_dict = {}
343        self.params = collections.OrderedDict()
344        self.dispersion = collections.OrderedDict()
345        self.details = {}
346        for p in self._model_info.parameters.user_parameters():
347            if p.name in hidden:
348                continue
349            self.params[p.name] = p.default
350            self.details[p.id] = [p.units, p.limits[0], p.limits[1]]
351            if p.polydisperse:
352                self.details[p.id+".width"] = [
353                    "", 0.0, 1.0 if p.relative_pd else np.inf
354                ]
355                self.dispersion[p.name] = {
356                    'width': 0,
357                    'npts': 35,
358                    'nsigmas': 3,
359                    'type': 'gaussian',
360                }
361
362    def __get_state__(self):
363        # type: () -> Dict[str, Any]
364        state = self.__dict__.copy()
365        state.pop('_model')
366        # May need to reload model info on set state since it has pointers
367        # to python implementations of Iq, etc.
368        #state.pop('_model_info')
369        return state
370
371    def __set_state__(self, state):
372        # type: (Dict[str, Any]) -> None
373        self.__dict__ = state
374        self._model = None
375
376    def __str__(self):
377        # type: () -> str
378        """
379        :return: string representation
380        """
381        return self.name
382
383    def is_fittable(self, par_name):
384        # type: (str) -> bool
385        """
386        Check if a given parameter is fittable or not
387
388        :param par_name: the parameter name to check
389        """
390        return par_name in self.fixed
391        #For the future
392        #return self.params[str(par_name)].is_fittable()
393
394
395    def getProfile(self):
396        # type: () -> (np.ndarray, np.ndarray)
397        """
398        Get SLD profile
399
400        : return: (z, beta) where z is a list of depth of the transition points
401                beta is a list of the corresponding SLD values
402        """
403        args = {} # type: Dict[str, Any]
404        for p in self._model_info.parameters.kernel_parameters:
405            if p.id == self.multiplicity_info.control:
406                value = float(self.multiplicity)
407            elif p.length == 1:
408                value = self.params.get(p.id, np.NaN)
409            else:
410                value = np.array([self.params.get(p.id+str(k), np.NaN)
411                                  for k in range(1, p.length+1)])
412            args[p.id] = value
413
414        x, y = self._model_info.profile(**args)
415        return x, 1e-6*y
416
417    def setParam(self, name, value):
418        # type: (str, float) -> None
419        """
420        Set the value of a model parameter
421
422        :param name: name of the parameter
423        :param value: value of the parameter
424
425        """
426        # Look for dispersion parameters
427        toks = name.split('.')
428        if len(toks) == 2:
429            for item in self.dispersion.keys():
430                if item == toks[0]:
431                    for par in self.dispersion[item]:
432                        if par == toks[1]:
433                            self.dispersion[item][par] = value
434                            return
435        else:
436            # Look for standard parameter
437            for item in self.params.keys():
438                if item == name:
439                    self.params[item] = value
440                    return
441
442        raise ValueError("Model does not contain parameter %s" % name)
443
444    def getParam(self, name):
445        # type: (str) -> float
446        """
447        Set the value of a model parameter
448
449        :param name: name of the parameter
450
451        """
452        # Look for dispersion parameters
453        toks = name.split('.')
454        if len(toks) == 2:
455            for item in self.dispersion.keys():
456                if item == toks[0]:
457                    for par in self.dispersion[item]:
458                        if par == toks[1]:
459                            return self.dispersion[item][par]
460        else:
461            # Look for standard parameter
462            for item in self.params.keys():
463                if item == name:
464                    return self.params[item]
465
466        raise ValueError("Model does not contain parameter %s" % name)
467
468    def getParamList(self):
469        # type: () -> Sequence[str]
470        """
471        Return a list of all available parameters for the model
472        """
473        param_list = list(self.params.keys())
474        # WARNING: Extending the list with the dispersion parameters
475        param_list.extend(self.getDispParamList())
476        return param_list
477
478    def getDispParamList(self):
479        # type: () -> Sequence[str]
480        """
481        Return a list of polydispersity parameters for the model
482        """
483        # TODO: fix test so that parameter order doesn't matter
484        ret = ['%s.%s' % (p_name, ext)
485               for p_name in self.dispersion.keys()
486               for ext in ('npts', 'nsigmas', 'width')]
487        #print(ret)
488        return ret
489
490    def clone(self):
491        # type: () -> "SasviewModel"
492        """ Return a identical copy of self """
493        return deepcopy(self)
494
495    def run(self, x=0.0):
496        # type: (Union[float, (float, float), List[float]]) -> float
497        """
498        Evaluate the model
499
500        :param x: input q, or [q,phi]
501
502        :return: scattering function P(q)
503
504        **DEPRECATED**: use calculate_Iq instead
505        """
506        if isinstance(x, (list, tuple)):
507            # pylint: disable=unpacking-non-sequence
508            q, phi = x
509            return self.calculate_Iq([q*math.cos(phi)], [q*math.sin(phi)])[0]
510        else:
511            return self.calculate_Iq([x])[0]
512
513
514    def runXY(self, x=0.0):
515        # type: (Union[float, (float, float), List[float]]) -> float
516        """
517        Evaluate the model in cartesian coordinates
518
519        :param x: input q, or [qx, qy]
520
521        :return: scattering function P(q)
522
523        **DEPRECATED**: use calculate_Iq instead
524        """
525        if isinstance(x, (list, tuple)):
526            return self.calculate_Iq([x[0]], [x[1]])[0]
527        else:
528            return self.calculate_Iq([x])[0]
529
530    def evalDistribution(self, qdist):
531        # type: (Union[np.ndarray, Tuple[np.ndarray, np.ndarray], List[np.ndarray]]) -> np.ndarray
532        r"""
533        Evaluate a distribution of q-values.
534
535        :param qdist: array of q or a list of arrays [qx,qy]
536
537        * For 1D, a numpy array is expected as input
538
539        ::
540
541            evalDistribution(q)
542
543          where *q* is a numpy array.
544
545        * For 2D, a list of *[qx,qy]* is expected with 1D arrays as input
546
547        ::
548
549              qx = [ qx[0], qx[1], qx[2], ....]
550              qy = [ qy[0], qy[1], qy[2], ....]
551
552        If the model is 1D only, then
553
554        .. math::
555
556            q = \sqrt{q_x^2+q_y^2}
557
558        """
559        if isinstance(qdist, (list, tuple)):
560            # Check whether we have a list of ndarrays [qx,qy]
561            qx, qy = qdist
562            if not self._model_info.parameters.has_2d:
563                return self.calculate_Iq(np.sqrt(qx ** 2 + qy ** 2))
564            else:
565                return self.calculate_Iq(qx, qy)
566
567        elif isinstance(qdist, np.ndarray):
568            # We have a simple 1D distribution of q-values
569            return self.calculate_Iq(qdist)
570
571        else:
572            raise TypeError("evalDistribution expects q or [qx, qy], not %r"
573                            % type(qdist))
574
575    def calculate_Iq(self, qx, qy=None):
576        # type: (Sequence[float], Optional[Sequence[float]]) -> np.ndarray
577        """
578        Calculate Iq for one set of q with the current parameters.
579
580        If the model is 1D, use *q*.  If 2D, use *qx*, *qy*.
581
582        This should NOT be used for fitting since it copies the *q* vectors
583        to the card for each evaluation.
584        """
585        #core.HAVE_OPENCL = False
586        if self._model is None:
587            self._model = core.build_model(self._model_info)
588        if qy is not None:
589            q_vectors = [np.asarray(qx), np.asarray(qy)]
590        else:
591            q_vectors = [np.asarray(qx)]
592        calculator = self._model.make_kernel(q_vectors)
593        parameters = self._model_info.parameters
594        pairs = [self._get_weights(p) for p in parameters.call_parameters]
595        #weights.plot_weights(self._model_info, pairs)
596        call_details, values, is_magnetic = make_kernel_args(calculator, pairs)
597        #call_details.show()
598        #print("pairs", pairs)
599        #print("params", self.params)
600        #print("values", values)
601        #print("is_mag", is_magnetic)
602        result = calculator(call_details, values, cutoff=self.cutoff,
603                            magnetic=is_magnetic)
604        calculator.release()
605        self._model.release()
606        return result
607
608    def calculate_ER(self):
609        # type: () -> float
610        """
611        Calculate the effective radius for P(q)*S(q)
612
613        :return: the value of the effective radius
614        """
615        if self._model_info.ER is None:
616            return 1.0
617        else:
618            value, weight = self._dispersion_mesh()
619            fv = self._model_info.ER(*value)
620            #print(values[0].shape, weights.shape, fv.shape)
621            return np.sum(weight * fv) / np.sum(weight)
622
623    def calculate_VR(self):
624        # type: () -> float
625        """
626        Calculate the volf ratio for P(q)*S(q)
627
628        :return: the value of the volf ratio
629        """
630        if self._model_info.VR is None:
631            return 1.0
632        else:
633            value, weight = self._dispersion_mesh()
634            whole, part = self._model_info.VR(*value)
635            return np.sum(weight * part) / np.sum(weight * whole)
636
637    def set_dispersion(self, parameter, dispersion):
638        # type: (str, weights.Dispersion) -> Dict[str, Any]
639        """
640        Set the dispersion object for a model parameter
641
642        :param parameter: name of the parameter [string]
643        :param dispersion: dispersion object of type Dispersion
644        """
645        if parameter in self.params:
646            # TODO: Store the disperser object directly in the model.
647            # The current method of relying on the sasview GUI to
648            # remember them is kind of funky.
649            # Note: can't seem to get disperser parameters from sasview
650            # (1) Could create a sasview model that has not yet been
651            # converted, assign the disperser to one of its polydisperse
652            # parameters, then retrieve the disperser parameters from the
653            # sasview model.
654            # (2) Could write a disperser parameter retriever in sasview.
655            # (3) Could modify sasview to use sasmodels.weights dispersers.
656            # For now, rely on the fact that the sasview only ever uses
657            # new dispersers in the set_dispersion call and create a new
658            # one instead of trying to assign parameters.
659            self.dispersion[parameter] = dispersion.get_pars()
660        else:
661            raise ValueError("%r is not a dispersity or orientation parameter")
662
663    def _dispersion_mesh(self):
664        # type: () -> List[Tuple[np.ndarray, np.ndarray]]
665        """
666        Create a mesh grid of dispersion parameters and weights.
667
668        Returns [p1,p2,...],w where pj is a vector of values for parameter j
669        and w is a vector containing the products for weights for each
670        parameter set in the vector.
671        """
672        pars = [self._get_weights(p)
673                for p in self._model_info.parameters.call_parameters
674                if p.type == 'volume']
675        return dispersion_mesh(self._model_info, pars)
676
677    def _get_weights(self, par):
678        # type: (Parameter) -> Tuple[np.ndarray, np.ndarray]
679        """
680        Return dispersion weights for parameter
681        """
682        if par.name not in self.params:
683            if par.name == self.multiplicity_info.control:
684                return [self.multiplicity], [1.0]
685            else:
686                # For hidden parameters use the default value.
687                value = self._model_info.parameters.defaults.get(par.name, np.NaN)
688                return [value], [1.0]
689        elif par.polydisperse:
690            dis = self.dispersion[par.name]
691            if dis['type'] == 'array':
692                value, weight = dis['values'], dis['weights']
693            else:
694                value, weight = weights.get_weights(
695                    dis['type'], dis['npts'], dis['width'], dis['nsigmas'],
696                    self.params[par.name], par.limits, par.relative_pd)
697            return value, weight / np.sum(weight)
698        else:
699            return [self.params[par.name]], [1.0]
700
701def test_model():
702    # type: () -> float
703    """
704    Test that a sasview model (cylinder) can be run.
705    """
706    Cylinder = _make_standard_model('cylinder')
707    cylinder = Cylinder()
708    return cylinder.evalDistribution([0.1, 0.1])
709
710def test_structure_factor():
711    # type: () -> float
712    """
713    Test that a sasview model (cylinder) can be run.
714    """
715    Model = _make_standard_model('hardsphere')
716    model = Model()
717    value = model.evalDistribution([0.1, 0.1])
718    if np.isnan(value):
719        raise ValueError("hardsphere returns null")
720
721def test_rpa():
722    # type: () -> float
723    """
724    Test that a sasview model (cylinder) can be run.
725    """
726    RPA = _make_standard_model('rpa')
727    rpa = RPA(3)
728    return rpa.evalDistribution([0.1, 0.1])
729
730
731def test_model_list():
732    # type: () -> None
733    """
734    Make sure that all models build as sasview models.
735    """
736    from .exception import annotate_exception
737    for name in core.list_models():
738        try:
739            _make_standard_model(name)
740        except:
741            annotate_exception("when loading "+name)
742            raise
743
744def test_old_name():
745    # type: () -> None
746    """
747    Load and run cylinder model from sas.models.CylinderModel
748    """
749    if not SUPPORT_OLD_STYLE_PLUGINS:
750        return
751    try:
752        # if sasview is not on the path then don't try to test it
753        import sas
754    except ImportError:
755        return
756    load_standard_models()
757    from sas.models.CylinderModel import CylinderModel
758    CylinderModel().evalDistribution([0.1, 0.1])
759
760if __name__ == "__main__":
761    print("cylinder(0.1,0.1)=%g"%test_model())
Note: See TracBrowser for help on using the repository browser.