source: sasmodels/code_cylinder.py @ 496b252

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

Update for Aaron

  • Property mode set to 100644
File size: 4.5 KB
RevLine 
[5378e40]1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4import numpy as np
5import math
6import pyopencl as cl
7from weights import GaussianDispersion
[8a20be5]8from sasmodel import card
[5378e40]9
[8a20be5]10def set_precision(src, qx, qy, dtype):
11    qx = np.ascontiguousarray(qx, dtype=dtype)
12    qy = np.ascontiguousarray(qy, dtype=dtype)
13    if np.dtype(dtype) == np.dtype('float32'):
14        header = """\
15#define real float
16"""
17    else:
18        header = """\
19#pragma OPENCL EXTENSION cl_khr_fp64: enable
20#define real double
21"""
22    return header+src, qx, qy
[5378e40]23
24class GpuCylinder(object):
25    PARS = {
26        'scale':1,'radius':1,'length':1,'sldCyl':1e-6,'sldSolv':0,'background':0,
27        'cyl_theta':0,'cyl_phi':0,
28    }
29    PD_PARS = ['radius', 'length', 'cyl_theta', 'cyl_phi']
30
[8a20be5]31    def __init__(self, qx, qy, dtype='float32'):
[5378e40]32
33        #create context, queue, and build program
[8a20be5]34        ctx,_queue = card()
35        src, qx, qy = set_precision(open('NR_BessJ1.cpp').read()+"\n"+open('Kernel-Cylinder.cpp').read(), qx, qy, dtype=dtype)
36        self.prg = cl.Program(ctx, src).build()
37        self.qx, self.qy = qx, qy
[5378e40]38
39        #buffers
40        mf = cl.mem_flags
[8a20be5]41        self.qx_b = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=self.qx)
42        self.qy_b = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=self.qy)
43        self.res_b = cl.Buffer(ctx, mf.WRITE_ONLY, qx.nbytes)
[5378e40]44        self.res = np.empty_like(self.qx)
45
46    def eval(self, pars):
47
[8a20be5]48        _ctx,queue = card()
49        radius, length, cyl_theta, cyl_phi = \
[5378e40]50            [GaussianDispersion(int(pars[base+'_pd_n']), pars[base+'_pd'], pars[base+'_pd_nsigma'])
51             for base in GpuCylinder.PD_PARS]
52
53        #Get the weights for each
54        radius.value, radius.weight = radius.get_weights(pars['radius'], 0, 1000, True)
55        length.value, length.weight = length.get_weights(pars['length'], 0, 1000, True)
56        cyl_theta.value, cyl_theta.weight = cyl_theta.get_weights(pars['cyl_theta'], -90, 180, False)
57        cyl_phi.value, cyl_phi.weight = cyl_phi.get_weights(pars['cyl_phi'], -90, 180, False)
58
59        #Perform the computation, with all weight points
60        sum, norm, norm_vol, vol = 0.0, 0.0, 0.0, 0.0
61        size = len(cyl_theta.weight)
62        sub = pars['sldCyl'] - pars['sldSolv']
63
[8a20be5]64        real = np.float32 if self.qx.dtype == np.dtype('float32') else np.float64
[5378e40]65        #Loop over radius, length, theta, phi weight points
66        for i in xrange(len(radius.weight)):
67            for j in xrange(len(length.weight)):
68                for k in xrange(len(cyl_theta.weight)):
69                    for l in xrange(len(cyl_phi.weight)):
70
[8a20be5]71
72                        self.prg.CylinderKernel(queue, self.qx.shape, None, self.qx_b, self.qy_b, self.res_b, real(sub),
73                                           real(radius.value[i]), real(length.value[j]), real(pars['scale']),
74                                           real(radius.weight[i]), real(length.weight[j]), real(cyl_theta.weight[k]),
75                                           real(cyl_phi.weight[l]), real(cyl_theta.value[k]), real(cyl_phi.value[l]),
[5378e40]76                                           np.uint32(self.qx.size), np.uint32(size))
[8a20be5]77                        cl.enqueue_copy(queue, self.res, self.res_b)
[5378e40]78                        sum += self.res
79                        vol += radius.weight[i]*length.weight[j]*pow(radius.value[i], 2)*length.value[j]
80                        norm_vol += radius.weight[i]*length.weight[j]
81                        norm += radius.weight[i]*length.weight[j]*cyl_theta.weight[k]*cyl_phi.weight[l]
82
83        if size > 1:
84            norm /= math.asin(1.0)
85        if vol != 0.0 and norm_vol != 0.0:
86            sum *= norm_vol/vol
87
88        return sum/norm+pars['background']
89
90def demo():
91    from time import time
92    import matplotlib.pyplot as plt
93
94    #create qx and qy evenly spaces
95    qx = np.linspace(-.02, .02, 128)
96    qy = np.linspace(-.02, .02, 128)
97    qx, qy = np.meshgrid(qx, qy)
98
99    #saved shape of qx
100    r_shape = qx.shape
101
102    #reshape for calculation; resize as float32
103    qx = qx.flatten()
104    qy = qy.flatten()
105
106    pars = CylinderParameters(scale=1, radius=64.1, length=266.96, sldCyl=.291e-6, sldSolv=5.77e-6, background=0,
107                              cyl_theta=0, cyl_phi=0)
108    t = time()
109    result = GpuCylinder(qx, qy)
110    result.x = result.cylinder_fit(pars, r_n=10, t_n=10, l_n=10, p_n=10, r_w=.1, t_w=.1, l_w=.1, p_w=.1, sigma=3)
111    result.x = np.reshape(result.x, r_shape)
112    tt = time()
113
114    print("Time taken: %f" % (tt - t))
115
116    plt.pcolormesh(result.x)
117    plt.show()
118
119
120if __name__=="__main__":
121    demo()
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
Note: See TracBrowser for help on using the repository browser.