source: sasmodels/sasmodels/mixture.py @ 7ae2b7f

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

still more linting; ignore numpy types

  • Property mode set to 100644
File size: 4.2 KB
RevLine 
[72a081d]1"""
2Mixture model
3-------------
4
5The product model multiplies the structure factor by the form factor,
6modulated by the effective radius of the form.  The resulting model
7has a attributes of both the model description (with parameters, etc.)
8and the module evaluator (with call, release, etc.).
9
10To use it, first load form factor P and structure factor S, then create
11*ProductModel(P, S)*.
12"""
13from copy import copy
[7ae2b7f]14import numpy as np  # type: ignore
[72a081d]15
[6d6508e]16from .modelinfo import Parameter, ParameterTable, ModelInfo
[f619de7]17from .kernel import KernelModel, Kernel
18
19try:
20    from typing import List
21    from .details import CallDetails
22except ImportError:
23    pass
[72a081d]24
25def make_mixture_info(parts):
[f619de7]26    # type: (List[ModelInfo]) -> ModelInfo
[72a081d]27    """
28    Create info block for product model.
29    """
30    flatten = []
31    for part in parts:
[f619de7]32        if part.composition and part.composition[0] == 'mixture':
33            flatten.extend(part.composition[1])
[72a081d]34        else:
35            flatten.append(part)
36    parts = flatten
37
38    # Build new parameter list
[f619de7]39    combined_pars = []
[72a081d]40    for k, part in enumerate(parts):
41        # Parameter prefix per model, A_, B_, ...
[69aa451]42        # Note that prefix must also be applied to id and length_control
43        # to support vector parameters
[72a081d]44        prefix = chr(ord('A')+k) + '_'
[f619de7]45        combined_pars.append(Parameter(prefix+'scale'))
46        for p in part.parameters.kernel_parameters:
[69aa451]47            p = copy(p)
[f619de7]48            p.name = prefix + p.name
49            p.id = prefix + p.id
[69aa451]50            if p.length_control is not None:
[f619de7]51                p.length_control = prefix + p.length_control
52            combined_pars.append(p)
53    parameters = ParameterTable(combined_pars)
[72a081d]54
[6d6508e]55    model_info = ModelInfo()
[f619de7]56    model_info.id = '+'.join(part.id for part in parts)
57    model_info.name = ' + '.join(part.name for part in parts)
[6d6508e]58    model_info.filename = None
59    model_info.title = 'Mixture model with ' + model_info.name
60    model_info.description = model_info.title
61    model_info.docs = model_info.title
62    model_info.category = "custom"
[f619de7]63    model_info.parameters = parameters
[6d6508e]64    #model_info.single = any(part['single'] for part in parts)
65    model_info.structure_factor = False
66    model_info.variant_info = None
67    #model_info.tests = []
68    #model_info.source = []
[72a081d]69    # Iq, Iqxy, form_volume, ER, VR and sesans
70    # Remember the component info blocks so we can build the model
[6d6508e]71    model_info.composition = ('mixture', parts)
[72a081d]72
73
[f619de7]74class MixtureModel(KernelModel):
[72a081d]75    def __init__(self, model_info, parts):
[f619de7]76        # type: (ModelInfo, List[KernelModel]) -> None
[72a081d]77        self.info = model_info
78        self.parts = parts
79
80    def __call__(self, q_vectors):
[f619de7]81        # type: (List[np.ndarray]) -> MixtureKernel
[72a081d]82        # Note: may be sending the q_vectors to the n times even though they
83        # are only needed once.  It would mess up modularity quite a bit to
84        # handle this optimally, especially since there are many cases where
85        # separate q vectors are needed (e.g., form in python and structure
86        # in opencl; or both in opencl, but one in single precision and the
87        # other in double precision).
[f619de7]88        kernels = [part.make_kernel(q_vectors) for part in self.parts]
[72a081d]89        return MixtureKernel(self.info, kernels)
90
91    def release(self):
[f619de7]92        # type: () -> None
[72a081d]93        """
94        Free resources associated with the model.
95        """
96        for part in self.parts:
97            part.release()
98
99
[f619de7]100class MixtureKernel(Kernel):
[72a081d]101    def __init__(self, model_info, kernels):
[f619de7]102        # type: (ModelInfo, List[Kernel]) -> None
103        self.dim = kernels[0].dim
104        self.info =  model_info
[72a081d]105        self.kernels = kernels
106
[f619de7]107    def __call__(self, call_details, value, weight, cutoff):
108        # type: (CallDetails, np.ndarray, np.ndarry, float) -> np.ndarray
109        scale, background = value[0:2]
[72a081d]110        total = 0.0
[f619de7]111        # remember the parts for plotting later
112        self.results = []
113        for kernel, kernel_details in zip(self.kernels, call_details.parts):
114            part_result = kernel(kernel_details, value, weight, cutoff)
[72a081d]115            total += part_result
[f619de7]116            self.results.append(part_result)
[72a081d]117
118        return scale*total + background
119
120    def release(self):
[f619de7]121        # type: () -> None
122        for k in self.kernels:
123            k.release()
[72a081d]124
Note: See TracBrowser for help on using the repository browser.