Changeset 5ff1b03 in sasmodels for sasmodels/kernel_iq.c
- Timestamp:
- Mar 25, 2016 9:44:37 AM (8 years ago)
- Branches:
- master, core_shell_microgels, costrafo411, magnetic_model, release_v0.94, release_v0.95, ticket-1257-vesicle-product, ticket_1156, ticket_1265_superball, ticket_822_more_unit_tests
- Children:
- c499331
- Parents:
- ba32cdd
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
sasmodels/kernel_iq.c
rba32cdd r5ff1b03 21 21 int32_t pd_offset[MAX_PD]; // offset of pd weights in the value & weight vector 22 22 int32_t pd_stride[MAX_PD]; // stride to move to the next index at this level 23 int32_t pd_isvol[MAX_PD]; // True if parameter is a volume weighting parameter24 23 #endif // MAX_PD > 0 25 int32_t par_offset[NPARS]; // offset of par values in the value & weight vector 26 int32_t par_coord[NPARS]; // polydispersity coordination bitvector 27 int32_t fast_coord_pars[NPARS]; // ids of the fast coordination parameters 28 int32_t fast_coord_count; // number of parameters coordinated with pd 1 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 29 30 int32_t theta_par; // id of spherical correction variable 30 31 } ProblemDetails; … … 54 55 double *pvec = (double *)(&local_values); // Alias named parameters with a vector 55 56 56 // Monodisperse computation 57 if (pd_stop == 1) { 58 // Shouldn't need to copy!! 59 for (int k=0; k < NPARS; k++) { 60 pvec[k] = values[k+2]; // skip scale and background 61 } 62 63 const double volume = CALL_VOLUME(local_values); 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 } 64 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) { 64 71 #ifdef USE_OPENMP 65 72 #pragma omp parallel for 66 73 #endif 74 for (int i=0; i < nq+1; i++) { 75 result[i] = 0.0; 76 } 77 } 78 79 // Monodisperse computation 80 if (problem->num_active == 0) { 81 #ifdef INVALID 82 if (INVALID(local_values)) { return; } 83 #endif 84 85 const double norm = CALL_VOLUME(local_values); 86 #ifdef USE_OPENMP 87 #pragma omp parallel for 88 #endif 89 result[nq] = norm; // Total volume normalization 67 90 for (int i=0; i < nq; i++) { 68 91 double scattering = CALL_IQ(q, i, local_values); 69 if (volume != 0.0) scattering /= volume; 70 result[i] = values[0]*scattering + values[1]; 92 result[i] = values[0]*scattering/norm + values[1]; 71 93 } 72 94 return; … … 74 96 75 97 #if MAX_PD > 0 76 //printf("Entering polydispersity\n"); 77 98 //printf("Entering polydispersity from %d to %d\n", pd_start, pd_stop); 78 99 // 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. 81 double norm; // contains sum over weights 82 double vol; // contains sum over volume 83 double norm_vol; // contains weights over volume 84 85 // Initialize the results to zero 86 if (pd_start == 0) { 87 norm_vol = 0.0; 88 norm = 0.0; 89 vol = 0.0; 90 91 #ifdef USE_OPENMP 92 #pragma omp parallel for 93 #endif 94 for (int i=0; i < nq; i++) { 95 result[i] = 0.0; 96 } 97 } else { 98 //Pulling values from previous segment 99 norm = result[nq]; 100 vol = result[nq+1]; 101 norm_vol = result[nq+2]; 102 } 103 104 // Location in the polydispersity hypercube, one index per dimension. 105 local int pd_index[MAX_PD]; 106 107 // polydispersity loop index positions 108 local int offset[NPARS]; // NPARS excludes scale/background 109 110 // Trigger the reset behaviour that happens at the end the fast loop 111 // by setting the initial index >= weight vector length. 112 pd_index[0] = problem->pd_length[0]; 113 100 // for each q, we need to track the normalization values between calls. 101 double norm = 0.0; 114 102 115 103 // need product of weights at every Iq calc, so keep product of 116 104 // weights from the outer loops so that weight = partial_weight * fast_weight 117 105 double partial_weight = NAN; // product of weight w4*w3*w2 but not w1 118 double partial_volweight = NAN; 119 double weight = 1.0; // set to 1 in case there are no weights 120 double vol_weight = 1.0; // set to 1 in case there are no vol weights 121 double spherical_correction = 1.0; // correction for latitude variation 106 double spherical_correction = 1.0; // cosine correction for latitude variation 107 108 // Location in the polydispersity hypercube, one index per dimension. 109 local int pd_index[MAX_PD]; 110 111 // Location of the coordinated parameters in their own sub-cubes. 112 local int offset[NPARS]; 113 114 // Trigger the reset behaviour that happens at the end the fast loop 115 // by setting the initial index >= weight vector length. 116 const int fast_length = problem->pd_length[0]; 117 pd_index[0] = fast_length; 122 118 123 119 // Loop over the weights then loop over q, accumulating values 124 120 for (int loop_index=pd_start; loop_index < pd_stop; loop_index++) { 125 121 // check if indices need to be updated 126 if (pd_index[0] >= problem->pd_length[0]) { 127 128 // RESET INDICES 129 pd_index[0] = loop_index%problem->pd_length[0]; 122 if (pd_index[0] == fast_length) { 123 //printf("should be here with %d active\n", problem->num_active); 124 125 // Compute position in polydispersity hypercube 126 for (int k=0; k < problem->num_active; k++) { 127 pd_index[k] = (loop_index/problem->pd_stride[k])%problem->pd_length[k]; 128 //printf("pd_index[%d] = %d\n",k,pd_index[k]); 129 } 130 131 // Compute partial weights 130 132 partial_weight = 1.0; 131 partial_volweight = 1.0;132 for (int k=1; k < MAX_PD; k++) {133 pd_index[k] = (loop_index%problem->pd_length[k])/problem->pd_stride[k];134 const double wi = weights[problem->pd_offset[k]+pd_index[k]];133 //printf("partial weight %d: ", loop_index); 134 for (int k=1; k < problem->num_active; k++) { 135 double wi = weights[problem->pd_offset[k] + pd_index[k]]; 136 //printf("pd[%d]=par[%d]=%g ", k, problem->pd_par[k], wi); 135 137 partial_weight *= wi; 136 if (problem->pd_isvol[k]) partial_volweight *= wi; 137 } 138 } 139 //printf("\n"); 140 141 // Update parameter offsets in weight vector 138 142 //printf("slow %d: ", loop_index); 139 for (int k=0; k < NPARS; k++) { 140 int coord = problem->par_coord[k]; 141 int this_offset = problem->par_offset[k]; 143 for (int k=0; k < problem->num_coord; k++) { 144 int par = problem->par_coord[k]; 145 int coord = problem->pd_coord[k]; 146 int this_offset = problem->par_offset[par]; 142 147 int block_size = 1; 143 for (int bit=0; bit < MAX_PD &&coord != 0; bit++) {148 for (int bit=0; coord != 0; bit++) { 144 149 if (coord&1) { 145 150 this_offset += block_size * pd_index[bit]; 146 151 block_size *= problem->pd_length[bit]; 147 152 } 148 coord /= 2;153 coord >>= 1; 149 154 } 150 offset[k] = this_offset; 151 pvec[k] = values[this_offset]; 152 //printf("p[%d]=v[%d]=%g ", k, offset[k], pvec[k]); 155 offset[par] = this_offset; 156 pvec[par] = values[this_offset]; 157 //printf("par[%d]=v[%d]=%g \n", k, offset[k], pvec[k]); 158 // if theta is not coordinated with fast index, precompute spherical correction 159 if (par == problem->theta_par && !(problem->par_coord[k]&1)) { 160 spherical_correction = fmax(fabs(cos(M_PI_180*pvec[problem->theta_par])), 1e-6); 161 } 153 162 } 154 163 //printf("\n"); 155 weight = partial_weight * weights[problem->pd_offset[0]+pd_index[0]]; 156 if (problem->theta_par >= 0) { 157 spherical_correction = fabs(cos(M_PI_180*pvec[problem->theta_par])); 158 } 159 if (problem->theta_par == problem->pd_par[0]) { 160 weight *= spherical_correction; 161 } 162 pd_index[0] += 1; 163 164 } else { 165 166 // INCREMENT INDICES 167 const double wi = weights[problem->pd_offset[0]+pd_index[0]]; 168 weight = partial_weight*wi; 169 if (problem->pd_isvol[0]) vol_weight *= wi; 170 //printf("fast %d: ", loop_index); 171 for (int k=0; k < problem->fast_coord_count; k++) { 172 const int pindex = problem->fast_coord_pars[k]; 173 pvec[pindex] = values[++offset[pindex]]; 174 //printf("p[%d]=v[%d]=%g ", pindex, offset[pindex], pvec[pindex]); 175 } 176 //printf("\n"); 177 if (problem->theta_par == problem->pd_par[0]) { 178 weight *= fabs(cos(M_PI_180*pvec[problem->theta_par])); 179 } 180 pd_index[0] += 1; 181 } 164 } 165 166 // Increment fast index 167 const double wi = weights[problem->pd_offset[0] + pd_index[0]++]; 168 double weight = partial_weight*wi; 169 //printf("fast %d: ", loop_index); 170 for (int k=0; k < problem->num_coord; k++) { 171 if (problem->pd_coord[k]&1) { 172 const int par = problem->par_coord[k]; 173 pvec[par] = values[offset[par]++]; 174 //printf("p[%d]=v[%d]=%g ", par, offset[par]-1, pvec[par]); 175 // if theta is coordinated with fast index, compute spherical correction each time 176 if (par == problem->theta_par) { 177 spherical_correction = fmax(fabs(cos(M_PI_180*pvec[problem->theta_par])), 1e-6); 178 } 179 } 180 } 181 //printf("\n"); 182 182 183 #ifdef INVALID 183 184 if (INVALID(local_values)) continue; … … 187 188 // Note: weight==0 must always be excluded 188 189 if (weight > cutoff) { 189 norm += weight; 190 vol += vol_weight * CALL_VOLUME(local_values); 191 norm_vol += vol_weight; 190 // spherical correction has some nasty effects when theta is +90 or -90 191 // where it becomes zero. If the entirety of the correction 192 weight *= spherical_correction; 193 norm += weight * CALL_VOLUME(local_values); 192 194 193 195 #ifdef USE_OPENMP … … 202 204 203 205 // Make normalization available for the next round 204 result[nq] = norm; 205 result[nq+1] = vol; 206 result[nq+2] = norm_vol; 206 result[nq] += norm; 207 207 208 208 // End of the PD loop we can normalize 209 if (pd_stop >= problem-> pd_stride[MAX_PD-1]) {209 if (pd_stop >= problem->total_pd) { 210 210 #ifdef USE_OPENMP 211 211 #pragma omp parallel for 212 212 #endif 213 213 for (int i=0; i < nq; i++) { 214 if (vol*norm_vol != 0.0) {215 result[i] *= norm_vol/vol;216 }217 214 result[i] = values[0]*result[i]/norm + values[1]; 218 215 }
Note: See TracChangeset
for help on using the changeset viewer.