source: sasmodels/sasmodels/kernel.py @ ee60aa7

core_shell_microgelsmagnetic_modelticket-1257-vesicle-productticket_1156ticket_1265_superballticket_822_more_unit_tests
Last change on this file since ee60aa7 was ee60aa7, checked in by Paul Kienzle <pkienzle@…>, 6 years ago

clean up effective radius functions; improve mono_gauss_coil accuracy; start moving VR into C

  • Property mode set to 100644
File size: 3.8 KB
Line 
1"""
2Execution kernel interface
3==========================
4
5:class:`KernelModel` defines the interface to all kernel models.
6In particular, each model should provide a :meth:`KernelModel.make_kernel`
7call which returns an executable kernel, :class:`Kernel`, that operates
8on the given set of *q_vector* inputs.  On completion of the computation,
9the kernel should be released, which also releases the inputs.
10"""
11
12from __future__ import division, print_function
13
14# pylint: disable=unused-import
15try:
16    from typing import List
17except ImportError:
18    pass
19else:
20    import numpy as np
21    from .details import CallDetails
22    from .modelinfo import ModelInfo
23# pylint: enable=unused-import
24
25class KernelModel(object):
26    info = None  # type: ModelInfo
27    dtype = None # type: np.dtype
28    def make_kernel(self, q_vectors):
29        # type: (List[np.ndarray]) -> "Kernel"
30        raise NotImplementedError("need to implement make_kernel")
31
32    def release(self):
33        # type: () -> None
34        pass
35
36class Kernel(object):
37    #: kernel dimension, either "1d" or "2d"
38    dim = None  # type: str
39    info = None  # type: ModelInfo
40    results = None # type: List[np.ndarray]
41    dtype = None  # type: np.dtype
42
43    def Iq(self, call_details, values, cutoff, magnetic):
44        # type: (CallDetails, np.ndarray, np.ndarray, float, bool) -> np.ndarray
45        Pq, Reff = self.Pq_Reff(call_details, values, cutoff, magnetic, effective_radius_type=0)
46        return Pq
47    __call__ = Iq
48
49    def Pq_Reff(self, call_details, values, cutoff, magnetic, effective_radius_type):
50        # type: (CallDetails, np.ndarray, np.ndarray, float, bool, int) -> np.ndarray
51        self._call_kernel(call_details, values, cutoff, magnetic, effective_radius_type)
52        #print("returned",self.q_input.q, self.result)
53        nout = 2 if self.info.have_Fq and self.dim == '1d' else 1
54        total_weight = self.result[nout*self.q_input.nq + 0]
55        if total_weight == 0.:
56            total_weight = 1.
57        weighted_volume = self.result[nout*self.q_input.nq + 1]
58        weighted_radius = self.result[nout*self.q_input.nq + 2]
59        effective_radius = weighted_radius/total_weight
60        # compute I = scale*P + background
61        #           = scale*(sum(w*F^2)/sum w)/(sum (w*V)/sum w) + background
62        #           = scale/sum (w*V) * sum(w*F^2) + background
63        F2 = self.result[0:nout*self.q_input.nq:nout]
64        scale = values[0]/(weighted_volume if weighted_volume != 0.0 else 1.0)
65        background = values[1]
66        Pq = scale*F2 + background
67        #print("scale",scale,background)
68        return Pq, effective_radius
69
70    def beta(self, call_details, values, cutoff, magnetic, effective_radius_type):
71        # type: (CallDetails, np.ndarray, np.ndarray, float, bool, int) -> np.ndarray
72        if self.dim == '2d':
73            raise NotImplementedError("beta not yet supported for 2D")
74        if not self.info.have_Fq:
75            raise NotImplementedError("beta not yet supported for "+self.info.id)
76        self._call_kernel(call_details, values, cutoff, magnetic, effective_radius_type)
77        total_weight = self.result[2*self.q_input.nq + 0]
78        if total_weight == 0.:
79            total_weight = 1.
80        weighted_volume = self.result[2*self.q_input.nq + 1]
81        weighted_radius = self.result[2*self.q_input.nq + 2]
82        volume_average = weighted_volume/total_weight
83        effective_radius = weighted_radius/total_weight
84        F2 = self.result[0:2*self.q_input.nq:2]/total_weight
85        F1 = self.result[1:2*self.q_input.nq:2]/total_weight
86        return F1, F2, volume_average, effective_radius
87
88    def release(self):
89        # type: () -> None
90        pass
91
92    def _call_kernel(self, call_details, values, cutoff, magnetic, effective_radius_type):
93        # type: (CallDetails, np.ndarray, np.ndarray, float, bool, int) -> np.ndarray
94        raise NotImplementedError()
Note: See TracBrowser for help on using the repository browser.