17. Evaluator type definitions¶
sasmodels.kernel¶
Execution kernel interface¶
KernelModel defines the interface to all kernel models.
In particular, each model should provide a KernelModel.make_kernel()
call which returns an executable kernel, Kernel, that operates
on the given set of q_vector inputs. On completion of the computation,
the kernel should be released, which also releases the inputs.
- class sasmodels.kernel.Kernel¶
Bases:
objectInstantiated model for the compute engine, applied to a particular q.
Subclasses should define __init__() to set up the kernel inputs, and _call_kernel() to evaluate the kernel:
def __init__(self, ...): ... self.q_input = <q-value class with nq attribute> self.info = <ModelInfo object> self.dim = <'1d' or '2d'> self.dtype = <kernel.dtype> size = 2*self.q_input.nq+4 if self.info.have_Fq else self.q_input.nq+4 size = size + <extra padding if needed for kernel> self.result = np.empty(size, dtype=self.dtype) def _call_kernel(self, call_details, values, cutoff, magnetic, radius_effective_mode): # type: (CallDetails, np.ndarray, np.ndarray, float, bool, int) -> None ... # call <kernel> nq = self.q_input.nq if self.info.have_Fq: # models that compute both F and F^2 end = 2*nq if have_Fq else nq self.result[0:end:2] = F**2 self.result[1:end:2] = F else: end = nq self.result[0:end] = Fsq self.result[end + 0] = total_weight self.result[end + 1] = form_volume self.result[end + 2] = shell_volume self.result[end + 3] = radius_effective
- Fq(call_details: CallDetails, values: np.ndarray, cutoff: np.ndarray, magnetic: float, radius_effective_mode: bool = 0) np.ndarray¶
Returns <F(q)>, <F(q)^2>, effective radius, shell volume and form:shell volume ratio. The <F(q)> term may be None if the form factor does not support direct computation of \(F(q)\)
\(P(q) = <F^2(q)>/<V>\) is used for structure factor calculations,
\[I(q) = \text{scale} \cdot P(q) \cdot S(q) + \text{background}\]For the beta approximation, this becomes
\[I(q) = \text{scale} P (1 + <F>^2/<F^2> (S - 1)) + \text{background} = \text{scale}/<V> (<F^2> + <F>^2 (S - 1)) + \text{background}\]\(<F(q)>\) and \(<F^2(q)>\) are averaged by polydispersity in shape and orientation, with each configuration \(x_k\) having form factor \(F(q, x_k)\), weight \(w_k\) and volume \(V_k\). The result is:
\[P(q)=\frac{\sum w_k F^2(q, x_k) / \sum w_k}{\sum w_k V_k / \sum w_k}\]The form factor itself is scaled by volume and contrast to compute the total scattering. This is then squared, and the volume weighted F^2 is then normalized by volume F. For a given density, the number of scattering centers is assumed to scale linearly with volume. Later scaling the resulting \(P(q)\) by the volume fraction of particles gives the total scattering on an absolute scale. Most models incorporate the volume fraction into the overall scale parameter. An exception is vesicle, which includes the volume fraction parameter in the model itself, scaling \(F\) by \(\surd V_f\) so that the math for the beta approximation works out.
By scaling \(P(q)\) by total weight \(\sum w_k\), there is no need to make sure that the polydisperisity distributions normalize to one. In particular, any distibution values \(x_k\) outside the valid domain of \(F\) will not be included, and the distribution will be implicitly truncated. This is controlled by the parameter limits defined in the model (which truncate the distribution before calling the kernel) as well as any region excluded using the INVALID macro defined within the model itself.
The volume used in the polydispersity calculation is the form volume for solid objects or the shell volume for hollow objects. Shell volume should be used within \(F\) so that the normalizing scale represents the volume fraction of the shell rather than the entire form. This corresponds to the volume fraction of shell-forming material added to the solvent.
The calculation of \(S\) requires the effective radius and the volume fraction of the particles. The model can have several different ways to compute effective radius, with the radius_effective_mode parameter used to select amongst them. The volume fraction of particles should be determined from the total volume fraction of the form, not just the shell volume fraction. This makes a difference for hollow shapes, which need to scale the volume fraction by the returned volume ratio when computing \(S\). For solid objects, the shell volume is set to the form volume so this scale factor evaluates to one and so can be used for both hollow and solid shapes.
- Iq(call_details: CallDetails, values: np.ndarray, cutoff: np.ndarray, magnetic: float) np.ndarray¶
Returns I(q) from the polydisperse average scattering.
\[I(q) = \text{scale} \cdot P(q) + \text{background}\]With the correct choice of model and contrast, setting scale to the volume fraction \(V_f\) of particles should match the measured absolute scattering. Some models (e.g., vesicle) have volume fraction built into the model, and do not need an additional scale.
- __call__(call_details: CallDetails, values: np.ndarray, cutoff: np.ndarray, magnetic: float) np.ndarray¶
Returns I(q) from the polydisperse average scattering.
\[I(q) = \text{scale} \cdot P(q) + \text{background}\]With the correct choice of model and contrast, setting scale to the volume fraction \(V_f\) of particles should match the measured absolute scattering. Some models (e.g., vesicle) have volume fraction built into the model, and do not need an additional scale.
- __class__¶
alias of
type
- __delattr__(name, /)¶
Implement delattr(self, name).
- __dict__ = mappingproxy({'__module__': 'sasmodels.kernel', '__doc__': "\n Instantiated model for the compute engine, applied to a particular *q*.\n\n Subclasses should define *__init__()* to set up the kernel inputs, and\n *_call_kernel()* to evaluate the kernel::\n\n def __init__(self, ...):\n ...\n self.q_input = <q-value class with nq attribute>\n self.info = <ModelInfo object>\n self.dim = <'1d' or '2d'>\n self.dtype = <kernel.dtype>\n size = 2*self.q_input.nq+4 if self.info.have_Fq else self.q_input.nq+4\n size = size + <extra padding if needed for kernel>\n self.result = np.empty(size, dtype=self.dtype)\n\n def _call_kernel(self, call_details, values, cutoff, magnetic,\n radius_effective_mode):\n # type: (CallDetails, np.ndarray, np.ndarray, float, bool, int) -> None\n ... # call <kernel>\n nq = self.q_input.nq\n if self.info.have_Fq: # models that compute both F and F^2\n end = 2*nq if have_Fq else nq\n self.result[0:end:2] = F**2\n self.result[1:end:2] = F\n else:\n end = nq\n self.result[0:end] = Fsq\n self.result[end + 0] = total_weight\n self.result[end + 1] = form_volume\n self.result[end + 2] = shell_volume\n self.result[end + 3] = radius_effective\n ", 'dim': None, 'info': None, 'dtype': None, 'q_input': None, 'result': None, 'Iq': <function Kernel.Iq>, '__call__': <function Kernel.Iq>, 'Fq': <function Kernel.Fq>, 'release': <function Kernel.release>, '_call_kernel': <function Kernel._call_kernel>, '__dict__': <attribute '__dict__' of 'Kernel' objects>, '__weakref__': <attribute '__weakref__' of 'Kernel' objects>, '__annotations__': {'dim': 'str', 'info': 'ModelInfo', 'dtype': 'np.dtype', 'q_input': 'Any', 'result': 'np.ndarray'}})¶
- __dir__()¶
Default dir() implementation.
- __doc__ = "\n Instantiated model for the compute engine, applied to a particular *q*.\n\n Subclasses should define *__init__()* to set up the kernel inputs, and\n *_call_kernel()* to evaluate the kernel::\n\n def __init__(self, ...):\n ...\n self.q_input = <q-value class with nq attribute>\n self.info = <ModelInfo object>\n self.dim = <'1d' or '2d'>\n self.dtype = <kernel.dtype>\n size = 2*self.q_input.nq+4 if self.info.have_Fq else self.q_input.nq+4\n size = size + <extra padding if needed for kernel>\n self.result = np.empty(size, dtype=self.dtype)\n\n def _call_kernel(self, call_details, values, cutoff, magnetic,\n radius_effective_mode):\n # type: (CallDetails, np.ndarray, np.ndarray, float, bool, int) -> None\n ... # call <kernel>\n nq = self.q_input.nq\n if self.info.have_Fq: # models that compute both F and F^2\n end = 2*nq if have_Fq else nq\n self.result[0:end:2] = F**2\n self.result[1:end:2] = F\n else:\n end = nq\n self.result[0:end] = Fsq\n self.result[end + 0] = total_weight\n self.result[end + 1] = form_volume\n self.result[end + 2] = shell_volume\n self.result[end + 3] = radius_effective\n "¶
- __eq__(value, /)¶
Return self==value.
- __format__(format_spec, /)¶
Default object formatter.
- __ge__(value, /)¶
Return self>=value.
- __getattribute__(name, /)¶
Return getattr(self, name).
- __getstate__()¶
Helper for pickle.
- __gt__(value, /)¶
Return self>value.
- __hash__()¶
Return hash(self).
- __init__()¶
- classmethod __init_subclass__()¶
This method is called when a class is subclassed.
The default implementation does nothing. It may be overridden to extend subclasses.
- __le__(value, /)¶
Return self<=value.
- __lt__(value, /)¶
Return self<value.
- __module__ = 'sasmodels.kernel'¶
- __ne__(value, /)¶
Return self!=value.
- classmethod __new__(*args, **kwargs)¶
- __reduce__()¶
Helper for pickle.
- __reduce_ex__(protocol, /)¶
Helper for pickle.
- __repr__()¶
Return repr(self).
- __setattr__(name, value, /)¶
Implement setattr(self, name, value).
- __sizeof__()¶
Size of object in memory, in bytes.
- __str__()¶
Return str(self).
- classmethod __subclasshook__()¶
Abstract classes can override this to customize issubclass().
This is invoked early on by abc.ABCMeta.__subclasscheck__(). It should return True, False or NotImplemented. If it returns NotImplemented, the normal algorithm is used. Otherwise, it overrides the normal algorithm (and the outcome is cached).
- __weakref__¶
list of weak references to the object
- _call_kernel(call_details: CallDetails, values: np.ndarray, cutoff: np.ndarray, magnetic: float, radius_effective_mode: bool) None¶
Call the kernel. Subclasses defining kernels for particular execution engines need to provide an implementation for this.
- dim: str = None¶
Kernel dimension, either “1d” or “2d”.
- dtype: np.dtype = None¶
Numerical precision for the computation.
- release() None¶
Free resources associated with the kernel instance.
- result: np.ndarray = None¶
Place to hold result of _call_kernel() for subclass.
- class sasmodels.kernel.KernelModel¶
Bases:
objectModel definition for the compute engine.
- __annotations__ = {'dtype': 'np.dtype', 'info': 'ModelInfo'}¶
- __class__¶
alias of
type
- __delattr__(name, /)¶
Implement delattr(self, name).
- __dict__ = mappingproxy({'__module__': 'sasmodels.kernel', '__doc__': '\n Model definition for the compute engine.\n ', 'info': None, 'dtype': None, 'make_kernel': <function KernelModel.make_kernel>, 'release': <function KernelModel.release>, '__dict__': <attribute '__dict__' of 'KernelModel' objects>, '__weakref__': <attribute '__weakref__' of 'KernelModel' objects>, '__annotations__': {'info': 'ModelInfo', 'dtype': 'np.dtype'}})¶
- __dir__()¶
Default dir() implementation.
- __doc__ = '\n Model definition for the compute engine.\n '¶
- __eq__(value, /)¶
Return self==value.
- __format__(format_spec, /)¶
Default object formatter.
- __ge__(value, /)¶
Return self>=value.
- __getattribute__(name, /)¶
Return getattr(self, name).
- __getstate__()¶
Helper for pickle.
- __gt__(value, /)¶
Return self>value.
- __hash__()¶
Return hash(self).
- __init__()¶
- classmethod __init_subclass__()¶
This method is called when a class is subclassed.
The default implementation does nothing. It may be overridden to extend subclasses.
- __le__(value, /)¶
Return self<=value.
- __lt__(value, /)¶
Return self<value.
- __module__ = 'sasmodels.kernel'¶
- __ne__(value, /)¶
Return self!=value.
- classmethod __new__(*args, **kwargs)¶
- __reduce__()¶
Helper for pickle.
- __reduce_ex__(protocol, /)¶
Helper for pickle.
- __repr__()¶
Return repr(self).
- __setattr__(name, value, /)¶
Implement setattr(self, name, value).
- __sizeof__()¶
Size of object in memory, in bytes.
- __str__()¶
Return str(self).
- classmethod __subclasshook__()¶
Abstract classes can override this to customize issubclass().
This is invoked early on by abc.ABCMeta.__subclasscheck__(). It should return True, False or NotImplemented. If it returns NotImplemented, the normal algorithm is used. Otherwise, it overrides the normal algorithm (and the outcome is cached).
- __weakref__¶
list of weak references to the object
- dtype: np.dtype = None¶
- make_kernel(q_vectors: List[np.ndarray]) Kernel¶
Instantiate a kernel for evaluating the model at q_vectors.
- release() None¶
Free resources associated with the kernel.