source: sasmodels/sasmodels/kernel_iq.cl @ d4c33d6

core_shell_microgelsmagnetic_modelticket-1257-vesicle-productticket_1156ticket_1265_superballticket_822_more_unit_tests
Last change on this file since d4c33d6 was d4c33d6, checked in by Paul Kienzle <pkienzle@…>, 7 years ago

send cos-weighted theta values to kernel rather than computing them inside

  • Property mode set to 100644
File size: 10.7 KB
Line 
1
2/*
3    ##########################################################
4    #                                                        #
5    #   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!   #
6    #   !!                                              !!   #
7    #   !!  KEEP THIS CODE CONSISTENT WITH KERNELPY.PY  !!   #
8    #   !!                                              !!   #
9    #   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!   #
10    #                                                        #
11    ##########################################################
12*/
13
14#ifndef _PAR_BLOCK_ // protected block so we can include this code twice.
15#define _PAR_BLOCK_
16
17typedef struct {
18#if MAX_PD > 0
19    int32_t pd_par[MAX_PD];     // id of the nth polydispersity variable
20    int32_t pd_length[MAX_PD];  // length of the nth polydispersity weight vector
21    int32_t pd_offset[MAX_PD];  // offset of pd weights in the value & weight vector
22    int32_t pd_stride[MAX_PD];  // stride to move to the next index at this level
23#endif // MAX_PD > 0
24    int32_t num_eval;           // total number of voxels in hypercube
25    int32_t num_weights;        // total length of the weights vector
26    int32_t num_active;         // number of non-trivial pd loops
27    int32_t theta_par;          // id of spherical correction variable (not used)
28} ProblemDetails;
29
30// Intel HD 4000 needs private arrays to be a multiple of 4 long
31typedef struct {
32    PARAMETER_TABLE
33} ParameterTable;
34typedef union {
35    ParameterTable table;
36    double vector[4*((NUM_PARS+3)/4)];
37} ParameterBlock;
38#endif // _PAR_BLOCK_
39
40
41#if defined(MAGNETIC) && NUM_MAGNETIC>0
42
43// Return value restricted between low and high
44static double clip(double value, double low, double high)
45{
46  return (value < low ? low : (value > high ? high : value));
47}
48
49// Compute spin cross sections given in_spin and out_spin
50// To convert spin cross sections to sld b:
51//     uu * (sld - m_sigma_x);
52//     dd * (sld + m_sigma_x);
53//     ud * (m_sigma_y + 1j*m_sigma_z);
54//     du * (m_sigma_y - 1j*m_sigma_z);
55static void set_spins(double in_spin, double out_spin, double spins[4])
56{
57  in_spin = clip(in_spin, 0.0, 1.0);
58  out_spin = clip(out_spin, 0.0, 1.0);
59  spins[0] = sqrt(sqrt((1.0-in_spin) * (1.0-out_spin))); // dd
60  spins[1] = sqrt(sqrt((1.0-in_spin) * out_spin));       // du
61  spins[2] = sqrt(sqrt(in_spin * (1.0-out_spin)));       // ud
62  spins[3] = sqrt(sqrt(in_spin * out_spin));             // uu
63}
64
65static double mag_sld(double qx, double qy, double p,
66                       double mx, double my, double sld)
67{
68    const double perp = qy*mx - qx*my;
69    return sld + perp*p;
70}
71
72#endif // MAGNETIC
73
74kernel
75void KERNEL_NAME(
76    int32_t nq,                 // number of q values
77    const int32_t pd_start,     // where we are in the polydispersity loop
78    const int32_t pd_stop,      // where we are stopping in the polydispersity loop
79    global const ProblemDetails *details,
80    global const double *values,
81    global const double *q, // nq q values, with padding to boundary
82    global double *result,  // nq+1 return values, again with padding
83    const double cutoff     // cutoff in the polydispersity weight product
84    )
85{
86
87  // who we are and what element we are working with
88  const int q_index = get_global_id(0);
89  if (q_index >= nq) return;
90
91  // Storage for the current parameter values.  These will be updated as we
92  // walk the polydispersity cube.
93  ParameterBlock local_values;
94
95#if defined(MAGNETIC) && NUM_MAGNETIC>0
96  // Location of the sld parameters in the parameter vector.
97  // These parameters are updated with the effective sld due to magnetism.
98  #if NUM_MAGNETIC > 3
99  const int32_t slds[] = { MAGNETIC_PARS };
100  #endif
101
102  // TODO: could precompute these outside of the kernel.
103  // Interpret polarization cross section.
104  //     up_frac_i = values[NUM_PARS+2];
105  //     up_frac_f = values[NUM_PARS+3];
106  //     up_angle = values[NUM_PARS+4];
107  double spins[4];
108  double cos_mspin, sin_mspin;
109  set_spins(values[NUM_PARS+2], values[NUM_PARS+3], spins);
110  SINCOS(-values[NUM_PARS+4]*M_PI_180, sin_mspin, cos_mspin);
111#endif // MAGNETIC
112
113  // Fill in the initial variables
114  //   values[0] is scale
115  //   values[1] is background
116  for (int i=0; i < NUM_PARS; i++) {
117    local_values.vector[i] = values[2+i];
118//if (q_index==0) printf("p%d = %g\n",i, local_values.vector[i]);
119  }
120//if (q_index==0) printf("NUM_VALUES:%d  NUM_PARS:%d  MAX_PD:%d\n", NUM_VALUES, NUM_PARS, MAX_PD);
121//if (q_index==0) printf("start:%d stop:%d\n", pd_start, pd_stop);
122
123  double pd_norm = (pd_start == 0 ? 0.0 : result[nq]);
124  double this_result = (pd_start == 0 ? 0.0 : result[q_index]);
125//if (q_index==0) printf("start %d %g %g\n", pd_start, pd_norm, this_result);
126
127#if MAX_PD>0
128  global const double *pd_value = values + NUM_VALUES;
129  global const double *pd_weight = pd_value + details->num_weights;
130#endif
131
132  // Jump into the middle of the polydispersity loop
133#if MAX_PD>4
134  int n4=details->pd_length[4];
135  int i4=(pd_start/details->pd_stride[4])%n4;
136  const int p4=details->pd_par[4];
137  global const double *v4 = pd_value + details->pd_offset[4];
138  global const double *w4 = pd_weight + details->pd_offset[4];
139#endif
140#if MAX_PD>3
141  int n3=details->pd_length[3];
142  int i3=(pd_start/details->pd_stride[3])%n3;
143  const int p3=details->pd_par[3];
144  global const double *v3 = pd_value + details->pd_offset[3];
145  global const double *w3 = pd_weight + details->pd_offset[3];
146//if (q_index==0) printf("offset %d: %d %d\n", 3, details->pd_offset[3], NUM_VALUES);
147#endif
148#if MAX_PD>2
149  int n2=details->pd_length[2];
150  int i2=(pd_start/details->pd_stride[2])%n2;
151  const int p2=details->pd_par[2];
152  global const double *v2 = pd_value + details->pd_offset[2];
153  global const double *w2 = pd_weight + details->pd_offset[2];
154#endif
155#if MAX_PD>1
156  int n1=details->pd_length[1];
157  int i1=(pd_start/details->pd_stride[1])%n1;
158  const int p1=details->pd_par[1];
159  global const double *v1 = pd_value + details->pd_offset[1];
160  global const double *w1 = pd_weight + details->pd_offset[1];
161#endif
162#if MAX_PD>0
163  int n0=details->pd_length[0];
164  int i0=(pd_start/details->pd_stride[0])%n0;
165  const int p0=details->pd_par[0];
166  global const double *v0 = pd_value + details->pd_offset[0];
167  global const double *w0 = pd_weight + details->pd_offset[0];
168#endif
169
170
171  int step = pd_start;
172
173
174#if MAX_PD>4
175  const double weight5 = 1.0;
176  while (i4 < n4) {
177    local_values.vector[p4] = v4[i4];
178    double weight4 = w4[i4] * weight5;
179//if (q_index == 0) printf("step:%d level %d: p:%d i:%d n:%d value:%g weight:%g\n", step, 4, p4, i4, n4, local_values.vector[p4], weight4);
180#elif MAX_PD>3
181    const double weight4 = 1.0;
182#endif
183#if MAX_PD>3
184  while (i3 < n3) {
185    local_values.vector[p3] = v3[i3];
186    double weight3 = w3[i3] * weight4;
187//if (q_index == 0) printf("step:%d level %d: p:%d i:%d n:%d value:%g weight:%g\n", step, 3, p3, i3, n3, local_values.vector[p3], weight3);
188#elif MAX_PD>2
189    const double weight3 = 1.0;
190#endif
191#if MAX_PD>2
192  while (i2 < n2) {
193    local_values.vector[p2] = v2[i2];
194    double weight2 = w2[i2] * weight3;
195//if (q_index == 0) printf("step:%d level %d: p:%d i:%d n:%d value:%g weight:%g\n", step, 2, p2, i2, n2, local_values.vector[p2], weight2);
196#elif MAX_PD>1
197    const double weight2 = 1.0;
198#endif
199#if MAX_PD>1
200  while (i1 < n1) {
201    local_values.vector[p1] = v1[i1];
202    double weight1 = w1[i1] * weight2;
203//if (q_index == 0) printf("step:%d level %d: p:%d i:%d n:%d value:%g weight:%g\n", step, 1, p1, i1, n1, local_values.vector[p1], weight1);
204#elif MAX_PD>0
205    const double weight1 = 1.0;
206#endif
207#if MAX_PD>0
208  while(i0 < n0) {
209    local_values.vector[p0] = v0[i0];
210    double weight0 = w0[i0] * weight1;
211//if (q_index == 0) printf("step:%d level %d: p:%d i:%d n:%d value:%g weight:%g\n", step, 0, p0, i0, n0, local_values.vector[p0], weight0);
212#else
213    const double weight0 = 1.0;
214#endif
215
216//if (q_index == 0) {printf("step:%d of %d, pars:",step,pd_stop); for (int i=0; i < NUM_PARS; i++) printf("p%d=%g ",i, local_values.vector[i]); printf("\n"); }
217
218    #ifdef INVALID
219    if (!INVALID(local_values.table))
220    #endif
221    {
222      // Accumulate I(q)
223      // Note: weight==0 must always be excluded
224      if (weight0 > cutoff) {
225        pd_norm += weight0 * CALL_VOLUME(local_values.table);
226
227#if defined(MAGNETIC) && NUM_MAGNETIC > 0
228        const double qx = q[2*q_index];
229        const double qy = q[2*q_index+1];
230        const double qsq = qx*qx + qy*qy;
231
232        // Constant across orientation, polydispersity for given qx, qy
233        double scattering = 0.0;
234        // TODO: what is the magnetic scattering at q=0
235        if (qsq > 1.e-16) {
236          double p[4];  // dd, du, ud, uu
237          p[0] = (qy*cos_mspin + qx*sin_mspin)/qsq;
238          p[3] = -p[0];
239          p[1] = p[2] = (qy*sin_mspin - qx*cos_mspin)/qsq;
240
241          for (int index=0; index<4; index++) {
242            const double xs = spins[index];
243            if (xs > 1.e-8) {
244              const int spin_flip = (index==1) || (index==2);
245              const double pk = p[index];
246              for (int axis=0; axis<=spin_flip; axis++) {
247                #define M1 NUM_PARS+5
248                #define M2 NUM_PARS+8
249                #define M3 NUM_PARS+13
250                #define SLD(_M_offset, _sld_offset) \
251                    local_values.vector[_sld_offset] = xs * (axis \
252                    ? (index==1 ? -values[_M_offset+2] : values[_M_offset+2]) \
253                    : mag_sld(qx, qy, pk, values[_M_offset], values[_M_offset+1], \
254                              (spin_flip ? 0.0 : values[_sld_offset+2])))
255                #if NUM_MAGNETIC==1
256                    SLD(M1, MAGNETIC_PAR1);
257                #elif NUM_MAGNETIC==2
258                    SLD(M1, MAGNETIC_PAR1);
259                    SLD(M2, MAGNETIC_PAR2);
260                #elif NUM_MAGNETIC==3
261                    SLD(M1, MAGNETIC_PAR1);
262                    SLD(M2, MAGNETIC_PAR2);
263                    SLD(M3, MAGNETIC_PAR3);
264                #else
265                for (int sk=0; sk<NUM_MAGNETIC; sk++) {
266                    SLD(M1+3*sk, slds[sk]);
267                }
268                #endif
269                scattering += CALL_IQ(q, q_index, local_values.table);
270              }
271            }
272          }
273        }
274#else  // !MAGNETIC
275        const double scattering = CALL_IQ(q, q_index, local_values.table);
276#endif // !MAGNETIC
277        this_result += weight0 * scattering;
278      }
279    }
280    ++step;
281#if MAX_PD>0
282    if (step >= pd_stop) break;
283    ++i0;
284  }
285  i0 = 0;
286#endif
287#if MAX_PD>1
288    if (step >= pd_stop) break;
289    ++i1;
290  }
291  i1 = 0;
292#endif
293#if MAX_PD>2
294    if (step >= pd_stop) break;
295    ++i2;
296  }
297  i2 = 0;
298#endif
299#if MAX_PD>3
300    if (step >= pd_stop) break;
301    ++i3;
302  }
303  i3 = 0;
304#endif
305#if MAX_PD>4
306    if (step >= pd_stop) break;
307    ++i4;
308  }
309  i4 = 0;
310#endif
311
312//if (q_index==0) printf("res: %g/%g\n", this_result, pd_norm);
313  // Remember the current result and the updated norm.
314  result[q_index] = this_result;
315  if (q_index == 0) result[nq] = pd_norm;
316}
Note: See TracBrowser for help on using the repository browser.