Changeset c072f83 in sasmodels


Ignore:
Timestamp:
Mar 21, 2016 12:28:32 PM (8 years ago)
Author:
Paul Kienzle <pkienzle@…>
Branches:
master, core_shell_microgels, costrafo411, magnetic_model, release_v0.94, release_v0.95, ticket-1257-vesicle-product, ticket_1156, ticket_1265_superball, ticket_822_more_unit_tests
Children:
3a45c2c
Parents:
0a7e5eb4
Message:

revised opencl calculator, first pass

Location:
sasmodels
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • sasmodels/generate.py

    ra6f9577 rc072f83  
    669669    c = p + 3*npars 
    670670 
    671     details = np.zeros(c + 3, 'int32') 
     671    details = np.zeros(c + 2, 'int32') 
    672672    details[0*max_pd:1*max_pd] = range(max_pd)       # pd_par: arbitrary order; use first 
    673673    details[1*max_pd:2*max_pd] = [1]*max_pd          # pd_length: only one element 
     
    702702        theta_par = -1 
    703703 
    704     details = np.empty(constants_offset + 3, 'int32') 
     704    details = np.empty(constants_offset + 2, 'int32') 
    705705    details[0*max_pd:1*max_pd] = idx             # pd_par 
    706706    details[1*max_pd:2*max_pd] = pd_length[idx] 
  • sasmodels/kernelcl.py

    ra6f9577 rc072f83  
    336336        self.program = None 
    337337 
    338     def __call__(self, q_vectors): 
     338    def make_calculator(self, q_vectors, details): 
    339339        if self.program is None: 
    340340            compiler = environment().compile_program 
    341             self.program = compiler(self.info['name'], self.source, self.dtype, 
    342                                     self.fast) 
     341            self.program = compiler(self.info['name'], self.source, 
     342                                    self.dtype, self.fast) 
    343343        is_2d = len(q_vectors) == 2 
    344344        kernel_name = generate.kernel_name(self.info, is_2d) 
    345345        kernel = getattr(self.program, kernel_name) 
    346         return GpuKernel(kernel, self.info, q_vectors, self.dtype) 
     346        return GpuKernel(kernel, self.info, q_vectors, details, self.dtype) 
    347347 
    348348    def release(self): 
     
    387387        # at this point, so instead using 32, which is good on the set of 
    388388        # architectures tested so far. 
    389         self.q_vectors = [_stretch_input(q, self.dtype, 32) for q in q_vectors] 
     389        if self.is_2d: 
     390            # Note: 17 rather than 15 because results is 2 elements 
     391            # longer than input. 
     392            width = ((self.nq+17)//16)*16 
     393            self.q = np.empty((width, 2), dtype=dtype) 
     394            self.q[:self.nq, 0] = q_vectors[0] 
     395            self.q[:self.nq, 1] = q_vectors[1] 
     396        else: 
     397            # Note: 33 rather than 31 because results is 2 elements 
     398            # longer than input. 
     399            width = ((self.nq+33)//32)*32 
     400            self.q = np.empty(width, dtype=dtype) 
     401            self.q[:self.nq] = q_vectors[0] 
     402        self.global_size = [self.q.shape[0]] 
    390403        context = env.get_context(self.dtype) 
    391         self.global_size = [self.q_vectors[0].size] 
    392404        #print("creating inputs of size", self.global_size) 
    393         self.q_buffers = [ 
    394             cl.Buffer(context, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=q) 
    395             for q in self.q_vectors 
    396         ] 
     405        # COPY_HOST_PTR initiates transfer as necessary? 
     406        self.q_b = cl.Buffer(context, mf.READ_ONLY | mf.COPY_HOST_PTR, 
     407                             hostbuf=self.q) 
    397408 
    398409    def release(self): 
     
    400411        Free the memory. 
    401412        """ 
    402         for b in self.q_buffers: 
    403             b.release() 
    404         self.q_buffers = [] 
     413        if self.q is not None: 
     414            self.q.release() 
     415            self.q = None 
    405416 
    406417    def __del__(self): 
     
    427438    Call :meth:`release` when done with the kernel instance. 
    428439    """ 
    429     def __init__(self, kernel, model_info, q_vectors, dtype): 
     440    def __init__(self, kernel, model_info, q_vectors, details, dtype): 
     441        if details.dtype != np.int32: 
     442            raise TypeError("numeric type does not match the kernel type") 
     443 
     444        max_pd = self.info['max_pd'] 
     445        npars = len(model_info['parameters'])-2 
    430446        q_input = GpuInput(q_vectors, dtype) 
     447        self.dtype = dtype 
    431448        self.kernel = kernel 
    432449        self.info = model_info 
    433         self.res = np.empty(q_input.nq, q_input.dtype) 
    434         dim = '2d' if q_input.is_2d else '1d' 
    435         self.fixed_pars = model_info['partype']['fixed-' + dim] 
    436         self.pd_pars = model_info['partype']['pd-' + dim] 
     450        self.details = details 
     451        self.pd_stop_index = 4*max_pd-1 
     452        # plus three for the normalization values 
     453        self.result = np.empty(q_input.nq+3, q_input.dtype) 
     454        #self.dim = '2d' if q_input.is_2d else '1d' 
    437455 
    438456        # Inputs and outputs for each kernel call 
     
    440458        env = environment() 
    441459        self.queue = env.get_queue(dtype) 
    442         self.loops_b = cl.Buffer(self.queue.context, mf.READ_WRITE, 
    443                                  2 * MAX_LOOPS * q_input.dtype.itemsize) 
    444         self.res_b = cl.Buffer(self.queue.context, mf.READ_WRITE, 
     460 
     461        # details is int32 data, padded to a 32 integer boundary 
     462        size = 4*((self.info['mono'].size+7)//8)*8 # padded to 32 byte boundary 
     463        self.details_b = cl.Buffer(self.queue.context, 
     464                                   mf.READ_ONLY | mf.COPY_HOST_PTR, 
     465                                   hostbuf=details) 
     466        size = np.sum(details[max_pd:2*max_pd]) 
     467        self.weights_b = cl.Buffer(self.queue.context, mf.READ_ONLY, size) 
     468        size = np.sum(details[max_pd:2*max_pd])+npars 
     469        self.values_b = cl.Buffer(self.queue.context, mf.READ_ONLY, size) 
     470        self.result_b = cl.Buffer(self.queue.context, mf.READ_WRITE, 
    445471                               q_input.global_size[0] * q_input.dtype.itemsize) 
    446         self.q_input = q_input 
    447  
    448         self._need_release = [self.loops_b, self.res_b, self.q_input] 
    449  
    450     def __call__(self, details, weights, values, cutoff): 
     472        self.q_input = q_input # allocated by GpuInput above 
     473 
     474        self._need_release = [ 
     475            self.details_b, self.weights_b, self.values_b, self.result_b, 
     476            self.q_input, 
     477        ] 
     478 
     479    def __call__(self, weights, values, cutoff): 
    451480        real = (np.float32 if self.q_input.dtype == generate.F32 
    452481                else np.float64 if self.q_input.dtype == generate.F64 
     
    454483                else np.float32)  # will never get here, so use np.float32 
    455484 
    456         #print "pars", fixed_pars, pd_pars 
    457         res_bi = self.res_b 
    458         nq = np.uint32(self.q_input.nq) 
    459         if pd_pars: 
    460             cutoff = real(cutoff) 
    461             loops_N = [np.uint32(len(p[0])) for p in pd_pars] 
    462             loops = np.hstack(pd_pars) \ 
    463                 if pd_pars else np.empty(0, dtype=self.q_input.dtype) 
    464             loops = np.ascontiguousarray(loops.T, self.q_input.dtype).flatten() 
    465             #print("loops",Nloops, loops) 
    466  
    467             #import sys; print("opencl eval",pars) 
    468             #print("opencl eval",pars) 
    469             if len(loops) > 2 * MAX_LOOPS: 
    470                 raise ValueError("too many polydispersity points") 
    471  
    472             loops_bi = self.loops_b 
    473             cl.enqueue_copy(self.queue, loops_bi, loops) 
    474             loops_l = cl.LocalMemory(len(loops.data)) 
    475             #ctx = environment().context 
    476             #loops_bi = cl.Buffer(ctx, mf.READ_ONLY|mf.COPY_HOST_PTR, hostbuf=loops) 
    477             dispersed = [loops_bi, loops_l, cutoff] + loops_N 
    478         else: 
    479             dispersed = [] 
    480         fixed = [real(p) for p in fixed_pars] 
    481         args = self.q_input.q_buffers + [res_bi, nq] + dispersed + fixed 
     485        if weights.dtype != real or values.dtype != real: 
     486            raise TypeError("numeric type does not match the kernel type") 
     487 
     488        cl.enqueue_copy(self.queue, self.weights_b, weights) 
     489        cl.enqueue_copy(self.queue, self.values_b, values) 
     490 
     491        args = [ 
     492            np.uint32(self.q_input.nq), 
     493            np.uint32(0), 
     494            np.uint32(self.details[self.pd_stop_index]), 
     495            self.details_b, 
     496            self.weights_b, 
     497            self.values_b, 
     498            self.q_input.q_b, 
     499            self.result_b, 
     500            real(cutoff), 
     501        ] 
    482502        self.kernel(self.queue, self.q_input.global_size, None, *args) 
    483         cl.enqueue_copy(self.queue, self.res, res_bi) 
    484  
    485         return self.res 
     503        cl.enqueue_copy(self.queue, self.result, self.result_b) 
     504 
     505        return self.result[:self.nq] 
    486506 
    487507    def release(self): 
Note: See TracChangeset for help on using the changeset viewer.