source: sasmodels/Models/code_cylinder.py @ 8cdb9f1

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

Speed-up of 3X, compare.py working

  • Property mode set to 100644
File size: 5.8 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
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        _ctx,queue = card()
36        self.res[:] = 0
37        cl.enqueue_copy(queue, self.res_b, self.res)
38        radius, length, cyl_theta, cyl_phi = \
39            [GaussianDispersion(int(pars[base+'_pd_n']), pars[base+'_pd'], pars[base+'_pd_nsigma'])
40             for base in GpuCylinder.PD_PARS]
41
42        #Get the weights for each
43        radius.value, radius.weight = radius.get_weights(pars['radius'], 0, 10000, True)
44        length.value, length.weight = length.get_weights(pars['length'], 0, 10000, True)
45        cyl_theta.value, cyl_theta.weight = cyl_theta.get_weights(pars['cyl_theta'], -np.inf, np.inf, False)
46        cyl_phi.value, cyl_phi.weight = cyl_phi.get_weights(pars['cyl_phi'], -np.inf, np.inf, False)
47
48        #Perform the computation, with all weight points
49        sum, norm, norm_vol, vol = 0.0, 0.0, 0.0, 0.0
50        size = len(cyl_theta.weight)
51        sub = pars['sldCyl'] - pars['sldSolv']
52
53        real = np.float32 if self.qx.dtype == np.dtype('float32') else np.float64
54        #Loop over radius, length, theta, phi weight points
55        for i in xrange(len(radius.weight)):
56            for j in xrange(len(length.weight)):
57                for k in xrange(len(cyl_theta.weight)):
58                    for l in xrange(len(cyl_phi.weight)):
59                        self.prg.CylinderKernel(queue, self.qx.shape, None, self.qx_b, self.qy_b, self.res_b, real(sub),
60                                           real(radius.value[i]), real(length.value[j]), real(pars['scale']),
61                                           real(radius.weight[i]), real(length.weight[j]), real(cyl_theta.weight[k]),
62                                           real(cyl_phi.weight[l]), real(cyl_theta.value[k]), real(cyl_phi.value[l]),
63                                           np.uint32(self.qx.size), np.uint32(size))
64
65                        vol += radius.weight[i]*length.weight[j]*pow(radius.value[i], 2)*length.value[j]
66                        norm_vol += radius.weight[i]*length.weight[j]
67                        norm += radius.weight[i]*length.weight[j]*cyl_theta.weight[k]*cyl_phi.weight[l]
68
69       # if size > 1:
70        #    norm /= math.asin(1.0)
71        cl.enqueue_copy(queue, self.res, self.res_b)
72        sum = self.res
73        if vol != 0.0 and norm_vol != 0.0:
74            sum *= norm_vol/vol
75
76        return sum/norm+pars['background']
77
78class OneDGpuCylinder(object):
79    PARS = {
80        'scale':1,'radius':1,'length':1,'sldCyl':1e-6,'sldSolv':0,'background':0,
81        'bolim':0, 'uplim':90
82    }
83    PD_PARS = ['radius', 'length']
84
85    def __init__(self, q, dtype='float32'):
86
87        #create context, queue, and build program
88        ctx,_queue = card()
89        trala = open('Kernel/NR_BessJ1.cpp').read()+"\n"+open('Kernel/OneDCyl_Kfun.cpp').read()+"\n"+open('Kernel/Kernel-OneDCylinder.cpp').read()
90        src, self.q = set_precision_1d(trala, q, dtype=dtype)
91        self.prg = cl.Program(ctx, src).build()
92
93        #buffers
94        mf = cl.mem_flags
95        self.q_b = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=self.q)
96        self.res_b = cl.Buffer(ctx, mf.WRITE_ONLY, q.nbytes)
97        self.res = np.empty_like(self.q)
98
99    def eval(self, pars):
100
101        _ctx,queue = card()
102        radius, length = \
103            [GaussianDispersion(int(pars[base+'_pd_n']), pars[base+'_pd'], pars[base+'_pd_nsigma'])
104             for base in OneDGpuCylinder.PD_PARS]
105
106        #Get the weights for each
107        radius.value, radius.weight = radius.get_weights(pars['radius'], 0, 10000, True)
108        length.value, length.weight = length.get_weights(pars['length'], 0, 10000, True)
109
110        #Perform the computation, with all weight points
111        sum, norm, vol = 0.0, 0.0, 0.0,
112        sub = pars['sldCyl'] - pars['sldSolv']
113
114        real = np.float32 if self.q.dtype == np.dtype('float32') else np.float64
115        #Loop over radius, length, theta, phi weight points
116        for r in xrange(len(radius.weight)):
117            for l in xrange(len(length.weight)):
118                        self.prg.OneDCylKernel(queue, self.q.shape, None, self.q_b, self.res_b, real(sub),
119                                           real(length.value[l]), real(radius.value[r]), real(pars['scale']),
120                                           np.uint32(self.q.size), real(pars['uplim']), real(pars['bolim']))
121                        cl.enqueue_copy(queue, self.res, self.res_b)
122                        sum += radius.weight[r]*length.weight[l]*self.res*pow(radius.value[r],2)*length.value[l]
123                        vol += radius.weight[r]*length.weight[l] *pow(radius.value[r],2)*length.value[l]
124                        norm += radius.weight[r]*length.weight[l]
125
126        if vol != 0.0 and norm != 0.0:
127            sum *= norm/vol
128
129        return sum/norm + pars['background']
130
131       
132
133       
134
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
Note: See TracBrowser for help on using the repository browser.