source: sasmodels/sasmodels/kernel_iq.c @ 256dfe1

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

simplify kernels by remove coordination parameter logic

  • Property mode set to 100644
File size: 6.4 KB
RevLine 
[2e44ac7]1
2/*
3    ##########################################################
4    #                                                        #
5    #   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!   #
6    #   !!                                              !!   #
7    #   !!  KEEP THIS CODE CONSISTENT WITH KERNELPY.PY  !!   #
8    #   !!                                              !!   #
9    #   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!   #
10    #                                                        #
11    ##########################################################
12*/
13
[03cac08]14#ifndef _PAR_BLOCK_ // protected block so we can include this code twice.
15#define _PAR_BLOCK_
[2e44ac7]16
17typedef struct {
[60eab2a]18#if MAX_PD > 0
[a6f9577]19    int32_t pd_par[MAX_PD];     // id of the nth polydispersity variable
[5cf3c33]20    int32_t pd_length[MAX_PD];  // length of the nth polydispersity weight vector
[0a7e5eb4]21    int32_t pd_offset[MAX_PD];  // offset of pd weights in the value & weight vector
[5cf3c33]22    int32_t pd_stride[MAX_PD];  // stride to move to the next index at this level
[60eab2a]23#endif // MAX_PD > 0
[a738209]24    int32_t pd_prod;            // total number of voxels in hypercube
25    int32_t pd_sum;             // total length of the weights vector
[5ff1b03]26    int32_t num_active;         // number of non-trivial pd loops
[0a7e5eb4]27    int32_t theta_par;          // id of spherical correction variable
[2e44ac7]28} ProblemDetails;
29
30typedef struct {
[03cac08]31    PARAMETER_TABLE;
[2e44ac7]32} ParameterBlock;
[03cac08]33#endif
34
[2e44ac7]35
[03cac08]36kernel
37void KERNEL_NAME(
[5cf3c33]38    int32_t nq,                 // number of q values
39    const int32_t pd_start,     // where we are in the polydispersity loop
40    const int32_t pd_stop,      // where we are stopping in the polydispersity loop
[6e7ff6d]41    global const ProblemDetails *details,
[0a7e5eb4]42    global const double *values,
[2e44ac7]43    global const double *q, // nq q values, with padding to boundary
[03cac08]44    global double *result,  // nq+3 return values, again with padding
[303d8d6]45    const double cutoff     // cutoff in the polydispersity weight product
[2e44ac7]46    )
47{
[10ddb64]48  // Storage for the current parameter values.  These will be updated as we
49  // walk the polydispersity cube.
[ae2b6b5]50  ParameterBlock local_values;  // current parameter values
[0a7e5eb4]51  double *pvec = (double *)(&local_values);  // Alias named parameters with a vector
[2e44ac7]52
[5ff1b03]53  // Fill in the initial variables
54  #ifdef USE_OPENMP
55  #pragma omp parallel for
56  #endif
57  for (int k=0; k < NPARS; k++) {
[a738209]58    pvec[k] = values[k+2];
[5ff1b03]59  }
[3044216]60
[5ff1b03]61  // Monodisperse computation
[a738209]62  if (details->num_active == 0) {
63    double norm, scale, background;
[5ff1b03]64    #ifdef INVALID
65    if (INVALID(local_values)) { return; }
66    #endif
[3044216]67
[a738209]68    norm = CALL_VOLUME(local_values);
[ae2b6b5]69    scale = values[0];
70    background = values[1];
[f2f67a6]71
[2e44ac7]72    #ifdef USE_OPENMP
73    #pragma omp parallel for
74    #endif
[ae2b6b5]75    for (int q_index=0; q_index < nq; q_index++) {
76      double scattering = CALL_IQ(q, q_index, local_values);
77      result[q_index] = (norm>0. ? scale*scattering/norm + background : background);
[2e44ac7]78    }
[5ff1b03]79    return;
[2e44ac7]80  }
81
[5ff1b03]82#if MAX_PD > 0
83
[a738209]84  const double *pd_value = values+2+NPARS;
85  const double *pd_weight = pd_value+details->pd_sum;
86
[5ff1b03]87  // need product of weights at every Iq calc, so keep product of
88  // weights from the outer loops so that weight = partial_weight * fast_weight
[a738209]89  double pd_norm;
[ae2b6b5]90  double partial_weight; // product of weight w4*w3*w2 but not w1
91  double spherical_correction; // cosine correction for latitude variation
92  double weight; // product of partial_weight*w1*spherical_correction
[5ff1b03]93
[ae2b6b5]94  // Number of elements in the longest polydispersity loop
[a738209]95  const int p0_par = details->pd_par[0];
96  const int p0_length = details->pd_length[0];
97  const int p0_offset = details->pd_offset[0];
98  const int p0_is_theta = (p0_par == details->theta_par);
99  int p0_index;
[380e8c9]100
[f9245d4]101  // Trigger the reset behaviour that happens at the end the fast loop
102  // by setting the initial index >= weight vector length.
[a738209]103  p0_index = p0_length;
[3044216]104
[ae2b6b5]105  // Default the spherical correction to 1.0 in case it is not otherwise set
106  spherical_correction = 1.0;
107
108  // Since we are no longer looping over the entire polydispersity hypercube
109  // for each q, we need to track the result and normalization values between
110  // calls.  This means initializing them to 0 at the start and accumulating
111  // them between calls.
[a738209]112  pd_norm = (pd_start == 0 ? 0.0 : result[nq]);
113
[ae2b6b5]114  if (pd_start == 0) {
115    #ifdef USE_OPENMP
116    #pragma omp parallel for
117    #endif
118    for (int q_index=0; q_index < nq; q_index++) {
119      result[q_index] = 0.0;
120    }
121  }
[f2f67a6]122
[2e44ac7]123  // Loop over the weights then loop over q, accumulating values
124  for (int loop_index=pd_start; loop_index < pd_stop; loop_index++) {
[f2f67a6]125    // check if fast loop needs to be reset
[a738209]126    if (p0_index == p0_length) {
[5ff1b03]127
[a738209]128      // Compute position in polydispersity hypercube and partial weight
[2e44ac7]129      partial_weight = 1.0;
[a738209]130      for (int k=1; k < details->num_active; k++) {
131        int pk = details->pd_par[k];
132        int index = details->pd_offset[k] + (loop_index/details->pd_stride[k])%details->pd_length[k];
133        pvec[pk] = pd_value[index];
134        partial_weight *= pd_weight[index];
135        if (pk == details->theta_par) {
136          spherical_correction = fmax(fabs(cos(M_PI_180*pvec[pk])), 1.e-6);
[2e44ac7]137        }
[03cac08]138      }
[a738209]139      p0_index = loop_index%p0_length;
[5ff1b03]140    }
141
[a738209]142    // Update parameter p0
143    weight = partial_weight*pd_weight[p0_offset + p0_index];
144    pvec[p0_par] = pd_value[p0_offset + p0_index];
145    if (p0_is_theta) {
146      spherical_correction = fmax(fabs(cos(M_PI_180*pvec[p0_par])), 1.e-6);
[2e44ac7]147    }
[a738209]148    p0_index++;
[ae2b6b5]149
[3044216]150    #ifdef INVALID
[0a7e5eb4]151    if (INVALID(local_values)) continue;
[3044216]152    #endif
[208f0a4]153
[303d8d6]154    // Accumulate I(q)
155    // Note: weight==0 must always be excluded
[10ddb64]156    if (weight > cutoff) {
[5ff1b03]157      // spherical correction has some nasty effects when theta is +90 or -90
158      // where it becomes zero.  If the entirety of the correction
159      weight *= spherical_correction;
[a738209]160      pd_norm += weight * CALL_VOLUME(local_values);
[3044216]161
[10ddb64]162      #ifdef USE_OPENMP
163      #pragma omp parallel for
164      #endif
[ae2b6b5]165      for (int q_index=0; q_index < nq; q_index++) {
166        const double scattering = CALL_IQ(q, q_index, local_values);
167        result[q_index] += weight*scattering;
[3044216]168      }
[03cac08]169    }
[2e44ac7]170  }
[ea1f14d]171
[a738209]172  if (pd_stop >= details->pd_prod) {
[ae2b6b5]173    // End of the PD loop we can normalize
174    double scale, background;
175    scale = values[0];
176    background = values[1];
[2e44ac7]177    #ifdef USE_OPENMP
178    #pragma omp parallel for
179    #endif
[ae2b6b5]180    for (int q_index=0; q_index < nq; q_index++) {
[a738209]181      result[q_index] = (pd_norm>0. ? scale*result[q_index]/pd_norm + background : background);
[2e44ac7]182    }
183  }
[f2f67a6]184
185  // Remember the updated norm.
[a738209]186  result[nq] = pd_norm;
[60eab2a]187#endif // MAX_PD > 0
[2e44ac7]188}
Note: See TracBrowser for help on using the repository browser.