source: sasmodels/sasmodels/sasview_model.py @ e7fe459

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

spherical sld: sasview assumes profile needs to be scaled by 1e6

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