QXRD  0.11.16
qxrddetectorgeometry.cpp
Go to the documentation of this file.
1 #include "qxrddetectorgeometry.h"
2 
3 #include "qmath.h"
4 
6  QcepObject(name, parent)
7 {
8 }
9 
10 /* geometry code taken from "areaDiffractionMachine" */
11 
12 static double mod(double a, double b) {
13  while (a < 0) a+=b;
14  while (a >= b) a-=b;
15  return a;
16 }
17 
18 
19 /*
20  * This is just the same as for convertWavelengthToEnergy but in reverse.
21  */
23 {
24  return 12398.4172/energy;
25 }
26 
27 
28 /*
29  * Wavelength is given in units of angrstrom. Energy is in units of eV.
30  * Wavelengths are converted into energy units.
31  * From Google: (Planck's constant * the speed of light)/(electron volt * angstrom) = 12 398.4172
32  * Thus, (when we realize that wavelength input is in units of angstrom), we see that
33  * E = hc/wavelength = 12,398.4172 eV*angstrom/(wavelength*angstrom) = 12,398.4172/wavelength (in units of eV, as desired)
34  * So our formula for energy is E=12398.4172/wavelength. The units get taken care of properly!
35  */
37 {
38  return 12398.4172/wavelength;
39 }
40 
41 
42 /*
43  * Use the famous Q=4*pi*sin(2theta/2)/lambda formula
44  */
45 double QxrdDetectorGeometry::convertTwoThetaToQ(double twoTheta,double wavelength)
46 {
47  // convert twoTheta from degrees to radians first
48  return 4.0*M_PI*sin( (twoTheta*M_PI/180.0) /2.0)/wavelength;
49 }
50 
51 
52 double QxrdDetectorGeometry::convertQToTwoTheta(double Q, double wavelength)
53 {
54  // convert twoTheta to degrees before returning
55  return 2.0*asin(Q*wavelength/(4*M_PI))*180.0/M_PI;
56 }
57 
58 double QxrdDetectorGeometry::getRadius(double xCenter,double yCenter,
59  double distance,double xPixel,double yPixel,
60  double pixelLength,double pixelHeight,
61  double cos_beta,double sin_beta,
62  double cos_rotation,double sin_rotation)
63 {
64  double pixelLength_mm,pixelHeight_mm;
65  double xMeasured,yMeasured;
66  double bottom;
67  double xPhysical,yPhysical;
68 
69  // pixellength comes in in units of micron
70  // We convert pixelLength & pixelHeight into mm units so
71  // that they are comparable with distance (in units of
72  // millimeters)
73  pixelLength_mm = pixelLength/1000.0;
74  pixelHeight_mm = pixelHeight/1000.0;
75 
76  xMeasured = (xPixel-xCenter)*pixelLength_mm;
77  yMeasured = (yPixel-yCenter)*pixelHeight_mm;
78 
79  bottom = distance+(xMeasured*cos_rotation+
80  yMeasured*sin_rotation)*sin_beta/*+
81  (-xMeasured*sin_rotation+
82  yMeasured*cos_rotation)*sin_alpha*cos_beta*/;
83 
84  // calculate the x y coordinates on the imaginary
85  // detector using fancy math
86  xPhysical = distance*((xMeasured*cos_rotation+
87  yMeasured*sin_rotation)*cos_beta
88  /*-(-xMeasured*sin_rotation+
89  yMeasured*cos_rotation)*sin_alpha*/)/bottom;
90 
91  yPhysical = distance*(-xMeasured*sin_rotation+
92  yMeasured*cos_rotation)/bottom;
93 
94  return sqrt(xPhysical*xPhysical + yPhysical*yPhysical);
95 }
96 
97 double QxrdDetectorGeometry::getTwoTheta(double xCenter,double yCenter,
98  double distance,double xPixel,double yPixel,
99  double pixelLength,double pixelHeight,
100  double cos_beta,double sin_beta,
101  double cos_rotation,double sin_rotation)
102 {
103  double pixelLength_mm,pixelHeight_mm;
104  double xMeasured,yMeasured;
105  double bottom;
106  double xPhysical,yPhysical;
107  double twoTheta;
108 
109  // pixellength comes in in units of micron
110  // We convert pixelLength & pixelHeight into mm units so
111  // that they are comparable with distance (in units of
112  // millimeters)
113  pixelLength_mm = pixelLength/1000.0;
114  pixelHeight_mm = pixelHeight/1000.0;
115 
116  xMeasured = (xPixel-xCenter)*pixelLength_mm;
117  yMeasured = (yPixel-yCenter)*pixelHeight_mm;
118 
119  bottom = distance+(xMeasured*cos_rotation+
120  yMeasured*sin_rotation)*sin_beta/*+
121  (-xMeasured*sin_rotation+
122  yMeasured*cos_rotation)*sin_alpha*cos_beta*/;
123 
124  // calculate the x y coordinates on the imaginary
125  // detector using fancy math
126  xPhysical = distance*((xMeasured*cos_rotation+
127  yMeasured*sin_rotation)*cos_beta
128  /*-(-xMeasured*sin_rotation+
129  yMeasured*cos_rotation)*sin_alpha*/)/bottom;
130 
131  yPhysical = distance*(-xMeasured*sin_rotation+
132  yMeasured*cos_rotation)/bottom;
133 
134  twoTheta = atan2(sqrt(xPhysical*xPhysical+
135  yPhysical*yPhysical),distance);
136  // Convert to radians
137  twoTheta = twoTheta * 180.0/M_PI;
138 
139  return twoTheta;
140 //
141 // // explicitly convert chi to degrees
142 // *chi=atan2(yPhysical,xPhysical)*180.0/M_PI;
143 //
144 // // then add rotation to it so that chi always points
145 // // to the right. Also, we have to multiply chi by -1
146 // // because we have been defining our angles the inverse
147 // // of the way they should be. There is a probably a
148 // // better way to do this if I really thought through
149 // // exactly how chi is defined. For the moment, through,
150 // // this does exactly the right thing.
151 // *chi = (*chi + rotation)*(-1);
152 //
153 // // make sure that chi is b/n 0 and 360
154 // *chi = mod(*chi, 360.0);
155 }
156 
157 /*
158  * This transformation is done using Josh's equations derived
159  * in the software manual. The notation in the manual
160  * corresponds to the variable names by:
161  * xMeasured = x'''
162  * yMeasured = y'''
163  * xPhysical = x_d
164  * yPhysical = y_d
165  */
166 void QxrdDetectorGeometry::getTwoThetaChi(double xCenter,double yCenter,
167  double distance,double xPixel,double yPixel,
168  double pixelLength,double pixelHeight,
169  double rotation,double cos_beta,double sin_beta,
170  double cos_alpha,double sin_alpha,
171  double cos_rotation,double sin_rotation,
172  double *twoTheta,double *chi)
173 {
174  double pixelLength_mm,pixelHeight_mm;
175  double xMeasured,yMeasured;
176  double bottom;
177  double xPhysical,yPhysical;
178 
179  // pixellength comes in in units of micron
180  // We convert pixelLength & pixelHeight into mm units so
181  // that they are comparable with distance (in units of
182  // millimeters)
183  pixelLength_mm = pixelLength/1000.0;
184  pixelHeight_mm = pixelHeight/1000.0;
185 
186  xMeasured = (xPixel-xCenter)*pixelLength_mm;
187  yMeasured = (yPixel-yCenter)*pixelHeight_mm;
188 
189  bottom = distance+(xMeasured*cos_rotation+
190  yMeasured*sin_rotation)*sin_beta+
191  (-xMeasured*sin_rotation+
192  yMeasured*cos_rotation)*sin_alpha*cos_beta;
193 
194  // calculate the x y coordinates on the imaginary
195  // detector using fancy math
196  xPhysical = distance*((xMeasured*cos_rotation+
197  yMeasured*sin_rotation)*cos_beta
198  -(-xMeasured*sin_rotation+
199  yMeasured*cos_rotation)*sin_alpha)/bottom;
200 
201  yPhysical = distance*(-xMeasured*sin_rotation+
202  yMeasured*cos_rotation)*cos_alpha/bottom;
203 
204  *twoTheta = atan2(sqrt(xPhysical*xPhysical+
205  yPhysical*yPhysical),distance);
206  // Convert to radians
207  *twoTheta = *twoTheta * 180.0/M_PI;
208 
209  // explicitly convert chi to degrees
210  *chi=atan2(yPhysical,xPhysical)*180.0/M_PI;
211 
212  // then add rotation to it so that chi always points
213  // to the right. Also, we have to multiply chi by -1
214  // because we have been defining our angles the inverse
215  // of the way they should be. There is a probably a
216  // better way to do this if I really thought through
217  // exactly how chi is defined. For the moment, through,
218  // this does exactly the right thing.
219  *chi = (*chi + rotation*180.0/M_PI)*(-1);
220 
221  // make sure that chi is b/n 0 and 360
222  *chi = mod(*chi, 360.0);
223 }
224 
225 
226 void QxrdDetectorGeometry::getQChi(double xCenter,double yCenter,double distance,
227  double energy,double xPixel,double yPixel,
228  double pixelLength,double pixelHeight,
229  double rotation,double cos_beta,double sin_beta,
230  double cos_alpha,double sin_alpha,
231  double cos_rotation,double sin_rotation,
232  double *q,double *chi)
233 {
234 
235  double wavelength;
236  double twoTheta;
237  wavelength = 12398.4172/energy;
238 
239  getTwoThetaChi(xCenter,yCenter,distance,xPixel,yPixel,
240  pixelLength,pixelHeight,rotation,cos_beta,sin_beta,
241  cos_alpha,sin_alpha,cos_rotation,sin_rotation,
242  &twoTheta,chi);
243 
244  *q=convertTwoThetaToQ(twoTheta,wavelength);
245 }
246 
247 
248 /*
249  * This transformation is done using Josh's equations derived
250  * in the software manual. The notation in the manual
251  * corresponds to the variable names by:
252  * xMeasured = x'''
253  * yMeasured = y'''
254  * xPhysical = x_d
255  * yPhysical = y_d
256  */
257 void QxrdDetectorGeometry::getXY(double xCenter,double yCenter,double distance,
258  double energy,double q,double chi,double pixelLength,
259  double pixelHeight,double rotation,double cos_beta,
260  double sin_beta,double cos_alpha,double sin_alpha,
261  double cos_rotation,double sin_rotation,
262  double * xPixel,double * yPixel)
263 {
264  double wavelength;
265  double twoTheta;
266  double xPhysical,yPhysical;
267  double bottom;
268  double pixelLength_mm,pixelHeight_mm;
269  double xMeasured,yMeasured;
270 
271  double tan_chi;
272 
273  wavelength = 12398.4172/energy;
274 
275  // rotate chi back to point whatever way it is supposed
276  // to point
277  chi = chi*(-1) - rotation;
278 
279  chi = mod(chi, 360.0);
280 
281  // explicitly convert chi to radians
282  chi*=M_PI/180.0;
283 
284  twoTheta = 2.0*asin(wavelength*q/(4.0*M_PI));
285 
286  tan_chi = tan(chi);
287  xPhysical = fabs(distance*tan(twoTheta)/sqrt(1.0+
288  tan_chi*tan_chi));
289 
290  // one must determine explicitly the sign of xPhysical
291  // by inspecting the diagram. This is b/c at one point
292  // we take a sqrt in our derivation.
293  if (chi>M_PI/2.0 && chi<3.0*M_PI/2.0)
294  xPhysical = -1.0*xPhysical;
295 
296  yPhysical=fabs(xPhysical*tan_chi);
297 
298  // set the sign of y explicitly
299  if (chi > M_PI && chi < 2.0*M_PI)
300  yPhysical = -1.0*fabs(yPhysical);
301 
302  // I should worry about cos_alpha being 0
303  bottom = distance*cos_beta-xPhysical*sin_beta-
304  cos_beta*(xPhysical*cos_beta+distance)/(
305  (xPhysical*cos_alpha)/(yPhysical*sin_alpha)+1);
306 
307  xMeasured = (distance*xPhysical*cos_rotation-
308  distance*xPhysical*cos_beta*sin_rotation/
309  (xPhysical*cos_alpha/yPhysical+sin_alpha))/
310  bottom;
311 
312  yMeasured = (distance*xPhysical*sin_rotation+
313  distance*xPhysical*cos_beta*cos_rotation/
314  (xPhysical*cos_alpha/yPhysical+sin_alpha))/
315  bottom;
316 
317  // convert pixelLength & pixelHeight into mm units so
318  // that they are comparable with distance (in units of
319  // millimeters)
320  pixelLength_mm = pixelLength/1000.0;
321  pixelHeight_mm = pixelHeight/1000.0;
322 
323  *xPixel = xMeasured/pixelLength_mm + xCenter;
324  *yPixel = yMeasured/pixelHeight_mm + yCenter;
325 }
QxrdDetectorGeometry(QString name, QcepObject *parent)
static double convertEnergyToWavelength(double energy)
static double convertWavelengthToEnergy(double wavelength)
static void getQChi(double xCenter, double yCenter, double distance, double energy, double xPixel, double yPixel, double pixelLength, double pixelHeight, double rotation, double cos_beta, double sin_beta, double cos_alpha, double sin_alpha, double cos_rotation, double sin_rotation, double *q, double *chi)
static void getTwoThetaChi(double xCenter, double yCenter, double distance, double xPixel, double yPixel, double pixelLength, double pixelHeight, double rotation, double cos_beta, double sin_beta, double cos_alpha, double sin_alpha, double cos_rotation, double sin_rotation, double *twoTheta, double *chi)
static double convertTwoThetaToQ(double twoTheta, double wavelength)
static double getRadius(double xCenter, double yCenter, double distance, double xPixel, double yPixel, double pixelLength, double pixelHeight, double cos_beta, double sin_beta, double cos_rotation, double sin_rotation)
static double mod(double a, double b)
static double getTwoTheta(double xCenter, double yCenter, double distance, double xPixel, double yPixel, double pixelLength, double pixelHeight, double cos_beta, double sin_beta, double cos_rotation, double sin_rotation)
QString name
Definition: qcepobject.h:49
static void getXY(double xCenter, double yCenter, double distance, double energy, double q, double chi, double pixelLength, double pixelHeight, double rotation, double cos_beta, double sin_beta, double cos_alpha, double sin_alpha, double cos_rotation, double sin_rotation, double *xPixel, double *yPixel)
static double convertQToTwoTheta(double Q, double wavelength)