1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595
|
/*
* Project: The SPD Image correction and azimuthal regrouping
* http://forge.epn-campus.eu/projects/show/azimuthal
*
* Copyright (C) 2005-2010 European Synchrotron Radiation Facility
* Grenoble, France
*
* Principal authors: P. Boesecke (boesecke@esrf.fr)
* R. Wilcke (wilcke@esrf.fr)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* and the GNU Lesser General Public License along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
# define R2T_VERSION "r2t : V1.0 Peter Boesecke 2010-05-25"
/*---------------------------------------------------------------------------
NAME
r2t - conversion between beam distance/center and sample distance/center
SYNOPSIS
DESCRIPTION
This modul provides routines to translate between saxs parameters and
fit2d parameters:
pixel size, center (PoNI), sample distance, detector rotation angles
pixel size, beam center, beam distance, detector tilt angles
The rotations matrices and angles are calculated with the modules
rot3d and tilt3d.
Both parameter sets have been chosen for different purposes. The saxs
rotation angles have been chosen to describe scattering patterns that
are obvserved with an arbitrarily rotated flat 2 dimensional ideal
detector. The fit2d parameters have been chosen to describe scattering
patterns that are observed with a flat 2 dimensional ideal detector
that is slightly misoriented with respect to the primary beam.
The saxs description assumes that the rotation angles of the detector are
exact, e.g. have been calibrated. The scattering pattern in the laboratory
space is interpreted according to them.
After adding a third tilt angle to the fit2d parameters both descriptions
allow to calculate the exact positions of all detector pixels in
the laboratory space. The transformations between both parameter
sets are bijective for tilts less pi/2. In the fit2d description
the beam center diverges to infinity for tilt2=pi/2 (detector plane
parallel to 90 deg).
Both programs use the same laboratory and detector coordinates:
The coordinate system is right-handed with axis 1 horizontal, axis 2
vertical and axis 3 pointing against the primary beam. Rotations and
tilts are ccw. The pixel sizes (pix and bpix) are identical.
The coordinate system with orientation 1 is defined in the following way:
The unit vectors along the three axes are: e1^, e2^, e3^.
The detector in rest position (tilts and rotations are 0) is in the
plane e1^, e2^.
origin (0,0) at lower left corner of the detector
axis 1: horizontally to the right
axis 2: vertically up
axis 3: against primary beam
^ 2 (vertical)
|
|
|
|
+------> 1 (horizontal)
\
\
\
_| 3 (against primary beam)
The fit2d tilts calibrate the detector pattern for the rotation angles
zero, while the saxs rotation angles orient the detector in space, e.g.
with a goniometer. The fit2d description is therefore not very well
suited for large tilts, e.g. when the detector is turned pi/2 around
the goniometer center, where the primary beam does not intersect with
the detector plane.
Due to that different parameters have been chosen:
-fit2d:
The intersection point of the beam with the detector is the beam
center. The tilts are done around this point. The tilt correction
calculates an image like it would be seen by a detector that is
exactly perpendicular to the primary beam. Then, the detector
normal at the beam center points to the sample, or more generally
spoken, to the goniometer center. It corresponds to the point of
normal incidence of the ideal perpendicularly oriented detector.
The fit2d parameters are: the intersection point of the primary
beam with the detector (here called "beam center"), the distance
between the goniometer center and this point (here called "beam
distance"), the tilt of the detector plane against the sample
("tilt2") and the azimuthal angle ("tilt1") of the tilt2-axis on the
detector plane. Both axes (tilt1 and tilt2) can be determined with
image analysis by interpreting the shape of powder rings on the
detector. The third angle ("tilt3") that rotates the detector in the
laboratory around the primary beam is missing in the fit2d description.
It is added here to define bijective transformations between saxs and
fit2d parameters.
fit2d: bpix, beam center, beam distance, tilt1, tilt2, tilt3
fit2d (rotations around detector axes, origin in detector plane):
rotation angle of tilting plane on detector (ccw around axis3):
| cos(tilt1) -sin(tilt1) 0.0 |
T1(tilt1) = | sin(tilt1) cos(tilt1) 0.0 |
| 0.0 0.0 1.0 |
inclination detector plane (ccw around axis1' after Tilt1):
| 1.0 0.0 0.0 |
T2(tilt2) = | 0.0 cos(tilt2) -sin(tilt2) |
| 0.0 sin(tilt2) cos(tilt2) |
rotation angle of detector (ccw around axis 3):
| cos(tilt3) -sin(tilt3) 0.0 |
T3(tilt3) = | sin(tilt3) cos(tilt3) 0.0 |
| 0.0 0.0 1.0 |
principal (output) ranges:
tilt1 ] - Pi .. +Pi]
tilt2 [ 0 .. +Pi]
tilt3 ] - Pi .. +Pi]
all tilts:
Tilt(tilt1,tilt2,tilt3) = T3(tilt3).T1(tilt1).T2(tilt2).T1(-tilt1)
-saxs:
The point on the detector plane where the normal intersects the
goniometer center (sample) is called point of normal incidence ("PoNI",
historically called "center"). The distance between this point and the
sample is the "sample distance". The detector rotations are done
sequentially in the laboratory space around the goniometer center, first
rotation around laboratory axis 1 ("detector rotation 1"), second
rotation around laboratory axis 2 ("detector rotation 2") and third
rotation around laboratory axis 3 ("detector rotation 3").
saxs: pix, PoNI ("center"), sample distance, rot1, rot2, rot3
saxs (rotations around lab axes, origin in sample (goniometer center)):
around lab axis 1:
| 1.0 0.0 0.0 |
R1(rot1) = | 0.0 cos(rot1) -sin(rot1) |
| 0.0 sin(rot1) cos(rot1) |
around lab axis 2:
| cos(rot2) 0.0 sin(rot2) |
R2(rot2) = | 0.0 1.0 0.0 |
| -sin(rot2) 0.0 cos(rot2) |
around lab axis 3:
| cos(rot3) -sin(rot3) 0.0 |
R3(rot3) = | sin(rot3) cos(rot3) 0.0 |
| 0.0 0.0 1.0 |
all rotations:
ROT(rot1,rot2,rot3) = R3(rot3).R2(rot2).R1(rot1)
r11 = R[0][0] = cos(rot2) cos(rot3)
r12 = R[1][0] = sin(rot1) sin(rot2) cos(rot3) - cos(rot1) sin(rot3)
r13 = R[2][0] = cos(rot1) sin(rot2) cos(rot3) + sin(rot1) sin(rot3)
r21 = R[0][1] = cos(rot2) sin(rot3)
r22 = R[1][1] = cos(rot1) cos(rot3) + sin(rot1) sin(rot2) sin(rot3)
r23 = R[2][1] = cos(rot1) sin(rot2) sin(rot3) - sin(rot1) cos(rot3)
r31 = R[0][2] = -sin(rot2)
r32 = R[1][2] = sin(rot1) cos(rot2)
r33 = R[2][2] = cos(rot1) cos(rot2)
principal (output) ranges:
rot1 ] -Pi .. +Pi ]
rot2 [ -Pi/2 .. +Pi/2 ]
rot3 ] -Pi .. +Pi ]
Bcen1[pix1_, cen1_, dis_, R_] :=
(cen1 pix1 ( R[1][0] R[0][1] - R[0][0] R[1][1]) +
dis (-R[2][0] R[1][1] + R[1][0] R[2][1]))/
(pix1 (R[1][0] R[0][1] - R[0][0] R[1][1]))
Bcen2[pix2_, cen2_, dis_, R_] :=
(cen2 pix2 (R[1][0] R[0][1] - R[0][0] R[1][1]) +
dis (R[2][0] R[0][1] - R[0][0] R[2][1]))/
(pix2 (R[1][0] R[0][1] - R[0][0] R[1][1]))
Bdis[dis_, R_] :=
dis ((R[2][1] ( R[1][0] R[0][2] - R[0][0] R[1][2]) +
R[2][0] (-R[1][1] R[0][2] + R[0][1] R[1][2]))/
(-R[1][0] R[0][1] + R[0][0] R[1][1]) +
R[2][2])
Cen1[pix1_, bcen1_, bdis_, R_] :=
bcen1 + (bdis (R[2][0] R[1][1] - R[1][0] R[2][1]))/
(pix1 (R[2][0] ( R[1][1] R[0][2] - R[0][1] R[1][2]) +
R[1][0] (-R[2][1] R[0][2] + R[0][1] R[2][2]) +
R[0][0] ( R[2][1] R[1][2] - R[1][1] R[2][2])))
Cen2[pix2_, bcen2_, bdis_, R_] :=
bcen2 + (bdis (-R[2][0] R[0][1] + R[0][0] R[2][1]))/
(pix2 ( R[2][0] ( R[1][1] R[0][2] - R[0][1] R[1][2]) +
R[1][0] (-R[2][1] R[0][2] + R[0][1] R[2][2]) +
R[0][0] ( R[2][1] R[1][2] - R[1][1] R[2][2])))
Dis[bdis_, R_] :=
(bdis (-R[1][0] R[0][1] + R[0][0] R[1][1]))/
(R[2][0] (-R[1][1] R[0][2] + R[0][1] R[1][2]) +
R[1][0] ( R[2][1] R[0][2] - R[0][1] R[2][2]) +
R[0][0] (-R[2][1] R[1][2] + R[1][1] R[2][2]))
Bcen1[pix1_, cen1_, dis_, R_] :=
(cen1 pix1 ( R12 R21 - R11 R22) +
dis (-R13 R22 + R12 R23))/
(pix1 (R12 R21 - R11 R22))
Bcen2[pix2_, cen2_, dis_, R_] :=
(cen2 pix2 (R12 R21 - R11 R22) +
dis (R13 R21 - R11 R23))/
(pix2 (R12 R21 - R11 R22))
Bdis[dis_, R_] :=
dis ((R23 ( R12 R31 - R11 R32) +
R13 (-R22 R31 + R21 R32))/
(-R12 R21 + R11 R22) +
R33)
Cen1[pix1_, bcen1_, bdis_, R_] :=
bcen1 + (bdis (R13 R22 - R12 R23))/
(pix1 (R13 ( R22 R31 - R21 R32) +
R12 (-R23 R31 + R21 R33) +
R11 ( R23 R32 - R22 R33)))
Cen2[pix2_, bcen2_, bdis_, R_] :=
bcen2 + (bdis (-R13 R21 + R11 R23))/
(pix2 (R13 ( R22 R31 - R21 R32) +
R12 (-R23 R31 + R21 R33) +
R11 ( R23 R32 - R22 R33)))
Dis[bdis_, R_] :=
(bdis (-R12 R21 + R11 R22))/
(R13 (-R22 R31 + R21 R32) +
R12 ( R23 R31 - R21 R33) +
R11 (-R23 R32 + R22 R33))
History
2010-05-17 Peter Boesecke creation
2010-05-25 V1.0 Peter Boesecke
2011-04-18 V1.0 PB r2t_version() added
---------------------------------------------------------------------------*/
/***************************************************************************
* Include *
***************************************************************************/
# include "r2t.h"
/****************************************************************************
* Static Variables and Numbers *
****************************************************************************/
static double r2t_eps=1e-8;
/****************************************************************************
* Routines *
****************************************************************************/
/*--------------------------------------------------------------------------
NAME
r2t_version --- returns pointer to the version string
SYNOPSIS
const char *r2t_version ( void );
DESCRPTION
Returns pointer to the version string.
--------------------------------------------------------------------------*/
const char *r2t_version ( void )
{
return ( R2T_VERSION );
} /* r2t_version */
/*+++------------------------------------------------------------------------
NAME
r2t_bcen1 --- calculate beam center 1
SYNOPSIS
int r2t_bcen1( double *bcen1,
double pix1, double cen1, double dis, double R[3][3] );
DESCRIPTION
bcen1 =
(cen1 pix1 ( R[1][0] R[0][1] - R[0][0] R[1][1]) +
dis (-R[2][0] R[1][1] + R[1][0] R[2][1]))/
(pix1 (R[1][0] R[0][1] - R[0][0] R[1][1]))
RETURN VALUE
status
----------------------------------------------------------------------------*/
int r2t_bcen1( double *bcen1,
double pix1, double cen1, double dis, double R[3][3] )
{ int status=-1;
double denom;
if (!R||!bcen1) {
fprintf( stderr, "ERROR: r2t_bcen1: NULL pointer\n" );
goto r2t_bcen1_error;
}
denom = pix1*(R[1][0]*R[0][1] - R[0][0]*R[1][1]);
if ( fabs(denom)<r2t_eps ) goto r2t_bcen1_error;
*bcen1 = ( cen1*pix1*( R[1][0]*R[0][1] - R[0][0]*R[1][1]) +
dis*(-R[2][0]*R[1][1] + R[1][0]*R[2][1]) ) / denom;
status = 0;
r2t_bcen1_error:
return( status );
} // r2t_bcen1
/*+++------------------------------------------------------------------------
NAME
r2t_bcen2 --- calculate beam center 2
SYNOPSIS
int r2t_bcen2( double *bcen2,
double pix2, double cen2, double dis, double R[3][3] );
DESCRIPTION
bcen2 =
(cen2 pix2 (R[1][0] R[0][1] - R[0][0] R[1][1]) +
dis (R[2][0] R[0][1] - R[0][0] R[2][1]))/
(pix2 (R[1][0] R[0][1] - R[0][0] R[1][1]))
RETURN VALUE
status
----------------------------------------------------------------------------*/
int r2t_bcen2( double *bcen2,
double pix2, double cen2, double dis, double R[3][3] )
{ int status=-1;
double denom;
if (!R||!bcen2) {
fprintf( stderr, "ERROR: r2t_bcen2: NULL pointer\n" );
goto r2t_bcen2_error;
}
denom = pix2*(R[1][0]*R[0][1] - R[0][0]*R[1][1]);
if ( fabs(denom)<r2t_eps ) goto r2t_bcen2_error;
*bcen2 = ( cen2*pix2*(R[1][0]*R[0][1] - R[0][0]*R[1][1]) +
dis*(R[2][0]*R[0][1] - R[0][0]*R[2][1]) ) / denom;
status = 0;
r2t_bcen2_error:
return( status );
} // r2t_bcen2
/*+++------------------------------------------------------------------------
NAME
r2t_bdis --- calculate beam distance
SYNOPSIS
int r2t_bdis ( double *bdis,
double dis, double R[3][3] );
DESCRIPTION
bdis =
dis ((R[2][1] ( R[1][0] R[0][2] - R[0][0] R[1][2]) +
R[2][0] (-R[1][1] R[0][2] + R[0][1] R[1][2]))/
(-R[1][0] R[0][1] + R[0][0] R[1][1]) +
R[2][2])
RETURN VALUE
status
----------------------------------------------------------------------------*/
int r2t_bdis ( double *bdis,
double dis, double R[3][3] )
{ int status=-1;
double denom;
if (!R||!bdis) {
fprintf( stderr, "ERROR: r2t_bdis: NULL pointer\n" );
goto r2t_bdis_error;
}
denom = -R[1][0]*R[0][1] + R[0][0]*R[1][1];
if ( fabs(denom)<r2t_eps ) goto r2t_bdis_error;
*bdis = dis*(R[2][2] + (R[2][1]*( R[1][0]*R[0][2] - R[0][0]*R[1][2]) +
R[2][0]*(-R[1][1]*R[0][2] + R[0][1]*R[1][2]))/denom);
status = 0;
r2t_bdis_error:
return( status );
} // r2t_bdis
/*+++------------------------------------------------------------------------
NAME
r2t_cen1 --- calculate center 1 (PoNI 1)
SYNOPSIS
int r2t_cen1 ( double *cen1,
double pix1, double bcen1, double bdis, double R[3][3] );
DESCRIPTION
cen1 =
bcen1 + (bdis (R[2][0] R[1][1] - R[1][0] R[2][1]))/
(pix1 (R[2][0] ( R[1][1] R[0][2] - R[0][1] R[1][2]) +
R[1][0] (-R[2][1] R[0][2] + R[0][1] R[2][2]) +
R[0][0] ( R[2][1] R[1][2] - R[1][1] R[2][2])))
RETURN VALUE
status
----------------------------------------------------------------------------*/
int r2t_cen1 ( double *cen1,
double pix1, double bcen1, double bdis, double R[3][3] )
{ int status=-1;
double denom;
if (!R||!cen1) {
fprintf( stderr, "ERROR: r2t_cen1: NULL pointer\n" );
goto r2t_cen1_error;
}
denom = pix1*(R[2][0]*( R[1][1]*R[0][2] - R[0][1]*R[1][2]) +
R[1][0]*(-R[2][1]*R[0][2] + R[0][1]*R[2][2]) +
R[0][0]*( R[2][1]*R[1][2] - R[1][1]*R[2][2]));
if ( fabs(denom)<r2t_eps ) goto r2t_cen1_error;
*cen1 = bcen1 + (bdis*(R[2][0]*R[1][1] - R[1][0]*R[2][1]))/denom;
status = 0;
r2t_cen1_error:
return( status );
} // r2t_cen1
/*+++------------------------------------------------------------------------
NAME
r2t_cen2 --- calculate center 2 (PoNI 2)
SYNOPSIS
int r2t_cen2 ( double *cen2,
double pix2, double bcen2, double bdis, double R[3][3] );
DESCRIPTION
cen2 =
bcen2 + (bdis (-R[2][0] R[0][1] + R[0][0] R[2][1]))/
(pix2 ( R[2][0] ( R[1][1] R[0][2] - R[0][1] R[1][2]) +
R[1][0] (-R[2][1] R[0][2] + R[0][1] R[2][2]) +
R[0][0] ( R[2][1] R[1][2] - R[1][1] R[2][2])))
RETURN VALUE
status
----------------------------------------------------------------------------*/
int r2t_cen2 ( double *cen2,
double pix2, double bcen2, double bdis, double R[3][3] )
{ int status=-1;
double denom;
if (!R||!cen2) {
fprintf( stderr, "ERROR: r2t_cen2: NULL pointer\n" );
goto r2t_cen2_error;
}
denom = pix2*(R[2][0]*( R[1][1]*R[0][2] - R[0][1]*R[1][2]) +
R[1][0]*(-R[2][1]*R[0][2] + R[0][1]*R[2][2]) +
R[0][0]*( R[2][1]*R[1][2] - R[1][1]*R[2][2]));
if ( fabs(denom)<r2t_eps ) goto r2t_cen2_error;
*cen2 = bcen2 + (bdis*(-R[2][0]*R[0][1] + R[0][0]*R[2][1]))/denom;
status = 0;
r2t_cen2_error:
return( status );
} // r2t_cen2
/*+++------------------------------------------------------------------------
NAME
r2t_dis --- calculate sample distance
SYNOPSIS
int r2t_dis ( double *dis,
double bdis, double R[3][3] );
DESCRIPTION
dis =
(bdis (-R[1][0] R[0][1] + R[0][0] R[1][1]))/
(R[2][0] (-R[1][1] R[0][2] + R[0][1] R[1][2]) +
R[1][0] ( R[2][1] R[0][2] - R[0][1] R[2][2]) +
R[0][0] (-R[2][1] R[1][2] + R[1][1] R[2][2]))
RETURN VALUE
status
----------------------------------------------------------------------------*/
int r2t_dis ( double *dis,
double bdis, double R[3][3] )
{ int status=-1;
double denom;
if (!R||!dis) {
fprintf( stderr, "ERROR: r2t_dis: NULL pointer\n" );
goto r2t_dis_error;
}
denom = (R[2][0]*(-R[1][1]*R[0][2] + R[0][1]*R[1][2]) +
R[1][0]*( R[2][1]*R[0][2] - R[0][1]*R[2][2]) +
R[0][0]*(-R[2][1]*R[1][2] + R[1][1]*R[2][2]));
if ( fabs(denom)<r2t_eps ) goto r2t_dis_error;
*dis = (bdis*(-R[1][0]*R[0][1] + R[0][0]*R[1][1]))/denom;
status = 0;
r2t_dis_error:
return( status );
} // r2t_dis
|