source: sasview/DataLoader/extensions/smearer.cpp @ 67c7e89

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 67c7e89 was a74d650a, checked in by Jae Cho <jhjcho@…>, 14 years ago

reduced an issue when both height and width are entered for smearing

  • Property mode set to 100644
File size: 8.2 KB
Line 
1/**
2        This software was developed by the University of Tennessee as part of the
3        Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
4        project funded by the US National Science Foundation.
5
6        If you use DANSE applications to do scientific research that leads to
7        publication, we ask that you acknowledge the use of the software with the
8        following sentence:
9
10        "This work benefited from DANSE software developed under NSF award DMR-0520547."
11
12        copyright 2009, University of Tennessee
13 */
14#include "smearer.hh"
15#include <stdio.h>
16#include <math.h>
17using namespace std;
18
19
20/**
21 * Constructor for BaseSmearer
22 *
23 * @param qmin: minimum Q value
24 * @param qmax: maximum Q value
25 * @param nbins: number of Q bins
26 */
27BaseSmearer :: BaseSmearer(double qmin, double qmax, int nbins) {
28        // Number of bins
29        this->nbins = nbins;
30        this->qmin = qmin;
31        this->qmax = qmax;
32        // Flag to keep track of whether we have a smearing matrix or
33        // whether we need to compute one
34        has_matrix = false;
35        even_binning = true;
36};
37
38/**
39 * Constructor for BaseSmearer
40 *
41 * Used for uneven binning
42 * @param q: array of Q values
43 * @param nbins: number of Q bins
44 */
45BaseSmearer :: BaseSmearer(double* q, int nbins) {
46        // Number of bins
47        this->nbins = nbins;
48        this->q_values = q;
49        // Flag to keep track of whether we have a smearing matrix or
50        // whether we need to compute one
51        has_matrix = false;
52        even_binning = false;
53};
54
55/**
56 * Constructor for SlitSmearer
57 *
58 * @param width: slit width in Q units
59 * @param height: slit height in Q units
60 * @param qmin: minimum Q value
61 * @param qmax: maximum Q value
62 * @param nbins: number of Q bins
63 */
64SlitSmearer :: SlitSmearer(double width, double height, double qmin, double qmax, int nbins) :
65        BaseSmearer(qmin, qmax, nbins){
66        this->height = height;
67        this->width = width;
68};
69
70/**
71 * Constructor for SlitSmearer
72 *
73 * @param width: slit width in Q units
74 * @param height: slit height in Q units
75 * @param q: array of Q values
76 * @param nbins: number of Q bins
77 */
78SlitSmearer :: SlitSmearer(double width, double height, double* q, int nbins) :
79        BaseSmearer(q, nbins){
80        this->height = height;
81        this->width = width;
82};
83
84/**
85 * Constructor for QSmearer
86 *
87 * @param width: array slit widths for each Q point, in Q units
88 * @param qmin: minimum Q value
89 * @param qmax: maximum Q value
90 * @param nbins: number of Q bins
91 */
92QSmearer :: QSmearer(double* width, double qmin, double qmax, int nbins) :
93        BaseSmearer(qmin, qmax, nbins){
94        this->width = width;
95};
96
97/**
98 * Constructor for QSmearer
99 *
100 * @param width: array slit widths for each Q point, in Q units
101 * @param q: array of Q values
102 * @param nbins: number of Q bins
103 */
104QSmearer :: QSmearer(double* width, double* q, int nbins) :
105        BaseSmearer(q, nbins){
106        this->width = width;
107};
108
109/**
110 * Compute the slit smearing matrix
111 *
112 * For even binning (q_min to q_max with nbins):
113 *
114 *   step = (q_max-q_min)/(nbins-1)
115 *   first bin goes from q_min to q_min+step
116 *   last bin goes from q_max to q_max+step
117 *
118 * For binning according to q array:
119 *
120 * Each q point represents a bin going from half the distance between it
121 * and the previous point to half the distance between it and the next point.
122 *
123 *    Example: bin i goes from (q_values[i-1]+q_values[i])/2 to (q_values[i]+q_values[i+1])/2
124 *
125 * The exceptions are the first and last bins, which are centered at the first and
126 * last q-values, respectively. The width of the first and last bins is the distance between
127 * their respective neighboring q-value.
128 */
129void SlitSmearer :: compute_matrix(){
130
131        weights = new vector<double>(nbins*nbins,0);
132
133        // Check the length of the data
134        if (nbins<2) return;
135
136        // Loop over all q-values
137        for(int i=0; i<nbins; i++) {
138                double q, q_min, q_max;
139                get_bin_range(i, &q, &q_min, &q_max);
140
141                // For each q-value, compute the weight of each other q-bin
142                // in the I(q) array
143                int npts_h = height>0 ? npts : 1;
144                int npts_w = width>0 ? npts : 1;
145
146                // If both height and width are great than zero,
147                // modify the number of points in each direction so
148                // that the total number of points is still what
149                // the user would expect (downgrade resolution)
150                // Never down-grade npts_h. That will give incorrect slit smearing...
151                if(npts_h>1 && npts_w>1){
152                        npts_h = npts;//(int)ceil(sqrt((double)npts));
153                        // In general width is much smaller than height, so smaller npt_w
154                        // should work fine.
155                        // Todo: It is still very expansive in time. Think about better way.
156                        npts_w = (int)ceil(npts_h / 100);
157                }
158
159                double shift_h, shift_w;
160                for(int k=0; k<npts_h; k++){
161                        if(npts_h==1){
162                                shift_h = 0;
163                        } else {
164                                shift_h = height/((double)npts_h-1.0) * (double)k;
165                        }
166                        for(int j=0; j<npts_w; j++){
167                                if(npts_w==1){
168                                        shift_w = 0;
169                                } else {
170                                        shift_w = width/((double)npts_w-1.0) * (double)j;
171                                }
172                                double q_shifted = sqrt( ((q-shift_w)*(q-shift_w) + shift_h*shift_h) );
173
174                                // Find in which bin this shifted value belongs
175                                int q_i=nbins;
176                                if (even_binning) {
177                                        // This is kept for backward compatibility since the binning
178                                        // was originally defined differently for even bins.
179                                        q_i = (int)(floor( (q_shifted-qmin) /((qmax-qmin)/((double)nbins -1.0)) ));
180                                } else {
181                                        for(int t=0; t<nbins; t++) {
182                                                double q_t, q_high, q_low;
183                                                get_bin_range(t, &q_t, &q_low, &q_high);
184                                                if(q_shifted>=q_low && q_shifted<q_high) {
185                                                        q_i = t;
186                                                        break;
187                                                }
188                                        }
189                                }
190
191                                // Skip the entries outside our I(q) range
192                                //TODO: be careful with edge effect
193                                if(q_i<nbins)
194                                        (*weights)[i*nbins+q_i]++;
195                        }
196                }
197        }
198};
199
200/**
201 * Compute the point smearing matrix
202 */
203void QSmearer :: compute_matrix(){
204        weights = new vector<double>(nbins*nbins,0);
205
206        // Loop over all q-values
207        double step = (qmax-qmin)/((double)nbins-1.0);
208        double q, q_min, q_max;
209        double q_j, q_jmax, q_jmin;
210        for(int i=0; i<nbins; i++) {
211                get_bin_range(i, &q, &q_min, &q_max);
212
213                for(int j=0; j<nbins; j++) {
214                        get_bin_range(j, &q_j, &q_jmin, &q_jmax);
215
216                        // Compute the fraction of the Gaussian contributing
217                        // to the q_j bin between q_jmin and q_jmax
218                        double value =  erf( (q_jmax-q)/(sqrt(2.0)*width[i]) );
219                value -= erf( (q_jmin-q)/(sqrt(2.0)*width[i]) );
220                (*weights)[i*nbins+j] += value;
221                }
222        }
223}
224
225/**
226 * Computes the Q range of a given bin of the Q distribution.
227 * The range is computed according the the data distribution that
228 * was given to the object at initialization.
229 *
230 * @param i: number of the bin in the distribution
231 * @param q: q-value of bin i
232 * @param q_min: lower bound of the bin
233 * @param q_max: higher bound of the bin
234 *
235 */
236int BaseSmearer :: get_bin_range(int i, double* q, double* q_min, double* q_max) {
237        if (even_binning) {
238                double step = (qmax-qmin)/((double)nbins-1.0);
239                *q = qmin + (double)i*step;
240                *q_min = *q - 0.5*step;
241                *q_max = *q + 0.5*step;
242                return 1;
243        } else if (i>=0 && i<nbins) {
244                *q = q_values[i];
245                if (i==0) {
246                        double step = (q_values[1]-q_values[0])/2.0;
247                        *q_min = *q - step;
248                        *q_max = *q + step;
249                } else if (i==nbins-1) {
250                        double step = (q_values[i]-q_values[i-1])/2.0;
251                        *q_min = *q - step;
252                        *q_max = *q + step;
253                } else {
254                        *q_min = *q - (q_values[i]-q_values[i-1])/2.0;
255                        *q_max = *q + (q_values[i+1]-q_values[i])/2.0;
256                }
257                return 1;
258        }
259        return -1;
260}
261
262/**
263 * Perform smearing by applying the smearing matrix to the input Q array
264 */
265void BaseSmearer :: smear(double *iq_in, double *iq_out, int first_bin, int last_bin){
266
267        // If we haven't computed the smearing matrix, do it now
268        if(!has_matrix) {
269                compute_matrix();
270                has_matrix = true;
271        }
272
273        // Loop over q-values and multiply apply matrix
274        for(int q_i=first_bin; q_i<=last_bin; q_i++){
275                double sum = 0.0;
276                double counts = 0.0;
277
278                for(int i=first_bin; i<=last_bin; i++){
279                        // Skip if weight is less than 1e-04(this value is much smaller than
280                        // the weight at the 3*sigma distance
281                        // Will speed up a little bit...
282                        if ((*weights)[q_i*nbins+i] < 1.0e-004){
283                                continue;
284                        }
285                        sum += iq_in[i] * (*weights)[q_i*nbins+i];
286                        counts += (*weights)[q_i*nbins+i];
287                }
288
289                // Normalize counts
290                iq_out[q_i] = (counts>0.0) ? sum/counts : 0;
291        }
292}
Note: See TracBrowser for help on using the repository browser.