source: sasmodels/sasmodels/kernel_iq.c @ 4b2972c

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

remove docs from kernel_iq

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