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-2014 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>
22 #include <math.h> // for cos, sin, M_PI, atan2, sqrt
23 #include <stdio.h> // for fprintf, FILE
24 #include <stdlib.h> // for NULL, free
25 #include "hkl-lattice-private.h" // for _HklLattice
26 #include "hkl-macros-private.h" // for HKL_MALLOC
27 #include "hkl-matrix-private.h" // for _HklMatrix
28 #include "hkl-parameter-private.h" // for hkl_parameter_init_copy, etc
29 #include "hkl-unit-private.h" // for hkl_unit_length_nm, etc
30 #include "hkl-vector-private.h" // for hkl_vector_angle, etc
31 #include "hkl.h" // for HklLattice, etc
35 static double convert_to_default(const HklParameter
*p
, double value
, HklUnitEnum unit_type
)
38 case HKL_UNIT_DEFAULT
:
41 return value
/ hkl_unit_factor(p
->unit
, p
->punit
);
45 static int check_lattice_param(double a
, double b
, double c
,
46 double alpha
, double beta
, double gamma
,
49 hkl_error (error
== NULL
|| *error
== NULL
);
51 double D
= 1. - cos(alpha
)*cos(alpha
) - cos(beta
)*cos(beta
)
52 - cos(gamma
)*cos(gamma
) + 2. * cos(alpha
)*cos(beta
)*cos(gamma
);
57 HKL_LATTICE_CHECK_LATTICE
,
58 "these lattice parameters are not valid, check alpha, beta and gamma");
68 * @a: the length of the a parameter
69 * @b: the length of the b parameter
70 * @c: the length of the c parameter
71 * @alpha: the angle between b and c (radian)
72 * @beta: the angle between a and c (radian)
73 * @gamma: the angle between a and b (radian)
74 * @error: return location for a GError, or NULL
78 * Returns: a new HklLattice
80 HklLattice
*hkl_lattice_new(double a
, double b
, double c
,
81 double alpha
, double beta
, double gamma
,
84 HklLattice
*self
= NULL
;
86 hkl_error (error
== NULL
|| *error
== NULL
);
88 if(!check_lattice_param(a
, b
, c
, alpha
, beta
, gamma
, error
))
90 g_assert (error
== NULL
|| *error
!= NULL
);
93 g_assert (error
== NULL
|| *error
== NULL
);
95 self
= HKL_MALLOC(HklLattice
);
97 self
->a
= hkl_parameter_new("a", "The length of the first lattice vector",
101 &hkl_unit_length_nm
);
102 self
->b
= hkl_parameter_new("b", "The length of the second lattice vector",
106 &hkl_unit_length_nm
);
107 self
->c
= hkl_parameter_new("c", "The length of the third lattice vector",
111 &hkl_unit_length_nm
);
112 self
->alpha
= hkl_parameter_new("alpha",
113 "The angle between the second and third lattice vector",
117 &hkl_unit_angle_deg
);
118 self
->beta
= hkl_parameter_new("beta",
119 "The angle between the first and third lattice vector",
123 &hkl_unit_angle_deg
);
124 self
->gamma
= hkl_parameter_new("gamma",
125 "The angle between the first and second lattice vector",
129 &hkl_unit_angle_deg
);
134 * hkl_lattice_new_copy: (skip)
141 HklLattice
*hkl_lattice_new_copy(const HklLattice
*self
)
143 HklLattice
*copy
= NULL
;
145 copy
= HKL_MALLOC(HklLattice
);
147 copy
->a
= hkl_parameter_new_copy(self
->a
);
148 copy
->b
= hkl_parameter_new_copy(self
->b
);
149 copy
->c
= hkl_parameter_new_copy(self
->c
);
150 copy
->alpha
= hkl_parameter_new_copy(self
->alpha
);
151 copy
->beta
= hkl_parameter_new_copy(self
->beta
);
152 copy
->gamma
= hkl_parameter_new_copy(self
->gamma
);
158 * hkl_lattice_new_default: (skip)
160 * default constructor
164 HklLattice
* hkl_lattice_new_default(void)
166 return hkl_lattice_new(1.54, 1.54, 1.54,
167 90*HKL_DEGTORAD
, 90*HKL_DEGTORAD
, 90*HKL_DEGTORAD
,
172 * hkl_lattice_free: (skip)
177 void hkl_lattice_free(HklLattice
*self
)
179 hkl_parameter_free(self
->a
);
180 hkl_parameter_free(self
->b
);
181 hkl_parameter_free(self
->c
);
182 hkl_parameter_free(self
->alpha
);
183 hkl_parameter_free(self
->beta
);
184 hkl_parameter_free(self
->gamma
);
189 * hkl_lattice_a_get: (skip)
190 * @self: the this ptr
192 const HklParameter
*hkl_lattice_a_get(const HklLattice
*self
)
198 * hkl_lattice_a_set: (skip)
199 * @self: the this ptr
200 * @parameter: the parameter to set
201 * @error: return location for a GError, or NULL
203 * Returns: TRUE on success, FALSE if an error occurred
205 int hkl_lattice_a_set(HklLattice
*self
, const HklParameter
*parameter
,
208 hkl_error (error
== NULL
|| *error
== NULL
);
210 return hkl_parameter_init_copy(self
->a
, parameter
, error
);
214 * hkl_lattice_b_get: (skip)
215 * @self: the this ptr
217 const HklParameter
*hkl_lattice_b_get(const HklLattice
*self
)
223 * hkl_lattice_b_set: (skip)
224 * @self: the this ptr
225 * @parameter: the parameter to set
226 * @error: return location for a GError, or NULL
228 * Returns: TRUE on success, FALSE if an error occurred
230 int hkl_lattice_b_set(HklLattice
*self
, const HklParameter
*parameter
,
233 hkl_error (error
== NULL
|| *error
== NULL
);
235 return hkl_parameter_init_copy(self
->b
, parameter
, error
);
239 * hkl_lattice_c_get: (skip)
240 * @self: the this ptr
242 const HklParameter
*hkl_lattice_c_get(const HklLattice
*self
)
248 * hkl_lattice_c_set: (skip)
249 * @self: the this ptr
250 * @parameter: the parameter to set
251 * @error: return location for a GError, or NULL
253 * Returns: TRUE on success, FALSE if an error occurred
255 int hkl_lattice_c_set(HklLattice
*self
, const HklParameter
*parameter
,
258 hkl_error (error
== NULL
|| *error
== NULL
);
260 return hkl_parameter_init_copy(self
->c
, parameter
, error
);
264 * hkl_lattice_alpha_get: (skip)
265 * @self: the this ptr
267 const HklParameter
*hkl_lattice_alpha_get(const HklLattice
*self
)
273 * hkl_lattice_alpha_set: (skip)
274 * @self: the this ptr
275 * @parameter: the parameter to set
276 * @error: return location for a GError, or NULL
278 * Returns: TRUE on success, FALSE if an error occurred
280 int hkl_lattice_alpha_set(HklLattice
*self
, const HklParameter
*parameter
,
283 hkl_error (error
== NULL
|| *error
== NULL
);
285 return hkl_parameter_init_copy(self
->alpha
, parameter
, error
);
289 * hkl_lattice_beta_get: (skip)
290 * @self: the this ptr
292 const HklParameter
*hkl_lattice_beta_get(const HklLattice
*self
)
298 * hkl_lattice_beta_set: (skip)
299 * @self: the this ptr
300 * @parameter: the parameter to set
301 * @error: return location for a GError, or NULL
303 * Returns: TRUE on success, FALSE if an error occurred
305 int hkl_lattice_beta_set(HklLattice
*self
, const HklParameter
*parameter
,
308 hkl_error (error
== NULL
|| *error
== NULL
);
310 return hkl_parameter_init_copy(self
->beta
, parameter
, error
);
314 * hkl_lattice_gamma_get: (skip)
315 * @self: the this ptr
317 const HklParameter
*hkl_lattice_gamma_get(const HklLattice
*self
)
323 * hkl_lattice_gamma_set: (skip)
324 * @self: the this ptr
325 * @parameter: the parameter to set
326 * @error: return location for a GError, or NULL
328 * Returns: TRUE on success, FALSE if an error occurred
330 int hkl_lattice_gamma_set(HklLattice
*self
, const HklParameter
*parameter
,
333 hkl_error (error
== NULL
|| *error
== NULL
);
335 return hkl_parameter_init_copy(self
->gamma
, parameter
, error
);
339 * hkl_lattice_lattice_set: (skip)
340 * @self: the this ptr
341 * @lattice: the lattice to set from.
343 void hkl_lattice_lattice_set(HklLattice
*self
, const HklLattice
*lattice
)
348 hkl_parameter_init_copy(self
->a
, lattice
->a
, NULL
);
349 hkl_parameter_init_copy(self
->b
, lattice
->b
, NULL
);
350 hkl_parameter_init_copy(self
->c
, lattice
->c
, NULL
);
351 hkl_parameter_init_copy(self
->alpha
, lattice
->alpha
, NULL
);
352 hkl_parameter_init_copy(self
->beta
, lattice
->beta
, NULL
);
353 hkl_parameter_init_copy(self
->gamma
, lattice
->gamma
, NULL
);
366 * set the lattice parameters
370 int hkl_lattice_set(HklLattice
*self
,
371 double a
, double b
, double c
,
372 double alpha
, double beta
, double gamma
,
373 HklUnitEnum unit_type
, GError
**error
)
375 hkl_error (error
== NULL
|| *error
== NULL
);
377 double _a
, _b
, _c
, _alpha
, _beta
, _gamma
;
379 _a
= convert_to_default(self
->a
, a
, unit_type
);
380 _b
= convert_to_default(self
->b
, b
, unit_type
);
381 _c
= convert_to_default(self
->c
, c
, unit_type
);
382 _alpha
= convert_to_default(self
->alpha
, alpha
, unit_type
);
383 _beta
= convert_to_default(self
->beta
, beta
, unit_type
);
384 _gamma
= convert_to_default(self
->gamma
, gamma
, unit_type
);
386 /* need to do the conversion before the check */
387 if(!check_lattice_param(_a
, _b
, _c
, _alpha
, _beta
, _gamma
, error
)){
388 g_assert (error
== NULL
|| *error
!= NULL
);
391 g_assert (error
== NULL
|| *error
== NULL
);
393 hkl_parameter_value_set(self
->a
, _a
, HKL_UNIT_DEFAULT
, NULL
);
394 hkl_parameter_value_set(self
->b
, _b
, HKL_UNIT_DEFAULT
, NULL
);
395 hkl_parameter_value_set(self
->c
, _c
, HKL_UNIT_DEFAULT
, NULL
);
396 hkl_parameter_value_set(self
->alpha
, _alpha
, HKL_UNIT_DEFAULT
, NULL
);
397 hkl_parameter_value_set(self
->beta
, _beta
, HKL_UNIT_DEFAULT
, NULL
);
398 hkl_parameter_value_set(self
->gamma
, _gamma
, HKL_UNIT_DEFAULT
, NULL
);
406 * @a: (out caller-allocates):
407 * @b: (out caller-allocates):
408 * @c: (out caller-allocates):
409 * @alpha: (out caller-allocates):
410 * @beta: (out caller-allocates):
411 * @gamma: (out caller-allocates):
413 * get the lattice parameters
414 * Return value: all the parameters
416 void hkl_lattice_get(const HklLattice
*self
,
417 double *a
, double *b
, double *c
,
418 double *alpha
, double *beta
, double *gamma
,
419 HklUnitEnum unit_type
)
421 *a
= hkl_parameter_value_get(self
->a
, unit_type
);
422 *b
= hkl_parameter_value_get(self
->b
, unit_type
);
423 *c
= hkl_parameter_value_get(self
->c
, unit_type
);
424 *alpha
= hkl_parameter_value_get(self
->alpha
, unit_type
);
425 *beta
= hkl_parameter_value_get(self
->beta
, unit_type
);
426 *gamma
= hkl_parameter_value_get(self
->gamma
, unit_type
);
430 * hkl_lattice_get_B: (skip)
432 * @B: (out): where to store the B matrix
434 * Get the B matrix from the lattice parameters
438 int hkl_lattice_get_B(const HklLattice
*self
, HklMatrix
*B
)
441 double c_alpha
, s_alpha
;
442 double c_beta
, s_beta
;
443 double c_gamma
, s_gamma
;
444 double b11
, b22
, tmp
;
446 c_alpha
= cos(hkl_parameter_value_get(self
->alpha
, HKL_UNIT_DEFAULT
));
447 c_beta
= cos(hkl_parameter_value_get(self
->beta
, HKL_UNIT_DEFAULT
));
448 c_gamma
= cos(hkl_parameter_value_get(self
->gamma
, HKL_UNIT_DEFAULT
));
449 D
= 1 - c_alpha
*c_alpha
- c_beta
*c_beta
- c_gamma
*c_gamma
450 + 2*c_alpha
*c_beta
*c_gamma
;
457 s_alpha
= sin(hkl_parameter_value_get(self
->alpha
, HKL_UNIT_DEFAULT
));
458 s_beta
= sin(hkl_parameter_value_get(self
->beta
, HKL_UNIT_DEFAULT
));
459 s_gamma
= sin(hkl_parameter_value_get(self
->gamma
, HKL_UNIT_DEFAULT
));
461 b11
= HKL_TAU
/ (hkl_parameter_value_get(self
->b
, HKL_UNIT_DEFAULT
) * s_alpha
);
462 b22
= HKL_TAU
/ hkl_parameter_value_get(self
->c
, HKL_UNIT_DEFAULT
);
465 B
->data
[0][0] = HKL_TAU
* s_alpha
/ (hkl_parameter_value_get(self
->a
, HKL_UNIT_DEFAULT
) * D
);
466 B
->data
[0][1] = b11
/ D
* (c_alpha
*c_beta
- c_gamma
);
467 B
->data
[0][2] = tmp
/ D
* (c_gamma
*c_alpha
- c_beta
);
471 B
->data
[1][2] = tmp
/ (s_beta
*s_gamma
) * (c_beta
*c_gamma
- c_alpha
);
481 * hkl_lattice_get_1_B: (skip)
482 * @self: the @HklLattice
483 * @B: (out): where to store the 1/B matrix
485 * Compute the invert of B (needed by the hkl_sample_UB_set method)
486 * should be optimized
488 * Returns: TRUE or FALSE depending of the success of the
491 int hkl_lattice_get_1_B(const HklLattice
*self
, HklMatrix
*B
)
505 * first compute the B matrix
510 hkl_lattice_get_B(self
, &tmp
);
513 * now invert this triangular matrix
522 B
->data
[0][0] = 1 / a
;
523 B
->data
[0][1] = -b
/ a
/ d
;
524 B
->data
[0][2] = (b
* e
- d
* c
) / a
/ d
/ f
;
527 B
->data
[1][1] = 1 / d
;
528 B
->data
[1][2] = -e
/ d
/ f
;
532 B
->data
[2][2] = 1 / f
;
538 * hkl_lattice_reciprocal:
539 * @self: the this ptr
540 * @reciprocal: the lattice where the result will be computed
542 * compute the reciprocal #HklLattice and put the result id the
543 * provided @reciprocal parameter
545 * Returns: 0 or 1 if it succeed.
547 int hkl_lattice_reciprocal(const HklLattice
*self
, HklLattice
*reciprocal
)
549 double c_alpha
, c_beta
, c_gamma
;
550 double s_alpha
, s_beta
, s_gamma
;
551 double c_beta1
, c_beta2
, c_beta3
;
552 double s_beta1
, s_beta2
, s_beta3
;
553 double s_beta_s_gamma
, s_gamma_s_alpha
, s_alpha_s_beta
;
556 c_alpha
= cos(hkl_parameter_value_get(self
->alpha
, HKL_UNIT_DEFAULT
));
557 c_beta
= cos(hkl_parameter_value_get(self
->beta
, HKL_UNIT_DEFAULT
));
558 c_gamma
= cos(hkl_parameter_value_get(self
->gamma
, HKL_UNIT_DEFAULT
));
559 D
= 1 - c_alpha
*c_alpha
- c_beta
*c_beta
- c_gamma
*c_gamma
560 + 2*c_alpha
*c_beta
*c_gamma
;
567 s_alpha
= sin(hkl_parameter_value_get(self
->alpha
, HKL_UNIT_DEFAULT
));
568 s_beta
= sin(hkl_parameter_value_get(self
->beta
, HKL_UNIT_DEFAULT
));
569 s_gamma
= sin(hkl_parameter_value_get(self
->gamma
, HKL_UNIT_DEFAULT
));
571 s_beta_s_gamma
= s_beta
* s_gamma
;
572 s_gamma_s_alpha
= s_gamma
* s_alpha
;
573 s_alpha_s_beta
= s_alpha
* s_beta
;
575 c_beta1
= (c_beta
* c_gamma
- c_alpha
) / s_beta_s_gamma
;
576 c_beta2
= (c_gamma
* c_alpha
- c_beta
) / s_gamma_s_alpha
;
577 c_beta3
= (c_alpha
* c_beta
- c_gamma
) / s_alpha_s_beta
;
578 s_beta1
= D
/ s_beta_s_gamma
;
579 s_beta2
= D
/ s_gamma_s_alpha
;
580 s_beta3
= D
/ s_alpha_s_beta
;
582 hkl_lattice_set(reciprocal
,
583 HKL_TAU
* s_alpha
/ (hkl_parameter_value_get(self
->a
, HKL_UNIT_DEFAULT
) * D
),
584 HKL_TAU
* s_beta
/ (hkl_parameter_value_get(self
->b
, HKL_UNIT_DEFAULT
) * D
),
585 HKL_TAU
* s_gamma
/ (hkl_parameter_value_get(self
->c
, HKL_UNIT_DEFAULT
) * D
),
586 atan2(s_beta1
, c_beta1
),
587 atan2(s_beta2
, c_beta2
),
588 atan2(s_beta3
, c_beta3
),
589 HKL_UNIT_DEFAULT
, NULL
);
595 * hkl_lattice_randomize: (skip)
598 * randomize the lattice
600 void hkl_lattice_randomize(HklLattice
*self
)
602 static HklVector vector_x
= {{1, 0, 0}};
605 unsigned int angles_to_randomize
;
607 /* La valeur des angles alpha, beta et gamma ne sont pas indépendant. */
608 /* Il faut donc gérer les différents cas. */
609 hkl_parameter_randomize(self
->a
);
610 hkl_parameter_randomize(self
->b
);
611 hkl_parameter_randomize(self
->c
);
613 angles_to_randomize
= self
->alpha
->fit
616 switch (angles_to_randomize
) {
620 if (self
->alpha
->fit
) {
622 a
= b
= c
= vector_x
;
625 hkl_vector_randomize_vector(&axe
, &a
);
626 hkl_vector_rotated_around_vector(&b
, &axe
,
627 hkl_parameter_value_get(self
->gamma
,
631 hkl_vector_randomize_vector(&axe
, &a
);
632 hkl_vector_rotated_around_vector(&c
, &axe
,
633 hkl_parameter_value_get(self
->beta
,
636 /* compute the alpha angle. */
637 hkl_parameter_value_set(self
->alpha
, hkl_vector_angle(&b
, &c
),
638 HKL_UNIT_DEFAULT
, NULL
);
639 } else if (self
->beta
->fit
) {
644 hkl_vector_randomize_vector(&axe
, &a
);
645 hkl_vector_rotated_around_vector(&b
, &axe
,
646 hkl_parameter_value_get(self
->gamma
,
651 hkl_vector_randomize_vector(&axe
, &b
);
652 hkl_vector_rotated_around_vector(&c
, &axe
,
653 hkl_parameter_value_get(self
->alpha
,
657 hkl_parameter_value_set(self
->beta
, hkl_vector_angle(&a
, &c
),
658 HKL_UNIT_DEFAULT
, NULL
);
664 hkl_vector_randomize_vector(&axe
, &a
);
665 hkl_vector_rotated_around_vector(&c
, &axe
,
666 hkl_parameter_value_get(self
->beta
,
671 hkl_vector_randomize_vector(&axe
, &c
);
672 hkl_vector_rotated_around_vector(&b
, &axe
,
673 hkl_parameter_value_get(self
->alpha
,
677 hkl_parameter_value_set(self
->gamma
, hkl_vector_angle(&a
, &b
),
678 HKL_UNIT_DEFAULT
, NULL
);
682 if (self
->alpha
->fit
) {
683 if (self
->beta
->fit
) {
688 hkl_vector_randomize_vector(&axe
, &a
);
689 hkl_vector_rotated_around_vector(&b
, &axe
,
690 hkl_parameter_value_get(self
->gamma
,
694 hkl_vector_randomize_vector_vector(&c
, &a
, &b
);
696 hkl_parameter_value_set(self
->alpha
, hkl_vector_angle(&b
, &c
),
697 HKL_UNIT_DEFAULT
, NULL
);
698 hkl_parameter_value_set(self
->beta
, hkl_vector_angle(&a
, &c
),
699 HKL_UNIT_DEFAULT
, NULL
);
705 hkl_vector_randomize_vector(&axe
, &a
);
706 hkl_vector_rotated_around_vector(&c
, &axe
,
707 hkl_parameter_value_get(self
->beta
,
711 hkl_vector_randomize_vector_vector(&b
, &a
, &c
);
713 hkl_parameter_value_set(self
->alpha
, hkl_vector_angle(&b
, &c
),
714 HKL_UNIT_DEFAULT
, NULL
);
715 hkl_parameter_value_set(self
->gamma
, hkl_vector_angle(&a
, &b
),
716 HKL_UNIT_DEFAULT
, NULL
);
723 hkl_vector_randomize_vector(&axe
, &b
);
724 hkl_vector_rotated_around_vector(&c
, &axe
,
725 hkl_parameter_value_get(self
->alpha
,
729 hkl_vector_randomize_vector_vector(&a
, &b
, &c
);
731 hkl_parameter_value_set(self
->beta
, hkl_vector_angle(&a
, &c
),
732 HKL_UNIT_DEFAULT
, NULL
);
733 hkl_parameter_value_set(self
->gamma
, hkl_vector_angle(&a
, &b
),
734 HKL_UNIT_DEFAULT
, NULL
);
738 hkl_vector_randomize(&a
);
739 hkl_vector_randomize_vector(&b
, &a
);
740 hkl_vector_randomize_vector_vector(&c
, &b
, &a
);
742 hkl_parameter_value_set(self
->alpha
, hkl_vector_angle(&b
, &c
),
743 HKL_UNIT_DEFAULT
, NULL
);
744 hkl_parameter_value_set(self
->beta
, hkl_vector_angle(&a
, &c
),
745 HKL_UNIT_DEFAULT
, NULL
);
746 hkl_parameter_value_set(self
->gamma
, hkl_vector_angle(&a
, &b
),
747 HKL_UNIT_DEFAULT
, NULL
);
753 * hkl_lattice_fprintf: (skip)
757 * print into a file the lattice.
759 void hkl_lattice_fprintf(FILE *f
, HklLattice
const *self
)
762 hkl_parameter_fprintf(f
, self
->a
);
764 hkl_parameter_fprintf(f
, self
->b
);
766 hkl_parameter_fprintf(f
, self
->c
);
768 hkl_parameter_fprintf(f
, self
->alpha
);
770 hkl_parameter_fprintf(f
, self
->beta
);
772 hkl_parameter_fprintf(f
, self
->gamma
);