source: sasmodels/sasmodels/kernel_iq.c @ e1bdc7e

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

add some debugging statements

  • Property mode set to 100644
File size: 7.3 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
17#define MAX_PD 4  // MAX_PD is the max number of polydisperse parameters
18
19typedef struct {
20    int pd_par[MAX_PD];     // index of the nth polydispersity variable
21    int pd_length[MAX_PD];  // length of the nth polydispersity weight vector
22    int pd_offset[MAX_PD];  // offset of pd weights in the par & weight vector
23    int pd_stride[MAX_PD];  // stride to move to the next index at this level
24    int pd_isvol[MAX_PD];   // True if parameter is a volume weighting parameter
25    int par_offset[NPARS];  // offset of par values in the par & weight vector
26    int par_coord[NPARS];   // polydispersity coordination bitvector
27    int fast_coord_index[NPARS]; // index of the fast coordination parameters
28    int fast_coord_count;   // number of parameters coordinated with pd 1
29    int theta_var;          // id of spherical correction variable
30    int fast_theta;         // true if spherical correction depends on pd 1
31} ProblemDetails;
32
33typedef struct {
34    PARAMETER_TABLE;
35} ParameterBlock;
36#endif
37
38
39kernel
40void KERNEL_NAME(
41    int nq,                 // number of q values
42    const int pd_start,     // where we are in the polydispersity loop
43    const int pd_stop,      // where we are stopping in the polydispersity loop
44    global const ProblemDetails *problem,
45    global const double *weights,
46    global const double *pars,
47    global const double *q, // nq q values, with padding to boundary
48    global double *result,  // nq+3 return values, again with padding
49    const double cutoff     // cutoff in the polydispersity weight product
50    )
51{
52printf("aliasing\n");
53  // Storage for the current parameter values.  These will be updated as we
54  // walk the polydispersity cube.
55  local ParameterBlock local_pars;  // current parameter values
56  double *pvec = (double *)(&local_pars);  // Alias named parameters with a vector
57
58printf("allocating\n");
59  local int offset[NPARS-2];
60
61#if 1 // defined(USE_SHORTCUT_OPTIMIZATION)
62printf("dereferencing %p as %d\n", problem, problem->pd_length[0]);
63  if (problem->pd_length[0] == 1) {
64    // Shouldn't need to copy!!
65    printf("copying\n");
66    for (int k=0; k < NPARS; k++) {
67      pvec[k] = pars[k+2];  // skip scale and background
68    }
69    printf("calculating\n");
70
71    #ifdef USE_OPENMP
72    #pragma omp parallel for
73    #endif
74    for (int i=0; i < nq; i++) {
75      const double scattering = CALL_IQ(q, i, local_pars);
76      result[i] += pars[0]*scattering + pars[1];
77    }
78    printf("returning\n");
79    return;
80  }
81  printf("falling through\n");
82#endif
83
84
85  // Since we are no longer looping over the entire polydispersity hypercube
86  // for each q, we need to track the normalization values for each q in a
87  // separate work vector.
88  double norm;   // contains sum over weights
89  double vol; // contains sum over volume
90  double norm_vol; // contains weights over volume
91
92  // Initialize the results to zero
93  if (pd_start == 0) {
94    norm_vol = 0.0;
95    norm = 0.0;
96    vol = 0.0;
97
98    #ifdef USE_OPENMP
99    #pragma omp parallel for
100    #endif
101    for (int i=0; i < nq; i++) {
102      result[i] = 0.0;
103    }
104  } else {
105    //Pulling values from previous segment
106    norm = result[nq];
107    vol = result[nq+1];
108    norm_vol = result[nq+2];
109  }
110
111  // Location in the polydispersity hypercube, one index per dimension.
112  local int pd_index[MAX_PD];
113
114  // Trigger the reset behaviour that happens at the end the fast loop
115  // by setting the initial index >= weight vector length.
116  pd_index[0] = problem->pd_length[0];
117
118
119  // need product of weights at every Iq calc, so keep product of
120  // weights from the outer loops so that weight = partial_weight * fast_weight
121  double partial_weight = NAN; // product of weight w4*w3*w2 but not w1
122  double partial_volweight = NAN;
123  double weight = 1.0;        // set to 1 in case there are no weights
124  double vol_weight = 1.0;    // set to 1 in case there are no vol weights
125  double spherical_correction = 1.0;  // correction for latitude variation
126
127  // Loop over the weights then loop over q, accumulating values
128  for (int loop_index=pd_start; loop_index < pd_stop; loop_index++) {
129    // check if indices need to be updated
130    if (pd_index[0] >= problem->pd_length[0]) {
131
132      // RESET INDICES
133      pd_index[0] = loop_index%problem->pd_length[0];
134      partial_weight = 1.0;
135      partial_volweight = 1.0;
136      for (int k=1; k < MAX_PD; k++) {
137        pd_index[k] = (loop_index%problem->pd_length[k])/problem->pd_stride[k];
138        const double wi = weights[problem->pd_offset[0]+pd_index[0]];
139        partial_weight *= wi;
140        if (problem->pd_isvol[k]) partial_volweight *= wi;
141      }
142      for (int k=0; k < NPARS; k++) {
143        int coord = problem->par_coord[k];
144        int this_offset = problem->par_offset[k];
145        int block_size = 1;
146        for (int bit=0; bit < MAX_PD && coord != 0; bit++) {
147          if (coord&1) {
148              this_offset += block_size * pd_index[bit];
149              block_size *= problem->pd_length[bit];
150          }
151          coord /= 2;
152        }
153        offset[k] = this_offset;
154        pvec[k] = pars[this_offset];
155      }
156      weight = partial_weight * weights[problem->pd_offset[0]+pd_index[0]];
157      if (problem->theta_var >= 0) {
158        spherical_correction = fabs(cos(M_PI_180*pvec[problem->theta_var]));
159      }
160      if (!problem->fast_theta) {
161        weight *= spherical_correction;
162      }
163
164    } else {
165
166      // INCREMENT INDICES
167      pd_index[0] += 1;
168      const double wi = weights[problem->pd_offset[0]+pd_index[0]];
169      weight = partial_weight*wi;
170      if (problem->pd_isvol[0]) vol_weight *= wi;
171      for (int k=0; k < problem->fast_coord_count; k++) {
172        pvec[problem->fast_coord_index[k]]
173            = pars[offset[problem->fast_coord_index[k]]++];
174      }
175      if (problem->fast_theta) {
176        weight *= fabs(cos(M_PI_180*pvec[problem->theta_var]));
177      }
178    }
179
180    #ifdef INVALID
181    if (INVALID(local_pars)) continue;
182    #endif
183
184    // Accumulate I(q)
185    // Note: weight==0 must always be excluded
186    if (weight > cutoff) {
187      norm += weight;
188      vol += vol_weight * CALL_VOLUME(local_pars);
189      norm_vol += vol_weight;
190
191      #ifdef USE_OPENMP
192      #pragma omp parallel for
193      #endif
194      for (int i=0; i < nq; i++) {
195        const double scattering = CALL_IQ(q, i, local_pars);
196        result[i] += weight*scattering;
197      }
198    }
199  }
200  //Makes a normalization avialable for the next round
201  result[nq] = norm;
202  result[nq+1] = vol;
203  result[nq+2] = norm_vol;
204
205  //End of the PD loop we can normalize
206  if (pd_stop >= problem->pd_stride[MAX_PD-1]) {
207    #ifdef USE_OPENMP
208    #pragma omp parallel for
209    #endif
210    for (int i=0; i < nq; i++) {
211      if (vol*norm_vol != 0.0) {
212        result[i] *= norm_vol/vol;
213      }
214      result[i] = pars[0]*result[i]/norm + pars[1];
215    }
216  }
217}
Note: See TracBrowser for help on using the repository browser.