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> |
---|
17 | using 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 | */ |
---|
27 | BaseSmearer :: 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 | }; |
---|
36 | |
---|
37 | /** |
---|
38 | * Constructor for SlitSmearer |
---|
39 | * |
---|
40 | * @param width: slit width in Q units |
---|
41 | * @param height: slit height in Q units |
---|
42 | * @param qmin: minimum Q value |
---|
43 | * @param qmax: maximum Q value |
---|
44 | * @param nbins: number of Q bins |
---|
45 | */ |
---|
46 | SlitSmearer :: SlitSmearer(double width, double height, double qmin, double qmax, int nbins) : |
---|
47 | BaseSmearer(qmin, qmax, nbins){ |
---|
48 | this->height = height; |
---|
49 | this->width = width; |
---|
50 | }; |
---|
51 | |
---|
52 | /** |
---|
53 | * Constructor for SlitSmearer |
---|
54 | * |
---|
55 | * @param width: array slit widths for each Q point, in Q units |
---|
56 | * @param qmin: minimum Q value |
---|
57 | * @param qmax: maximum Q value |
---|
58 | * @param nbins: number of Q bins |
---|
59 | */ |
---|
60 | QSmearer :: QSmearer(double* width, double qmin, double qmax, int nbins) : |
---|
61 | BaseSmearer(qmin, qmax, nbins){ |
---|
62 | this->width = width; |
---|
63 | }; |
---|
64 | |
---|
65 | /** |
---|
66 | * Compute the slit smearing matrix |
---|
67 | */ |
---|
68 | void SlitSmearer :: compute_matrix(){ |
---|
69 | |
---|
70 | weights = new vector<double>(nbins*nbins,0); |
---|
71 | |
---|
72 | // Loop over all q-values |
---|
73 | for(int i=0; i<nbins; i++) { |
---|
74 | double q = qmin + (double)i*(qmax-qmin)/((double)nbins-1.0); |
---|
75 | |
---|
76 | // For each q-value, compute the weight of each other q-bin |
---|
77 | // in the I(q) array |
---|
78 | int npts_h = height>0 ? npts : 1; |
---|
79 | int npts_w = width>0 ? npts : 1; |
---|
80 | |
---|
81 | // If both height and width are great than zero, |
---|
82 | // modify the number of points in each direction so |
---|
83 | // that the total number of points is still what |
---|
84 | // the user would expect (downgrade resolution) |
---|
85 | if(npts_h>1 && npts_w>1){ |
---|
86 | npts_h = (int)ceil(sqrt((double)npts)); |
---|
87 | npts_w = npts_h; |
---|
88 | } |
---|
89 | |
---|
90 | double shift_h, shift_w; |
---|
91 | for(int k=0; k<npts_h; k++){ |
---|
92 | if(npts_h==1){ |
---|
93 | shift_h = 0; |
---|
94 | } else { |
---|
95 | shift_h = height/((double)npts_h-1.0) * (double)k; |
---|
96 | } |
---|
97 | for(int j=0; j<npts_w; j++){ |
---|
98 | if(npts_w==1){ |
---|
99 | shift_w = 0; |
---|
100 | } else { |
---|
101 | shift_w = width/((double)npts_w-1.0) * (double)j; |
---|
102 | } |
---|
103 | double q_shifted = sqrt( ((q-shift_w)*(q-shift_w) + shift_h*shift_h) ); |
---|
104 | int q_i = (int)(floor( (q_shifted-qmin) /((qmax-qmin)/((double)nbins -1.0)) )); |
---|
105 | |
---|
106 | // Skip the entries outside our I(q) range |
---|
107 | //TODO: be careful with edge effect |
---|
108 | if(q_i<nbins) |
---|
109 | (*weights)[i*nbins+q_i]++; |
---|
110 | } |
---|
111 | } |
---|
112 | } |
---|
113 | }; |
---|
114 | |
---|
115 | /** |
---|
116 | * Compute the point smearing matrix |
---|
117 | */ |
---|
118 | void QSmearer :: compute_matrix(){ |
---|
119 | weights = new vector<double>(nbins*nbins,0); |
---|
120 | |
---|
121 | // Loop over all q-values |
---|
122 | double step = (qmax-qmin)/((double)nbins-1.0); |
---|
123 | for(int i=0; i<nbins; i++) { |
---|
124 | double q = qmin + (double)i*step; |
---|
125 | double q_min = q - 0.5*step; |
---|
126 | double q_max = q + 0.5*step; |
---|
127 | |
---|
128 | for(int j=0; j<nbins; j++) { |
---|
129 | double q_j = qmin + (double)j*step; |
---|
130 | |
---|
131 | // Compute the fraction of the Gaussian contributing |
---|
132 | // to the q bin between q_min and q_max |
---|
133 | double value = erf( (q_max-q_j)/(sqrt(2.0)*width[j]) ); |
---|
134 | value -= erf( (q_min-q_j)/(sqrt(2.0)*width[j]) ); |
---|
135 | (*weights)[i*nbins+j] += value; |
---|
136 | } |
---|
137 | } |
---|
138 | } |
---|
139 | |
---|
140 | /** |
---|
141 | * Perform smearing by applying the smearing matrix to the input Q array |
---|
142 | */ |
---|
143 | void BaseSmearer :: smear(double *iq_in, double *iq_out, int first_bin, int last_bin){ |
---|
144 | |
---|
145 | // If we haven't computed the smearing matrix, do it now |
---|
146 | if(!has_matrix) { |
---|
147 | compute_matrix(); |
---|
148 | has_matrix = true; |
---|
149 | } |
---|
150 | |
---|
151 | // Loop over q-values and multiply apply matrix |
---|
152 | for(int q_i=first_bin; q_i<=last_bin; q_i++){ |
---|
153 | double sum = 0.0; |
---|
154 | double counts = 0.0; |
---|
155 | |
---|
156 | for(int i=first_bin; i<=last_bin; i++){ |
---|
157 | sum += iq_in[i] * (*weights)[q_i*nbins+i]; |
---|
158 | counts += (*weights)[q_i*nbins+i]; |
---|
159 | } |
---|
160 | |
---|
161 | // Normalize counts |
---|
162 | iq_out[q_i] = (counts>0.0) ? sum/counts : 0; |
---|
163 | } |
---|
164 | } |
---|