source: sasmodels/sasmodels/kernel_iq.c @ ee8f734

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

protect against zero norm

  • Property mode set to 100644
File size: 8.1 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
[5ff1b03]24    int32_t par_offset[NPARS];  // offset of par value blocks in the value & weight vector
25    int32_t par_coord[NPARS];   // ids of the coordination parameters
26    int32_t pd_coord[NPARS];    // polydispersity coordination bitvector
27    int32_t num_active;         // number of non-trivial pd loops
28    int32_t total_pd;           // total number of voxels in hypercube
29    int32_t num_coord;          // number of coordinated parameters
[0a7e5eb4]30    int32_t theta_par;          // id of spherical correction variable
[2e44ac7]31} ProblemDetails;
32
33typedef struct {
[03cac08]34    PARAMETER_TABLE;
[2e44ac7]35} ParameterBlock;
[03cac08]36#endif
37
[2e44ac7]38
[03cac08]39kernel
40void KERNEL_NAME(
[5cf3c33]41    int32_t nq,                 // number of q values
42    const int32_t pd_start,     // where we are in the polydispersity loop
43    const int32_t pd_stop,      // where we are stopping in the polydispersity loop
[2e44ac7]44    global const ProblemDetails *problem,
45    global const double *weights,
[0a7e5eb4]46    global const double *values,
[2e44ac7]47    global const double *q, // nq q values, with padding to boundary
[03cac08]48    global double *result,  // nq+3 return values, again with padding
[303d8d6]49    const double cutoff     // cutoff in the polydispersity weight product
[2e44ac7]50    )
51{
[10ddb64]52  // Storage for the current parameter values.  These will be updated as we
53  // walk the polydispersity cube.
[0a7e5eb4]54  local ParameterBlock local_values;  // current parameter values
55  double *pvec = (double *)(&local_values);  // Alias named parameters with a vector
[2e44ac7]56
[5ff1b03]57  // Fill in the initial variables
58  #ifdef USE_OPENMP
59  #pragma omp parallel for
60  #endif
61  for (int k=0; k < NPARS; k++) {
62    pvec[k] = values[problem->par_offset[k]];
63  }
[3044216]64
[5ff1b03]65  // If it is the first round initialize the result to zero, otherwise
66  // assume that the previous result has been passed back.
67  // Note: doing this even in the monodisperse case in order to handle the
68  // rare case where the model parameters are invalid and zero is returned.
69  // So slightly increased cost for slightly smaller code size.
70  if (pd_start == 0) {
[3044216]71    #ifdef USE_OPENMP
72    #pragma omp parallel for
73    #endif
[5ff1b03]74    for (int i=0; i < nq+1; i++) {
75      result[i] = 0.0;
[3044216]76    }
77  }
[60eab2a]78
[5ff1b03]79  // Monodisperse computation
80  if (problem->num_active == 0) {
81    #ifdef INVALID
82    if (INVALID(local_values)) { return; }
83    #endif
[3044216]84
[5ff1b03]85    const double norm = CALL_VOLUME(local_values);
[398aa94]86    const double scale = values[0];
87    const double background = values[1];
[2e44ac7]88    #ifdef USE_OPENMP
89    #pragma omp parallel for
90    #endif
[5ff1b03]91    result[nq] = norm; // Total volume normalization
[3044216]92    for (int i=0; i < nq; i++) {
[5ff1b03]93      double scattering = CALL_IQ(q, i, local_values);
[398aa94]94      result[i] = (norm>0. ? scale*scattering/norm + background : background);
[2e44ac7]95    }
[5ff1b03]96    return;
[2e44ac7]97  }
98
[5ff1b03]99#if MAX_PD > 0
100  //printf("Entering polydispersity from %d to %d\n", pd_start, pd_stop);
101  // Since we are no longer looping over the entire polydispersity hypercube
102  // for each q, we need to track the normalization values between calls.
103  double norm = 0.0;
104
105  // need product of weights at every Iq calc, so keep product of
106  // weights from the outer loops so that weight = partial_weight * fast_weight
107  double partial_weight = NAN; // product of weight w4*w3*w2 but not w1
108  double spherical_correction = 1.0;  // cosine correction for latitude variation
109
[3044216]110  // Location in the polydispersity hypercube, one index per dimension.
[03cac08]111  local int pd_index[MAX_PD];
[a10da8b]112
[5ff1b03]113  // Location of the coordinated parameters in their own sub-cubes.
114  local int offset[NPARS];
[380e8c9]115
[f9245d4]116  // Trigger the reset behaviour that happens at the end the fast loop
117  // by setting the initial index >= weight vector length.
[5ff1b03]118  const int fast_length = problem->pd_length[0];
119  pd_index[0] = fast_length;
[3044216]120
[2e44ac7]121  // Loop over the weights then loop over q, accumulating values
122  for (int loop_index=pd_start; loop_index < pd_stop; loop_index++) {
123    // check if indices need to be updated
[5ff1b03]124    if (pd_index[0] == fast_length) {
125      //printf("should be here with %d active\n", problem->num_active);
[208f0a4]126
[5ff1b03]127      // Compute position in polydispersity hypercube
128      for (int k=0; k < problem->num_active; k++) {
129        pd_index[k] = (loop_index/problem->pd_stride[k])%problem->pd_length[k];
130        //printf("pd_index[%d] = %d\n",k,pd_index[k]);
131      }
132
133      // Compute partial weights
[2e44ac7]134      partial_weight = 1.0;
[5ff1b03]135      //printf("partial weight %d: ", loop_index);
136      for (int k=1; k < problem->num_active; k++) {
137        double wi = weights[problem->pd_offset[k] + pd_index[k]];
138        //printf("pd[%d]=par[%d]=%g ", k, problem->pd_par[k], wi);
[f78a2a1]139        partial_weight *= wi;
[2e44ac7]140      }
[5ff1b03]141      //printf("\n");
142
143      // Update parameter offsets in weight vector
[ba32cdd]144      //printf("slow %d: ", loop_index);
[5ff1b03]145      for (int k=0; k < problem->num_coord; k++) {
146        int par = problem->par_coord[k];
147        int coord = problem->pd_coord[k];
148        int this_offset = problem->par_offset[par];
[2e44ac7]149        int block_size = 1;
[5ff1b03]150        for (int bit=0; coord != 0; bit++) {
[2e44ac7]151          if (coord&1) {
152              this_offset += block_size * pd_index[bit];
[03cac08]153              block_size *= problem->pd_length[bit];
[2e44ac7]154          }
[5ff1b03]155          coord >>= 1;
156        }
157        offset[par] = this_offset;
158        pvec[par] = values[this_offset];
159        //printf("par[%d]=v[%d]=%g \n", k, offset[k], pvec[k]);
160        // if theta is not coordinated with fast index, precompute spherical correction
161        if (par == problem->theta_par && !(problem->par_coord[k]&1)) {
162          spherical_correction = fmax(fabs(cos(M_PI_180*pvec[problem->theta_par])), 1e-6);
[2e44ac7]163        }
[03cac08]164      }
[ba32cdd]165      //printf("\n");
[5ff1b03]166    }
167
168    // Increment fast index
169    const double wi = weights[problem->pd_offset[0] + pd_index[0]++];
170    double weight = partial_weight*wi;
171    //printf("fast %d: ", loop_index);
172    for (int k=0; k < problem->num_coord; k++) {
173      if (problem->pd_coord[k]&1) {
174        const int par = problem->par_coord[k];
175        pvec[par] = values[offset[par]++];
176        //printf("p[%d]=v[%d]=%g ", par, offset[par]-1, pvec[par]);
177        // if theta is coordinated with fast index, compute spherical correction each time
178        if (par == problem->theta_par) {
179          spherical_correction = fmax(fabs(cos(M_PI_180*pvec[problem->theta_par])), 1e-6);
180        }
[2e44ac7]181      }
182    }
[5ff1b03]183    //printf("\n");
184
[3044216]185    #ifdef INVALID
[0a7e5eb4]186    if (INVALID(local_values)) continue;
[3044216]187    #endif
[208f0a4]188
[303d8d6]189    // Accumulate I(q)
190    // Note: weight==0 must always be excluded
[10ddb64]191    if (weight > cutoff) {
[5ff1b03]192      // spherical correction has some nasty effects when theta is +90 or -90
193      // where it becomes zero.  If the entirety of the correction
194      weight *= spherical_correction;
195      norm += weight * CALL_VOLUME(local_values);
[3044216]196
[10ddb64]197      #ifdef USE_OPENMP
198      #pragma omp parallel for
199      #endif
[3044216]200      for (int i=0; i < nq; i++) {
[0a7e5eb4]201        const double scattering = CALL_IQ(q, i, local_values);
[3044216]202        result[i] += weight*scattering;
203      }
[03cac08]204    }
[2e44ac7]205  }
[ea1f14d]206
[398aa94]207  // Accumulate norm.
[5ff1b03]208  result[nq] += norm;
[2e44ac7]209
[380e8c9]210  // End of the PD loop we can normalize
[5ff1b03]211  if (pd_stop >= problem->total_pd) {
[398aa94]212    const double scale = values[0];
213    const double background = values[1];
[2e44ac7]214    #ifdef USE_OPENMP
215    #pragma omp parallel for
216    #endif
[3044216]217    for (int i=0; i < nq; i++) {
[398aa94]218      result[i] = (norm>0. ? scale*scattering/norm + background : background);
[2e44ac7]219    }
220  }
[60eab2a]221#endif // MAX_PD > 0
[2e44ac7]222}
Note: See TracBrowser for help on using the repository browser.