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_smatrix(&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
)){ // hkl1 colinear with Q
98 f_data
[0] = dhkl0
.data
[0];
99 f_data
[1] = dhkl0
.data
[1];
100 f_data
[2] = dhkl0
.data
[2];
103 f_data
[0] = dhkl0
.data
[0];
104 f_data
[1] = dhkl0
.data
[1];
105 f_data
[2] = dhkl0
.data
[2];
106 f_data
[3] = psi
->parent
.value
- hkl_vector_oriented_angle(&n
, &hkl1
, &Q
);
112 static int hkl_pseudo_axis_engine_mode_init_psi_real(HklPseudoAxisEngineMode
*base
,
113 HklPseudoAxisEngine
*engine
,
114 HklGeometry
*geometry
,
115 HklDetector
*detector
,
119 int status
= HKL_SUCCESS
;
122 HklPseudoAxisEngineModePsi
*self
= (HklPseudoAxisEngineModePsi
*)base
;
125 status
= hkl_pseudo_axis_engine_init_func(base
, engine
, geometry
, detector
, sample
);
126 if (status
== HKL_FAIL
)
129 // update the geometry internals
130 hkl_geometry_update(geometry
);
133 // for now the 0 holder is the sample holder.
134 holder
= &geometry
->holders
[0];
135 hkl_quaternion_to_matrix(&holder
->q
, &RUB
);
136 hkl_matrix_times_matrix(&RUB
, &sample
->UB
);
139 hkl_source_compute_ki(&geometry
->source
, &ki
);
140 hkl_detector_compute_kf(detector
, geometry
, &self
->Q0
);
141 hkl_vector_minus_vector(&self
->Q0
, &ki
);
142 if (hkl_vector_is_null(&self
->Q0
))
146 hkl_matrix_solve(&RUB
, &self
->hkl0
, &self
->Q0
);
151 static int hkl_pseudo_axis_engine_mode_get_psi_real(HklPseudoAxisEngineMode
*base
,
152 HklPseudoAxisEngine
*engine
,
153 HklGeometry
*geometry
,
154 HklDetector
*detector
,
158 int status
= HKL_SUCCESS
;
160 if (!base
|| !engine
|| !engine
->mode
|| !geometry
|| !detector
|| !sample
){
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 hkl_vector_normalize(&Q
); // needed for a problem of precision
181 // compute the intersection of the plan P(kf, ki) and PQ (normal Q)
183 hkl_vector_vectorial_product(&n
, &ki
);
184 hkl_vector_vectorial_product(&n
, &Q
);
186 // compute hkl1 in the laboratory referentiel
187 // the geometry was already updated in the detector compute kf
188 // for now the 0 holder is the sample holder.
189 hkl1
.data
[0] = base
->parameters
[0].value
;
190 hkl1
.data
[1] = base
->parameters
[1].value
;
191 hkl1
.data
[2] = base
->parameters
[2].value
;
192 hkl_vector_times_smatrix(&hkl1
, &sample
->UB
);
193 hkl_vector_rotated_quaternion(&hkl1
, &geometry
->holders
[0].q
);
195 // project hkl1 on the plan of normal Q
196 hkl_vector_project_on_plan(&hkl1
, &Q
);
198 if (hkl_vector_is_null(&hkl1
))
201 // compute the angle beetween hkl1 and n
202 ((HklParameter
*)engine
->pseudoAxes
[0])->value
= hkl_vector_oriented_angle(&n
, &hkl1
, &Q
);
208 HklPseudoAxisEngineModePsi
*hkl_pseudo_axis_engine_mode_psi_new(char const *name
,
209 size_t axes_names_len
,
210 char const *axes_names
[])
212 HklPseudoAxisEngineModePsi
*self
;
213 HklParameter parameters
[3];
214 HklFunction functions
[] = {psi_func
};
216 if (axes_names_len
!= 4)
217 die("This generic HklPseudoAxisEngineModePsi need exactly 4 axes");
219 self
= HKL_MALLOC(HklPseudoAxisEngineModePsi
);
222 hkl_parameter_init(¶meters
[0],
229 hkl_parameter_init(¶meters
[1],
236 hkl_parameter_init(¶meters
[2],
242 // the base constructor;
243 hkl_pseudo_axis_engine_mode_init(&self
->parent
,
245 hkl_pseudo_axis_engine_mode_init_psi_real
,
246 hkl_pseudo_axis_engine_mode_get_psi_real
,
247 hkl_pseudo_axis_engine_mode_set_real
,
250 axes_names_len
, axes_names
);
256 HklPseudoAxisEngine
*hkl_pseudo_axis_engine_psi_new(void)
258 HklPseudoAxisEngine
*self
;
260 self
= hkl_pseudo_axis_engine_new("psi", 1, "psi");
263 hkl_parameter_init((HklParameter
*)self
->pseudoAxes
[0],
267 &hkl_unit_angle_rad
, &hkl_unit_angle_deg
);