source: sasmodels/sasmodels/kernel_iq.c @ 7b7da6b

core_shell_microgelscostrafo411magnetic_modelrelease_v0.94release_v0.95ticket-1257-vesicle-productticket_1156ticket_1265_superballticket_822_more_unit_tests
Last change on this file since 7b7da6b was 7b7da6b, checked in by Paul Kienzle <pkienzle@…>, 8 years ago

remove unused variable warnings for pd_values/pd_weights

  • Property mode set to 100644
File size: 11.0 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 pd_prod;            // total number of voxels in hypercube
25    int32_t pd_sum;             // 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
28} ProblemDetails;
29
30typedef struct {
31    PARAMETER_TABLE;
32} ParameterBlock;
33#endif // _PAR_BLOCK_
34
35
36#ifdef MAGNETIC
37// Return value restricted between low and high
38static double clip(double value, double low, double high)
39{
40  return (value < low ? low : (value > high ? high : value));
41}
42
43// Compute spin cross sections given in_spin and out_spin
44// To convert spin cross sections to sld b:
45//     uu * (sld - m_sigma_x);
46//     dd * (sld + m_sigma_x);
47//     ud * (m_sigma_y + 1j*m_sigma_z);
48//     du * (m_sigma_y - 1j*m_sigma_z);
49static void spins(double in_spin, double out_spin,
50    double *uu, double *dd, double *ud, double *du)
51{
52  in_spin = clip(in_spin, 0.0, 1.0);
53  out_spin = clip(out_spin, 0.0, 1.0);
54  *uu = sqrt(sqrt(in_spin * out_spin));
55  *dd = sqrt(sqrt((1.0-in_spin) * (1.0-out_spin)));
56  *ud = sqrt(sqrt(in_spin * (1.0-out_spin)));
57  *du = sqrt(sqrt((1.0-in_spin) * out_spin));
58}
59
60#endif // MAGNETIC
61
62kernel
63void KERNEL_NAME(
64    int32_t nq,                 // number of q values
65    const int32_t pd_start,     // where we are in the polydispersity loop
66    const int32_t pd_stop,      // where we are stopping in the polydispersity loop
67    global const ProblemDetails *details,
68    global const double *values,
69    global const double *q, // nq q values, with padding to boundary
70    global double *result,  // nq+1 return values, again with padding
71    const double cutoff     // cutoff in the polydispersity weight product
72    )
73{
74
75  // Storage for the current parameter values.  These will be updated as we
76  // walk the polydispersity cube.  local_values will be aliased to pvec.
77  ParameterBlock local_values;
78  double *pvec = (double *)&local_values;
79
80#ifdef MAGNETIC
81  // Location of the sld parameters in the parameter pvec.
82  // These parameters are updated with the effective sld due to magnetism.
83  const int32_t slds[] = { MAGNETIC_PARS };
84
85  const double up_frac_i = values[NPARS+2];
86  const double up_frac_f = values[NPARS+3];
87  const double up_angle = values[NPARS+4];
88  #define MX(_k) (values[NPARS+5+3*_k])
89  #define MY(_k) (values[NPARS+6+3*_k])
90  #define MZ(_k) (values[NPARS+7+3*_k])
91
92  // TODO: could precompute these outside of the kernel.
93  // Interpret polarization cross section.
94  double uu, dd, ud, du;
95  double cos_mspin, sin_mspin;
96  spins(up_frac_i, up_frac_f, &uu, &dd, &ud, &du);
97  SINCOS(-up_angle*M_PI_180, sin_mspin, cos_mspin);
98#endif // MAGNETIC
99
100  // Fill in the initial variables
101  //   values[0] is scale
102  //   values[1] is background
103  #ifdef USE_OPENMP
104  #pragma omp parallel for
105  #endif
106  for (int i=0; i < NPARS; i++) {
107    pvec[i] = values[2+i];
108//printf("p%d = %g\n",i, pvec[i]);
109  }
110
111  double pd_norm;
112//printf("start: %d %d\n",pd_start, pd_stop);
113  if (pd_start == 0) {
114    pd_norm = 0.0;
115    #ifdef USE_OPENMP
116    #pragma omp parallel for
117    #endif
118    for (int q_index=0; q_index < nq; q_index++) result[q_index] = 0.0;
119//printf("initializing %d\n", nq);
120  } else {
121    pd_norm = result[nq];
122  }
123//printf("start %d %g %g\n", pd_start, pd_norm, result[0]);
124
125#if MAX_PD>0
126  global const double *pd_value = values + NUM_VALUES + 2;
127  global const double *pd_weight = pd_value + details->pd_sum;
128#endif
129
130  // Jump into the middle of the polydispersity loop
131#if MAX_PD>4
132  int n4=details->pd_length[4];
133  int i4=(pd_start/details->pd_stride[4])%n4;
134  const int p4=details->pd_par[4];
135  global const double *v4 = pd_value + details->pd_offset[4];
136  global const double *w4 = pd_weight + details->pd_offset[4];
137#endif
138#if MAX_PD>3
139  int n3=details->pd_length[3];
140  int i3=(pd_start/details->pd_stride[3])%n3;
141  const int p3=details->pd_par[3];
142  global const double *v3 = pd_value + details->pd_offset[3];
143  global const double *w3 = pd_weight + details->pd_offset[3];
144//printf("offset %d: %d %d\n", 3, details->pd_offset[3], NUM_VALUES);
145#endif
146#if MAX_PD>2
147  int n2=details->pd_length[2];
148  int i2=(pd_start/details->pd_stride[2])%n2;
149  const int p2=details->pd_par[2];
150  global const double *v2 = pd_value + details->pd_offset[2];
151  global const double *w2 = pd_weight + details->pd_offset[2];
152#endif
153#if MAX_PD>1
154  int n1=details->pd_length[1];
155  int i1=(pd_start/details->pd_stride[1])%n1;
156  const int p1=details->pd_par[1];
157  global const double *v1 = pd_value + details->pd_offset[1];
158  global const double *w1 = pd_weight + details->pd_offset[1];
159#endif
160#if MAX_PD>0
161  int n0=details->pd_length[0];
162  int i0=(pd_start/details->pd_stride[0])%n0;
163  const int p0=details->pd_par[0];
164  global const double *v0 = pd_value + details->pd_offset[0];
165  global const double *w0 = pd_weight + details->pd_offset[0];
166//printf("w0:%p, values:%p, diff:%d, %d\n",w0,values,(w0-values),NUM_VALUES);
167#endif
168
169
170  double spherical_correction=1.0;
171  const int theta_par = details->theta_par;
172#if MAX_PD>0
173  const int fast_theta = (theta_par == p0);
174  const int slow_theta = (theta_par >= 0 && !fast_theta);
175#else
176  const int slow_theta = (theta_par >= 0);
177#endif
178
179  int step = pd_start;
180
181
182#if MAX_PD>4
183  const double weight5 = 1.0;
184  while (i4 < n4) {
185    pvec[p4] = v4[i4];
186    double weight4 = w4[i4] * weight5;
187//printf("step:%d level %d: p:%d i:%d n:%d value:%g weight:%g\n", step, 4, p4, i4, n4, pvec[p4], weight4);
188#elif MAX_PD>3
189    const double weight4 = 1.0;
190#endif
191#if MAX_PD>3
192  while (i3 < n3) {
193    pvec[p3] = v3[i3];
194    double weight3 = w3[i3] * weight4;
195//printf("step:%d level %d: p:%d i:%d n:%d value:%g weight:%g\n", step, 3, p3, i3, n3, pvec[p3], weight3);
196#elif MAX_PD>2
197    const double weight3 = 1.0;
198#endif
199#if MAX_PD>2
200  while (i2 < n2) {
201    pvec[p2] = v2[i2];
202    double weight2 = w2[i2] * weight3;
203//printf("step:%d level %d: p:%d i:%d n:%d value:%g weight:%g\n", step, 2, p2, i2, n2, pvec[p2], weight2);
204#elif MAX_PD>1
205    const double weight2 = 1.0;
206#endif
207#if MAX_PD>1
208  while (i1 < n1) {
209    pvec[p1] = v1[i1];
210    double weight1 = w1[i1] * weight2;
211//printf("step:%d level %d: p:%d i:%d n:%d value:%g weight:%g\n", step, 1, p1, i1, n1, pvec[p1], weight1);
212#elif MAX_PD>0
213    const double weight1 = 1.0;
214#endif
215    if (slow_theta) { // Theta is not in inner loop
216      spherical_correction = fmax(fabs(cos(M_PI_180*pvec[theta_par])), 1.e-6);
217    }
218#if MAX_PD>0
219  while(i0 < n0) {
220    pvec[p0] = v0[i0];
221    double weight0 = w0[i0] * weight1;
222//printf("step:%d level %d: p:%d i:%d n:%d value:%g weight:%g\n", step, 0, p0, i0, n0, pvec[p0], weight0);
223    if (fast_theta) { // Theta is in inner loop
224      spherical_correction = fmax(fabs(cos(M_PI_180*pvec[p0])), 1.e-6);
225    }
226#else
227    const double weight0 = 1.0;
228#endif
229
230//printf("step:%d of %d, pars:",step,pd_stop); for (int i=0; i < NPARS; i++) printf("p%d=%g ",i, pvec[i]); printf("\n");
231//printf("sphcor: %g\n", spherical_correction);
232
233    #ifdef INVALID
234    if (!INVALID(local_values))
235    #endif
236    {
237      // Accumulate I(q)
238      // Note: weight==0 must always be excluded
239      if (weight0 > cutoff) {
240        // spherical correction has some nasty effects when theta is +90 or -90
241        // where it becomes zero.
242        const double weight = weight0 * spherical_correction;
243        pd_norm += weight * CALL_VOLUME(local_values);
244
245        #ifdef USE_OPENMP
246        #pragma omp parallel for
247        #endif
248        for (int q_index=0; q_index<nq; q_index++) {
249#ifdef MAGNETIC
250          const double qx = q[2*q_index];
251          const double qy = q[2*q_index+1];
252          const double qsq = qx*qx + qy*qy;
253
254          // Constant across orientation, polydispersity for given qx, qy
255          double px, py, pz;
256          if (qsq > 1.e-16) {
257            px = (qy*cos_mspin + qx*sin_mspin)/qsq;
258            py = (qy*sin_mspin - qx*cos_mspin)/qsq;
259            pz = 1.0;
260          } else {
261            px = py = pz = 0.0;
262          }
263
264          double scattering = 0.0;
265          if (uu > 1.e-8) {
266            for (int sk=0; sk<NUM_MAGNETIC; sk++) {
267                const double perp = (qy*MX(sk) - qx*MY(sk));
268                pvec[slds[sk]] = (values[slds[sk]+2] - perp*px)*uu;
269            }
270            scattering += CALL_IQ(q, q_index, local_values);
271          }
272          if (dd > 1.e-8){
273            for (int sk=0; sk<NUM_MAGNETIC; sk++) {
274                const double perp = (qy*MX(sk) - qx*MY(sk));
275                pvec[slds[sk]] = (values[slds[sk]+2] + perp*px)*dd;
276            }
277            scattering += CALL_IQ(q, q_index, local_values);
278          }
279          if (ud > 1.e-8){
280            for (int sk=0; sk<NUM_MAGNETIC; sk++) {
281                const double perp = (qy*MX(sk) - qx*MY(sk));
282                pvec[slds[sk]] = perp*py*ud;
283            }
284            scattering += CALL_IQ(q, q_index, local_values);
285            for (int sk=0; sk<NUM_MAGNETIC; sk++) {
286                pvec[slds[sk]] = MZ(sk)*pz*ud;
287            }
288            scattering += CALL_IQ(q, q_index, local_values);
289          }
290          if (du > 1.e-8) {
291            for (int sk=0; sk<NUM_MAGNETIC; sk++) {
292                const double perp = (qy*MX(sk) - qx*MY(sk));
293                pvec[slds[sk]] = perp*py*du;
294            }
295            scattering += CALL_IQ(q, q_index, local_values);
296            for (int sk=0; sk<NUM_MAGNETIC; sk++) {
297                pvec[slds[sk]] = -MZ(sk)*pz*du;
298            }
299            scattering += CALL_IQ(q, q_index, local_values);
300          }
301#else  // !MAGNETIC
302          const double scattering = CALL_IQ(q, q_index, local_values);
303#endif // !MAGNETIC
304//printf("q_index:%d %g %g %g %g\n",q_index, scattering, weight, spherical_correction, weight0);
305          result[q_index] += weight * scattering;
306        }
307      }
308    }
309    ++step;
310#if MAX_PD>0
311    if (step >= pd_stop) break;
312    ++i0;
313  }
314  i0 = 0;
315#endif
316#if MAX_PD>1
317    if (step >= pd_stop) break;
318    ++i1;
319  }
320  i1 = 0;
321#endif
322#if MAX_PD>2
323    if (step >= pd_stop) break;
324    ++i2;
325  }
326  i2 = 0;
327#endif
328#if MAX_PD>3
329    if (step >= pd_stop) break;
330    ++i3;
331  }
332  i3 = 0;
333#endif
334#if MAX_PD>4
335    if (step >= pd_stop) break;
336    ++i4;
337  }
338  i4 = 0;
339#endif
340
341//printf("res: %g/%g\n", result[0], pd_norm);
342  // Remember the updated norm.
343  result[nq] = pd_norm;
344}
Note: See TracBrowser for help on using the repository browser.