source: sasmodels/sasmodels/dll.py @ ce27e21

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

first pass for sasview wrapper around opencl models

  • Property mode set to 100644
File size: 4.5 KB
Line 
1"""
2C types wrapper for sasview models.
3"""
4
5import ctypes as ct
6from ctypes import c_void_p, c_int, c_double
7
8import numpy as np
9
10from . import gen
11
12from .gen import F32, F64
13
14IQ_ARGS = [c_void_p, c_void_p, c_int, c_void_p, c_double]
15IQXY_ARGS = [c_void_p, c_void_p, c_void_p, c_int, c_void_p, c_double]
16
17class DllModel(object):
18    """
19    ctypes wrapper for a single model.
20
21    *source* and *info* are the model source and interface as returned
22    from :func:`gen.make`.
23
24    *dtype* is the desired model precision.  Any numpy dtype for single
25    or double precision floats will do, such as 'f', 'float32' or 'single'
26    for single and 'd', 'float64' or 'double' for double.  Double precision
27    is an optional extension which may not be available on all devices.
28    """
29    def __init__(self, dllpath, info):
30        self.info = info
31        self.dllpath = dllpath
32        self.dll = None
33
34    def _load_dll(self):
35        Nfixed1d = len(self.info['partype']['fixed-1d'])
36        Nfixed2d = len(self.info['partype']['fixed-2d'])
37        Npd1d = len(self.info['partype']['pd-1d'])
38        Npd2d = len(self.info['partype']['pd-2d'])
39
40        self.dll = ct.CDLL(self.dllpath)
41
42        self.Iq = self.dll[gen.kernel_name(self.info, False)]
43        self.Iq.argtypes = IQ_ARGS + [c_double]*Nfixed1d + [c_int]*Npd1d
44
45        self.Iqxy = self.dll[gen.kernel_name(self.info, True)]
46        self.Iqxy.argtypes = IQXY_ARGS + [c_double]*Nfixed2d + [c_int]*Npd2d
47
48    def __getstate__(self):
49        return {'info': self.info, 'dllpath': self.dllpath, 'dll': None}
50
51    def __setstate__(self, state):
52        self.__dict__ = state
53
54    def __call__(self, input):
55        if self.dll is None: self._load_dll()
56
57        kernel = self.Iqxy if input.is_2D else self.Iq
58        return DllKernel(kernel, self.info, input)
59
60    def make_input(self, q_vectors):
61        """
62        Make q input vectors available to the model.
63
64        This only needs to be done once for all models that operate on the
65        same input.  So for example, if you are adding two different models
66        together to compare to a data set, then only one model needs to
67        needs to call make_input, so long as the models have the same dtype.
68        """
69        return DllInput(q_vectors)
70
71
72class DllInput(object):
73    """
74    Make q data available to the gpu.
75
76    *q_vectors* is a list of q vectors, which will be *[q]* for 1-D data,
77    and *[qx, qy]* for 2-D data.  Internally, the vectors will be reallocated
78    to get the best performance on OpenCL, which may involve shifting and
79    stretching the array to better match the memory architecture.  Additional
80    points will be evaluated with *q=1e-3*.
81
82    *dtype* is the data type for the q vectors. The data type should be
83    set to match that of the kernel, which is an attribute of
84    :class:`GpuProgram`.  Note that not all kernels support double
85    precision, so even if the program was created for double precision,
86    the *GpuProgram.dtype* may be single precision.
87
88    Call :meth:`release` when complete.  Even if not called directly, the
89    buffer will be released when the data object is freed.
90    """
91    def __init__(self, q_vectors):
92        self.nq = q_vectors[0].size
93        self.dtype = np.dtype('double')
94        self.is_2D = (len(q_vectors) == 2)
95        self.q_vectors = [np.ascontiguousarray(q,self.dtype) for q in q_vectors]
96        self.q_pointers = [q.ctypes.data for q in q_vectors]
97
98    def release(self):
99        self.q_vectors = []
100
101class DllKernel(object):
102    def __init__(self, kernel, info, input):
103        self.input = input
104        self.kernel = kernel
105        self.info = info
106        self.res = np.empty(input.nq, input.dtype)
107        dim = '2d' if input.is_2D else '1d'
108        self.fixed_pars = info['partype']['fixed-'+dim]
109        self.pd_pars = info['partype']['pd-'+dim]
110
111        # In dll kernel, but not in opencl kernel
112        self.p_res = self.res.ctypes.data
113
114    def __call__(self, pars, pd_pars, cutoff):
115        real = np.float32 if self.input.dtype == F32 else np.float64
116        fixed = [real(p) for p in pars]
117        cutoff = real(cutoff)
118        loops = np.hstack(pd_pars)
119        loops = np.ascontiguousarray(loops.T, self.input.dtype).flatten()
120        loops_N = [np.uint32(len(p[0])) for p in pd_pars]
121
122        nq = c_int(self.input.nq)
123        p_loops = loops.ctypes.data
124        args = self.input.q_pointers + [self.p_res, nq, p_loops, cutoff] + fixed + loops_N
125        #print pars
126        self.kernel(*args)
127
128        return self.res
129
130    def release(self):
131        pass
Note: See TracBrowser for help on using the repository browser.