1 /* This file is part of the hkl library.
3 * The hkl library is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
8 * The hkl library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with the hkl library. If not, see <http://www.gnu.org/licenses/>.
16 * Copyright (C) 2003-2012 Synchrotron SOLEIL
17 * L'Orme des Merisiers Saint-Aubin
18 * BP 48 91192 GIF-sur-YVETTE CEDEX
20 * Authors: Picca Frédéric-Emmanuel <picca@synchrotron-soleil.fr>
21 * Maria-Teresa Nunez-Pardo-de-Verra <tnunez@mail.desy.de>
22 * Jens Krüger <Jens.Krueger@frm2.tum.de>
24 #include <gsl/gsl_math.h>
25 #include <gsl/gsl_vector.h>
26 #include <gsl/gsl_sf.h>
28 #include <ccan/array_size/array_size.h>
30 #include "hkl-parameter-private.h"
31 #include "hkl-pseudoaxis-auto-private.h"
32 #include "hkl-pseudoaxis-common-hkl-private.h"
34 /***********************/
35 /* numerical functions */
36 /***********************/
38 static int _bissector_h_f1(const gsl_vector
*x
, void *params
, gsl_vector
*f
)
40 const double mu
= x
->data
[0];
41 const double komega
= x
->data
[1];
42 const double kappa
= x
->data
[2];
43 const double gamma
= x
->data
[4];
46 CHECK_NAN(x
->data
, x
->size
);
48 omega
= komega
+ atan(tan(kappa
/2.)*cos(50 * HKL_DEGTORAD
)) - M_PI_2
;
50 RUBh_minus_Q(x
->data
, params
, f
->data
);
51 f
->data
[3] = fmod(omega
, M_PI
);
52 f
->data
[4] = fmod(gamma
- 2 * fmod(mu
, M_PI
), 2*M_PI
);
57 static const HklFunction bissector_h_f1
= {
58 .function
= _bissector_h_f1
,
62 static int _bissector_h_f2(const gsl_vector
*x
, void *params
, gsl_vector
*f
)
64 const double mu
= x
->data
[0];
65 const double komega
= x
->data
[1];
66 const double kappa
= x
->data
[2];
67 const double gamma
= x
->data
[4];
70 CHECK_NAN(x
->data
, x
->size
);
72 omega
= komega
+ atan(tan(kappa
/2.)*cos(50 * HKL_DEGTORAD
)) + M_PI_2
;
74 RUBh_minus_Q(x
->data
, params
, f
->data
);
75 f
->data
[3] = fmod(omega
, M_PI
);
76 f
->data
[4] = fmod(gamma
- 2 * fmod(mu
, M_PI
), 2*M_PI
);
82 static const HklFunction bissector_h_f2
= {
83 .function
= _bissector_h_f2
,
87 static int _constant_kphi_h_f1(const gsl_vector
*x
, void *params
, gsl_vector
*f
)
89 const double komega
= x
->data
[1];
90 const double kappa
= x
->data
[2];
93 CHECK_NAN(x
->data
, x
->size
);
95 omega
= komega
+ atan(tan(kappa
/2.)*cos(50 * HKL_DEGTORAD
)) - M_PI_2
;
97 RUBh_minus_Q(x
->data
, params
, f
->data
);
98 f
->data
[3] = fmod(omega
, M_PI
);
103 static const HklFunction constant_kphi_h_f1
= {
104 .function
= _constant_kphi_h_f1
,
108 static int _constant_kphi_h_f2(const gsl_vector
*x
, void *params
, gsl_vector
*f
)
110 const double komega
= x
->data
[1];
111 const double kappa
= x
->data
[2];
114 CHECK_NAN(x
->data
, x
->size
);
116 omega
= komega
+ atan(tan(kappa
/2.)*cos(50 * HKL_DEGTORAD
)) + M_PI_2
;
118 RUBh_minus_Q(x
->data
, params
, f
->data
);
119 f
->data
[3] = fmod(omega
, M_PI
);
124 static const HklFunction constant_kphi_h_f2
= {
125 .function
= _constant_kphi_h_f2
,
129 static int _constant_phi_h_f1(const gsl_vector
*x
, void *params
, gsl_vector
*f
)
131 const double komega
= x
->data
[1];
132 const double kappa
= x
->data
[2];
133 const double kphi
= x
->data
[3];
134 double omega
, phi
, p
;
136 CHECK_NAN(x
->data
, x
->size
);
138 p
= atan(tan(kappa
/2.)*cos(50 * HKL_DEGTORAD
));
139 omega
= komega
+ p
- M_PI_2
;
140 phi
= kphi
+ p
+ M_PI_2
;
142 RUBh_minus_Q(x
->data
, params
, f
->data
);
143 f
->data
[3] = fmod(omega
, M_PI
);
149 static const HklFunction constant_phi_h_f1
= {
150 .function
= _constant_phi_h_f1
,
154 static int _constant_phi_h_f2(const gsl_vector
*x
, void *params
, gsl_vector
*f
)
156 const double komega
= x
->data
[1];
157 const double kappa
= x
->data
[2];
158 const double kphi
= x
->data
[3];
159 double omega
, phi
, p
;
161 CHECK_NAN(x
->data
, x
->size
);
163 p
= atan(tan(kappa
/2.)*cos(50 * HKL_DEGTORAD
));
164 omega
= komega
+ p
+ M_PI_2
;
165 phi
= kphi
+ p
- M_PI_2
;
167 RUBh_minus_Q(x
->data
, params
, f
->data
);
168 f
->data
[3] = fmod(omega
, M_PI
);
174 static const HklFunction constant_phi_h_f2
= {
175 .function
= _constant_phi_h_f2
,
179 static int _bissector_v(const gsl_vector
*x
, void *params
, gsl_vector
*f
)
181 const double komega
= x
->data
[0];
182 const double kappa
= x
->data
[1];
183 const double delta
= x
->data
[3];
186 CHECK_NAN(x
->data
, x
->size
);
188 omega
= komega
+ atan(tan(kappa
/2.)*cos(50 * HKL_DEGTORAD
)) - M_PI_2
;
190 RUBh_minus_Q(x
->data
, params
, f
->data
);
191 f
->data
[3] = fmod(delta
- 2 * fmod(omega
, M_PI
), 2*M_PI
);
196 static const HklFunction bissector_v
= {
197 .function
= _bissector_v
,
201 static int _constant_omega_v(const gsl_vector
*x
, void *params
, gsl_vector
*f
)
203 const double komega
= x
->data
[0];
204 const double kappa
= x
->data
[1];
206 HklEngine
*engine
= params
;
210 hkl_parameter_list_get_values(&engine
->mode
->parameters
, &omega0
, &shit
);
212 CHECK_NAN(x
->data
, x
->size
);
214 omega
= komega
+ atan(tan(kappa
/2.)*cos(50 * HKL_DEGTORAD
)) - M_PI_2
;
216 RUBh_minus_Q(x
->data
, params
, f
->data
);
217 f
->data
[3] = omega0
- omega
;
222 static const HklFunction constant_omega_v
= {
223 .function
= _constant_omega_v
,
227 static int _constant_chi_v(const gsl_vector
*x
, void *params
, gsl_vector
*f
)
229 const double kappa
= x
->data
[1];
231 HklEngine
*engine
= params
;
235 hkl_parameter_list_get_values(&engine
->mode
->parameters
, &chi0
, &shit
);
237 CHECK_NAN(x
->data
, x
->size
);
239 chi
= 2 * asin(sin(kappa
/2.) * sin(50 * HKL_DEGTORAD
));
241 RUBh_minus_Q(x
->data
, params
, f
->data
);
242 f
->data
[3] = chi0
- chi
;
247 static const HklFunction constant_chi_v
= {
248 .function
= _constant_chi_v
,
252 static int _constant_phi_v(const gsl_vector
*x
, void *params
, gsl_vector
*f
)
254 const double kappa
= x
->data
[1];
255 const double kphi
= x
->data
[2];
257 HklEngine
*engine
= params
;
261 hkl_parameter_list_get_values(&engine
->mode
->parameters
, &phi0
, &shit
);
263 CHECK_NAN(x
->data
, x
->size
);
265 phi
= kphi
+ atan(tan(kappa
/2.)*cos(50 * HKL_DEGTORAD
)) + M_PI_2
;
267 RUBh_minus_Q(x
->data
, params
, f
->data
);
268 f
->data
[3] = phi0
- phi
;
273 static const HklFunction constant_phi_v
= {
274 .function
= _constant_phi_v
,
278 static int _double_diffraction_h(const gsl_vector
*x
, void *params
, gsl_vector
*f
)
280 const double komega
= x
->data
[1];
281 const double kappa
= x
->data
[2];
284 CHECK_NAN(x
->data
, x
->size
);
286 omega
= komega
+ atan(tan(kappa
/2.)*cos(50 * HKL_DEGTORAD
)) - M_PI_2
;
288 _double_diffraction(x
->data
, params
, f
->data
);
289 f
->data
[4] = fmod(omega
, M_PI
);
294 static const HklFunction double_diffraction_h
= {
295 .function
= _double_diffraction_h
,
299 static int _constant_incidence_func(const gsl_vector
*x
, void *params
, gsl_vector
*f
)
301 static const HklVector Y
= {
306 HklEngine
*engine
= params
;
307 double parameters
[5];
314 CHECK_NAN(x
->data
, x
->size
);
316 RUBh_minus_Q(x
->data
, params
, f
->data
);
318 /* get the mode parameters */
319 hkl_parameter_list_get_values(&engine
->mode
->parameters
,
321 n
.data
[0] = parameters
[0];
322 n
.data
[1] = parameters
[1];
323 n
.data
[2] = parameters
[2];
324 incidence0
= parameters
[3];
325 azimuth0
= parameters
[4];
327 /* compute the two angles */
330 /* first check that the mode was already initialized if not
331 * the surface is oriented along the nx, ny, nz axis for all
332 * diffractometer angles equal to zero */
333 if(engine
->mode
->geometry_init
){
334 HklQuaternion q0
= engine
->mode
->geometry_init
->holders
[0].q
;
336 hkl_quaternion_conjugate(&q0
);
337 hkl_vector_rotated_quaternion(&n
, &q0
);
340 hkl_vector_rotated_quaternion(&n
, &engine
->geometry
->holders
[0].q
);
342 hkl_source_compute_ki(&engine
->geometry
->source
, &ki
);
343 incidence
= M_PI_2
- hkl_vector_angle(&n
, &ki
);
345 hkl_vector_project_on_plan(&n
, &ki
);
346 azimuth
= hkl_vector_angle(&n
, &Y
);
348 f
->data
[3] = incidence0
- incidence
;
349 f
->data
[4] = azimuth0
- azimuth
;
354 static const HklFunction constant_incidence_func
= {
355 .function
= _constant_incidence_func
,
363 static HklMode
*bissector_vertical(void)
365 static const char* axes
[] = {"komega", "kappa", "kphi", "delta"};
366 static const HklFunction
*functions
[] = {&bissector_v
};
367 static const HklModeAutoInfo info
= {
368 INFO_AUTO(__func__
, axes
, functions
),
371 return hkl_mode_auto_new(&info
,
372 &hkl_mode_operations
);
375 static HklMode
*constant_omega_vertical(void)
377 static const char* axes
[] = {"komega", "kappa", "kphi", "delta"};
378 static const HklFunction
*functions
[] = {&constant_omega_v
};
379 static const HklParameter parameters
[] = {
380 {HKL_PARAMETER_DEFAULTS_ANGLE
, .name
= "omega"},
382 static const HklModeAutoInfo info
= {
383 INFO_AUTO_WITH_PARAMS(__func__
, axes
, functions
, parameters
),
386 return hkl_mode_auto_new(&info
,
387 &hkl_mode_operations
);
390 static HklMode
*constant_chi_vertical(void)
392 static const char* axes
[] = {"komega", "kappa", "kphi", "delta"};
393 static const HklFunction
*functions
[] = {&constant_chi_v
};
394 static const HklParameter parameters
[] = {
395 {HKL_PARAMETER_DEFAULTS_ANGLE
, .name
= "chi"},
397 static const HklModeAutoInfo info
= {
398 INFO_AUTO_WITH_PARAMS(__func__
, axes
, functions
, parameters
),
401 return hkl_mode_auto_new(&info
,
402 &hkl_mode_operations
);
405 static HklMode
*constant_phi_vertical(void)
407 static const char* axes
[] = {"komega", "kappa", "kphi", "delta"};
408 static const HklFunction
*functions
[] = {&constant_phi_v
};
409 static const HklParameter parameters
[] = {
410 {HKL_PARAMETER_DEFAULTS_ANGLE
, .name
= "phi"},
412 static const HklModeAutoInfo info
= {
413 INFO_AUTO_WITH_PARAMS(__func__
, axes
, functions
, parameters
),
416 return hkl_mode_auto_new(&info
,
417 &hkl_mode_operations
);
420 static HklMode
*lifting_detector_kphi(void)
422 static const char* axes
[] = {"kphi", "gamma", "delta"};
423 static const HklFunction
*functions
[] = {&RUBh_minus_Q_func
};
424 static const HklModeAutoInfo info
= {
425 INFO_AUTO(__func__
, axes
, functions
),
428 return hkl_mode_auto_new(&info
,
429 &hkl_mode_operations
);
432 static HklMode
*lifting_detector_komega(void)
434 static const char* axes
[] = {"komega", "gamma", "delta"};
435 static const HklFunction
*functions
[] = {&RUBh_minus_Q_func
};
436 static const HklModeAutoInfo info
= {
437 INFO_AUTO(__func__
, axes
, functions
),
440 return hkl_mode_auto_new(&info
,
441 &hkl_mode_operations
);
444 static HklMode
*lifting_detector_mu(void)
446 static const char* axes
[] = {"mu", "gamma", "delta"};
447 static const HklFunction
*functions
[] = {&RUBh_minus_Q_func
};
448 static const HklModeAutoInfo info
= {
449 INFO_AUTO(__func__
, axes
, functions
),
452 return hkl_mode_auto_new(&info
,
453 &hkl_mode_operations
);
456 static HklMode
*double_diffraction_vertical(void)
458 static const char* axes
[] = {"komega", "kappa", "kphi", "delta"};
459 static const HklFunction
*functions
[] = {&double_diffraction_func
};
460 static const HklParameter parameters
[] = {
461 {HKL_PARAMETER_DEFAULTS
, .name
= "h2", .range
= {.min
=-1, .max
=1}, ._value
= 1,},
462 {HKL_PARAMETER_DEFAULTS
, .name
= "k2", .range
= {.min
=-1, .max
=1}, ._value
= 1,},
463 {HKL_PARAMETER_DEFAULTS
, .name
= "l2", .range
= {.min
=-1, .max
=1}, ._value
= 1,},
465 static const HklModeAutoInfo info
= {
466 INFO_AUTO_WITH_PARAMS(__func__
, axes
, functions
, parameters
),
469 return hkl_mode_auto_new(&info
,
470 &hkl_mode_operations
);
473 static HklMode
*bissector_horizontal(void)
475 static const char* axes
[] = {"mu", "komega", "kappa", "kphi", "gamma"};
476 static const HklFunction
*functions
[] = {&bissector_h_f1
, &bissector_h_f2
};
477 static const HklModeAutoInfo info
= {
478 INFO_AUTO(__func__
, axes
, functions
),
481 return hkl_mode_auto_new(&info
,
482 &hkl_mode_operations
);
485 static HklMode
*constant_phi_horizontal(void)
487 static const char* axes
[] = {"mu", "komega", "kappa", "kphi", "gamma"};
488 static const HklFunction
*functions
[] = {&constant_phi_h_f1
, &constant_phi_h_f2
};
489 static const HklParameter parameters
[] = {
490 {HKL_PARAMETER_DEFAULTS_ANGLE
, .name
= "phi",},
492 static const HklModeAutoInfo info
= {
493 INFO_AUTO_WITH_PARAMS(__func__
, axes
, functions
, parameters
),
496 return hkl_mode_auto_new(&info
,
497 &hkl_mode_operations
);
500 static HklMode
*constant_kphi_horizontal(void)
502 static const char* axes
[] = {"mu", "komega", "kappa", "gamma"};
503 static const HklFunction
*functions
[] = {&constant_kphi_h_f1
, &constant_kphi_h_f2
};
504 static const HklModeAutoInfo info
= {
505 INFO_AUTO(__func__
, axes
, functions
),
508 return hkl_mode_auto_new(&info
,
509 &hkl_mode_operations
);
512 static HklMode
*double_diffraction_horizontal(void)
514 static const char* axes
[] = {"mu", "komega", "kappa", "kphi", "gamma"};
515 static const HklFunction
*functions
[] = {&double_diffraction_h
};
516 static const HklParameter parameters
[] = {
517 {HKL_PARAMETER_DEFAULTS
, .name
= "h2", .range
= {.min
=-1, .max
=1}, ._value
= 1,},
518 {HKL_PARAMETER_DEFAULTS
, .name
= "k2", .range
= {.min
=-1, .max
=1}, ._value
= 1,},
519 {HKL_PARAMETER_DEFAULTS
, .name
= "l2", .range
= {.min
=-1, .max
=1}, ._value
= 1,},
521 static const HklModeAutoInfo info
= {
522 INFO_AUTO_WITH_PARAMS(__func__
, axes
, functions
, parameters
),
525 return hkl_mode_auto_new(&info
,
526 &hkl_mode_operations
);
529 static HklMode
*psi_constant_vertical(void)
531 static const char* axes
[] = {"komega", "kappa", "kphi", "delta"};
532 static const HklFunction
*functions
[] = {&psi_constant_vertical_func
};
533 static const HklParameter parameters
[] = {
534 {HKL_PARAMETER_DEFAULTS
, .name
= "h2", .range
= {.min
=-1, .max
=1}, ._value
= 1,},
535 {HKL_PARAMETER_DEFAULTS
, .name
= "k2", .range
= {.min
=-1, .max
=1}, ._value
= 0,},
536 {HKL_PARAMETER_DEFAULTS
, .name
= "l2", .range
= {.min
=-1, .max
=1}, ._value
= 0,},
537 {HKL_PARAMETER_DEFAULTS_ANGLE
, .name
= "psi"},
539 static const HklModeAutoInfo info
= {
540 INFO_AUTO_WITH_PARAMS(__func__
, axes
, functions
, parameters
),
543 return hkl_mode_auto_new(&info
,
544 &psi_constant_vertical_mode_operations
);
547 static HklMode
*constant_incidence(void)
549 static const char* axes
[] = {"komega", "kappa", "kphi", "gamma", "delta"};
550 static const HklFunction
*functions
[] = {&constant_incidence_func
};
551 static const HklParameter parameters
[] = {
552 {HKL_PARAMETER_DEFAULTS
, .name
= "x", .range
= {.min
=-1, .max
=1}, ._value
= 1,},
553 {HKL_PARAMETER_DEFAULTS
, .name
= "y", .range
= {.min
=-1, .max
=1}, ._value
= 1,},
554 {HKL_PARAMETER_DEFAULTS
, .name
= "z", .range
= {.min
=-1, .max
=1}, ._value
= 1,},
555 {HKL_PARAMETER_DEFAULTS_ANGLE
, .name
= "incidence"},
556 {HKL_PARAMETER_DEFAULTS_ANGLE
, .name
= "aximuth", ._value
= M_PI_2
,},
558 static const HklModeAutoInfo info
= {
559 INFO_AUTO_WITH_PARAMS(__func__
, axes
, functions
, parameters
),
562 return hkl_mode_auto_new(&info
,
563 &hkl_mode_operations
);
566 /**********************/
567 /* pseudo axis engine */
568 /**********************/
570 HklEngine
*hkl_engine_k6c_hkl_new(void)
573 HklMode
*default_mode
;
575 self
= hkl_engine_hkl_new();
577 default_mode
= bissector_vertical();
578 hkl_engine_add_mode(self
, default_mode
);
579 hkl_engine_select_mode(self
, default_mode
);
581 hkl_engine_add_mode(self
, constant_omega_vertical());
582 hkl_engine_add_mode(self
, constant_chi_vertical());
583 hkl_engine_add_mode(self
, constant_phi_vertical());
584 hkl_engine_add_mode(self
, lifting_detector_kphi());
585 hkl_engine_add_mode(self
, lifting_detector_komega());
586 hkl_engine_add_mode(self
, lifting_detector_mu());
587 hkl_engine_add_mode(self
, double_diffraction_vertical());
588 hkl_engine_add_mode(self
, bissector_horizontal());
589 hkl_engine_add_mode(self
, constant_phi_horizontal());
590 hkl_engine_add_mode(self
, constant_kphi_horizontal());
591 hkl_engine_add_mode(self
, double_diffraction_horizontal());
592 hkl_engine_add_mode(self
, psi_constant_vertical());
593 hkl_engine_add_mode(self
, constant_incidence());