source: sasmodels/Models/code_cylinder.py @ 14de349

core_shell_microgelscostrafo411magnetic_modelrelease_v0.94release_v0.95ticket-1257-vesicle-productticket_1156ticket_1265_superballticket_822_more_unit_tests
Last change on this file since 14de349 was 1726b21, checked in by HMP1 <helen.park@…>, 10 years ago

cylinder now MUCH faster!

  • Property mode set to 100644
File size: 5.9 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4import numpy as np
5import pyopencl as cl
6
7from weights import GaussianDispersion
8from sasmodel import card, set_precision, set_precision_1d, tic, toc
9
10
11class GpuCylinder(object):
12    PARS = {
13        'scale':1,'radius':1,'length':1,'sldCyl':1e-6,'sldSolv':0,'background':0,
14        'cyl_theta':0,'cyl_phi':0,
15    }
16    PD_PARS = ['radius', 'length', 'cyl_theta', 'cyl_phi']
17
18    def __init__(self, qx, qy, dtype='float32'):
19
20        #create context, queue, and build program
21        ctx,_queue = card()
22        src, qx, qy = set_precision(open('Kernel/NR_BessJ1.cpp').read()+"\n"+open('Kernel/Kernel-Cylinder.cpp').read(), qx, qy, dtype=dtype)
23        self.prg = cl.Program(ctx, src).build()
24        self.qx, self.qy = qx, qy
25
26        #buffers
27        mf = cl.mem_flags
28        self.qx_b = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=self.qx)
29        self.qy_b = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=self.qy)
30        self.res_b = cl.Buffer(ctx, cl.mem_flags.READ_WRITE, self.qx.nbytes)
31        self.res = np.empty_like(self.qx)
32
33    def eval(self, pars):
34
35        tic()
36        _ctx,queue = card()
37        self.res[:] = 0
38        cl.enqueue_copy(queue, self.res_b, self.res)
39        radius, length, cyl_theta, cyl_phi = \
40            [GaussianDispersion(int(pars[base+'_pd_n']), pars[base+'_pd'], pars[base+'_pd_nsigma'])
41             for base in GpuCylinder.PD_PARS]
42
43        #Get the weights for each
44        radius.value, radius.weight = radius.get_weights(pars['radius'], 0, 10000, True)
45        length.value, length.weight = length.get_weights(pars['length'], 0, 10000, True)
46        cyl_theta.value, cyl_theta.weight = cyl_theta.get_weights(pars['cyl_theta'], -np.inf, np.inf, False)
47        cyl_phi.value, cyl_phi.weight = cyl_phi.get_weights(pars['cyl_phi'], -np.inf, np.inf, False)
48
49        #Perform the computation, with all weight points
50        sum, norm, norm_vol, vol = 0.0, 0.0, 0.0, 0.0
51        size = len(cyl_theta.weight)
52        sub = pars['sldCyl'] - pars['sldSolv']
53
54        real = np.float32 if self.qx.dtype == np.dtype('float32') else np.float64
55        #Loop over radius, length, theta, phi weight points
56        for i in xrange(len(radius.weight)):
57            for j in xrange(len(length.weight)):
58
59                vol += radius.weight[i]*length.weight[j]*pow(radius.value[i], 2)*length.value[j]
60                norm_vol += radius.weight[i]*length.weight[j]
61
62                for k in xrange(len(cyl_theta.weight)):
63                    for l in xrange(len(cyl_phi.weight)):
64                        self.prg.CylinderKernel(queue, self.qx.shape, None, self.qx_b, self.qy_b, self.res_b, real(sub),
65                                           real(radius.value[i]), real(length.value[j]), real(pars['scale']),
66                                           real(radius.weight[i]), real(length.weight[j]), real(cyl_theta.weight[k]),
67                                           real(cyl_phi.weight[l]), real(cyl_theta.value[k]), real(cyl_phi.value[l]),
68                                           np.uint32(self.qx.size), np.uint32(size))
69
70                        norm += radius.weight[i]*length.weight[j]*cyl_theta.weight[k]*cyl_phi.weight[l]
71
72
73       # if size > 1:
74        #    norm /= math.asin(1.0)
75        cl.enqueue_copy(queue, self.res, self.res_b)
76        sum = self.res
77        if vol != 0.0 and norm_vol != 0.0:
78            sum *= norm_vol/vol
79
80        print toc()*1000, self.qx.shape[0]
81        return sum/norm+pars['background']
82
83class OneDGpuCylinder(object):
84    PARS = {
85        'scale':1,'radius':1,'length':1,'sldCyl':1e-6,'sldSolv':0,'background':0,
86        'bolim':0, 'uplim':90
87    }
88    PD_PARS = ['radius', 'length']
89
90    def __init__(self, q, dtype='float32'):
91
92        #create context, queue, and build program
93        ctx,_queue = card()
94        trala = open('Kernel/NR_BessJ1.cpp').read()+"\n"+open('Kernel/OneDCyl_Kfun.cpp').read()+"\n"+open('Kernel/Kernel-OneDCylinder.cpp').read()
95        src, self.q = set_precision_1d(trala, q, dtype=dtype)
96        self.prg = cl.Program(ctx, src).build()
97
98        #buffers
99        mf = cl.mem_flags
100        self.q_b = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=self.q)
101        self.res_b = cl.Buffer(ctx, mf.WRITE_ONLY, q.nbytes)
102        self.res = np.empty_like(self.q)
103
104    def eval(self, pars):
105
106        _ctx,queue = card()
107        radius, length = \
108            [GaussianDispersion(int(pars[base+'_pd_n']), pars[base+'_pd'], pars[base+'_pd_nsigma'])
109             for base in OneDGpuCylinder.PD_PARS]
110
111        #Get the weights for each
112        radius.value, radius.weight = radius.get_weights(pars['radius'], 0, 10000, True)
113        length.value, length.weight = length.get_weights(pars['length'], 0, 10000, True)
114
115        #Perform the computation, with all weight points
116        sum, norm, vol = 0.0, 0.0, 0.0,
117        sub = pars['sldCyl'] - pars['sldSolv']
118
119        real = np.float32 if self.q.dtype == np.dtype('float32') else np.float64
120        #Loop over radius, length, theta, phi weight points
121        for r in xrange(len(radius.weight)):
122            for l in xrange(len(length.weight)):
123                        self.prg.OneDCylKernel(queue, self.q.shape, None, self.q_b, self.res_b, real(sub),
124                                           real(length.value[l]), real(radius.value[r]), real(pars['scale']),
125                                           np.uint32(self.q.size), real(pars['uplim']), real(pars['bolim']))
126                        cl.enqueue_copy(queue, self.res, self.res_b)
127                        sum += radius.weight[r]*length.weight[l]*self.res*pow(radius.value[r],2)*length.value[l]
128                        vol += radius.weight[r]*length.weight[l] *pow(radius.value[r],2)*length.value[l]
129                        norm += radius.weight[r]*length.weight[l]
130
131        if vol != 0.0 and norm != 0.0:
132            sum *= norm/vol
133
134        return sum/norm + pars['background']
135
136       
137
138       
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
Note: See TracBrowser for help on using the repository browser.