source: sasmodels/code_cylinder.py @ d772f5d

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

Added 1D Fit, fixed fitting error

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