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-2010 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 <gsl/gsl_math.h>
23 #include <gsl/gsl_vector.h>
24 #include <gsl/gsl_sf_trig.h>
26 #include <hkl/hkl-pseudoaxis.h>
27 #include <hkl/hkl-pseudoaxis-common.h>
28 #include <hkl/hkl-pseudoaxis-auto.h>
29 #include <hkl/hkl-pseudoaxis-common-psi.h>
31 static int psi_func(const gsl_vector
*x
, void *params
, gsl_vector
*f
)
34 HklVector dhkl0
, hkl1
;
35 HklVector ki
, kf
, Q
, n
;
37 HklPseudoAxisEngine
*engine
;
38 HklPseudoAxisEngineModePsi
*modepsi
;
43 double const *x_data
= gsl_vector_const_ptr(x
, 0);
44 double *f_data
= gsl_vector_ptr(f
, 0);
47 modepsi
= (HklPseudoAxisEngineModePsi
*)engine
->mode
;
48 psi
= engine
->pseudoAxes
[0];
50 /* update the workspace from x; */
51 len
= HKL_LIST_LEN(engine
->axes
);
53 hkl_axis_set_value(engine
->axes
[i
], x_data
[i
]);
54 hkl_geometry_update(engine
->geometry
);
57 hkl_source_compute_ki(&engine
->geometry
->source
, &ki
);
58 hkl_detector_compute_kf(engine
->detector
, engine
->geometry
, &kf
);
60 hkl_vector_minus_vector(&Q
, &ki
);
61 if (hkl_vector_is_null(&Q
)){
68 /* for now the 0 holder is the sample holder. */
69 holder
= &engine
->geometry
->holders
[0];
70 hkl_quaternion_to_matrix(&holder
->q
, &RUB
);
71 hkl_matrix_times_matrix(&RUB
, &engine
->sample
->UB
);
74 hkl_matrix_solve(&RUB
, &dhkl0
, &Q
);
75 hkl_vector_minus_vector(&dhkl0
, &modepsi
->hkl0
);
77 /* compute the intersection of the plan P(kf, ki) and PQ (normal Q) */
79 * now that dhkl0 have been computed we can use a
80 * normalized Q to compute n and psi
82 hkl_vector_normalize(&Q
);
84 hkl_vector_vectorial_product(&n
, &ki
);
85 hkl_vector_vectorial_product(&n
, &Q
);
87 /* compute hkl1 in the laboratory referentiel */
88 /* for now the 0 holder is the sample holder. */
89 hkl1
.data
[0] = engine
->mode
->parameters
[0].value
;
90 hkl1
.data
[1] = engine
->mode
->parameters
[1].value
;
91 hkl1
.data
[2] = engine
->mode
->parameters
[2].value
;
92 hkl_vector_times_matrix(&hkl1
, &engine
->sample
->UB
);
93 hkl_vector_rotated_quaternion(&hkl1
, &engine
->geometry
->holders
[0].q
);
95 /* project hkl1 on the plan of normal Q */
96 hkl_vector_project_on_plan(&hkl1
, &Q
);
97 if (hkl_vector_is_null(&hkl1
)){
98 /* hkl1 colinear with Q */
99 f_data
[0] = dhkl0
.data
[0];
100 f_data
[1] = dhkl0
.data
[1];
101 f_data
[2] = dhkl0
.data
[2];
104 f_data
[0] = dhkl0
.data
[0];
105 f_data
[1] = dhkl0
.data
[1];
106 f_data
[2] = dhkl0
.data
[2];
107 f_data
[3] = psi
->parent
.value
- hkl_vector_oriented_angle(&n
, &hkl1
, &Q
);
113 static int hkl_pseudo_axis_engine_mode_init_psi_real(HklPseudoAxisEngineMode
*base
,
114 HklPseudoAxisEngine
*engine
,
115 HklGeometry
*geometry
,
116 HklDetector
*detector
,
120 int status
= HKL_SUCCESS
;
123 HklPseudoAxisEngineModePsi
*self
= (HklPseudoAxisEngineModePsi
*)base
;
126 status
= hkl_pseudo_axis_engine_init_func(base
, engine
, geometry
, detector
, sample
);
127 if (status
== HKL_FAIL
)
130 /* update the geometry internals */
131 hkl_geometry_update(geometry
);
134 /* for now the 0 holder is the sample holder. */
135 holder
= &geometry
->holders
[0];
136 hkl_quaternion_to_matrix(&holder
->q
, &RUB
);
137 hkl_matrix_times_matrix(&RUB
, &sample
->UB
);
140 hkl_source_compute_ki(&geometry
->source
, &ki
);
141 hkl_detector_compute_kf(detector
, geometry
, &self
->Q0
);
142 hkl_vector_minus_vector(&self
->Q0
, &ki
);
143 if (hkl_vector_is_null(&self
->Q0
))
147 hkl_matrix_solve(&RUB
, &self
->hkl0
, &self
->Q0
);
152 static int hkl_pseudo_axis_engine_mode_get_psi_real(HklPseudoAxisEngineMode
*base
,
153 HklPseudoAxisEngine
*engine
,
154 HklGeometry
*geometry
,
155 HklDetector
*detector
,
159 int status
= HKL_SUCCESS
;
166 if (!base
|| !engine
|| !engine
->mode
|| !geometry
|| !detector
|| !sample
){
171 /* get kf, ki and Q */
172 hkl_source_compute_ki(&geometry
->source
, &ki
);
173 hkl_detector_compute_kf(detector
, geometry
, &kf
);
175 hkl_vector_minus_vector(&Q
, &ki
);
176 if (hkl_vector_is_null(&Q
))
179 /* needed for a problem of precision */
180 hkl_vector_normalize(&Q
);
182 /* compute the intersection of the plan P(kf, ki) and PQ (normal Q) */
184 hkl_vector_vectorial_product(&n
, &ki
);
185 hkl_vector_vectorial_product(&n
, &Q
);
187 /* compute hkl1 in the laboratory referentiel */
188 /* the geometry was already updated in the detector compute kf */
189 /* for now the 0 holder is the sample holder. */
190 hkl1
.data
[0] = base
->parameters
[0].value
;
191 hkl1
.data
[1] = base
->parameters
[1].value
;
192 hkl1
.data
[2] = base
->parameters
[2].value
;
193 hkl_vector_times_matrix(&hkl1
, &sample
->UB
);
194 hkl_vector_rotated_quaternion(&hkl1
, &geometry
->holders
[0].q
);
196 /* project hkl1 on the plan of normal Q */
197 hkl_vector_project_on_plan(&hkl1
, &Q
);
199 if (hkl_vector_is_null(&hkl1
))
202 /* compute the angle beetween hkl1 and n */
203 ((HklParameter
*)engine
->pseudoAxes
[0])->value
= hkl_vector_oriented_angle(&n
, &hkl1
, &Q
);
209 HklPseudoAxisEngineModePsi
*hkl_pseudo_axis_engine_mode_psi_new(char const *name
,
210 size_t axes_names_len
,
211 char const *axes_names
[])
213 HklPseudoAxisEngineModePsi
*self
;
214 HklParameter parameters
[3];
215 HklFunction functions
[] = {psi_func
};
217 if (axes_names_len
!= 4){
218 fprintf(stderr
, "This generic HklPseudoAxisEngineModePsi need exactly 4 axes");
222 self
= HKL_MALLOC(HklPseudoAxisEngineModePsi
);
225 hkl_parameter_init(¶meters
[0],
232 hkl_parameter_init(¶meters
[1],
239 hkl_parameter_init(¶meters
[2],
245 /* the base constructor; */
246 hkl_pseudo_axis_engine_mode_init(&self
->parent
,
248 hkl_pseudo_axis_engine_mode_init_psi_real
,
249 hkl_pseudo_axis_engine_mode_get_psi_real
,
250 hkl_pseudo_axis_engine_mode_set_real
,
253 axes_names_len
, axes_names
);
259 HklPseudoAxisEngine
*hkl_pseudo_axis_engine_psi_new(void)
261 HklPseudoAxisEngine
*self
;
263 self
= hkl_pseudo_axis_engine_new("psi", 1, "psi");
266 hkl_parameter_init((HklParameter
*)self
->pseudoAxes
[0],
270 &hkl_unit_angle_rad
, &hkl_unit_angle_deg
);