upgrading copyright year from 2015 to 2016
[hkl.git] / hkl / hkl-engine-soleil-sixs-med.c
blobb6bb4b6681db55126062b10b7a3c181611817c34
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-2016 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_multiroots.h>
23 #include "hkl-factory-private.h" // for autodata_factories_, etc
24 #include "hkl-axis-private.h" // for HklAxis
25 #include "hkl-pseudoaxis-common-hkl-private.h" // for hkl_engine_hkl_new, etc
26 #include "hkl-pseudoaxis-common-q-private.h" // for hkl_engine_q2_new, etc
27 #include "hkl-pseudoaxis-common-tth-private.h" // for hkl_engine_tth2_new, etc
28 #include "hkl-pseudoaxis-common-readonly-private.h"
30 #define PITCH "pitch"
31 #define BETA "beta"
32 #define MU "mu"
33 #define OMEGA "omega"
34 #define GAMMA "gamma"
35 #define DELTA "delta"
36 #define ETA_A "eta_a"
38 /* #define DEBUG */
40 /*********************/
41 /* MED 2+2 HklEngine */
42 /*********************/
44 static int _reflectivity_func(const gsl_vector *x, void *params, gsl_vector *f)
46 const double mu = x->data[0];
47 const double gamma = x->data[2];
49 CHECK_NAN(x->data, x->size);
51 RUBh_minus_Q(x->data, params, f->data);
52 f->data[3] = gamma - 2 * mu;
54 return GSL_SUCCESS;
57 static const HklFunction reflectivity_func = {
58 .function = _reflectivity_func,
59 .size = 4,
62 static HklMode* mu_fixed_2_2()
64 static const char* axes_r[] = {BETA, MU, OMEGA, GAMMA, DELTA};
65 static const char* axes_w[] = {OMEGA, GAMMA, DELTA};
66 static const HklFunction *functions[] = {&RUBh_minus_Q_func};
67 static const HklModeAutoInfo info = {
68 HKL_MODE_AUTO_INFO("mu_fixed", axes_r, axes_w, functions),
71 return hkl_mode_auto_new(&info,
72 &hkl_full_mode_operations,
73 TRUE);
76 static HklMode* reflectivity_2_2()
78 static const char* axes_r[] = {BETA, MU, OMEGA, GAMMA, DELTA};
79 static const char* axes_w[] = {MU, OMEGA, GAMMA, DELTA};
80 static const HklFunction *functions[] = {&reflectivity_func};
81 static const HklModeAutoInfo info = {
82 HKL_MODE_AUTO_INFO("reflectivity", axes_r, axes_w, functions),
85 return hkl_mode_auto_new(&info,
86 &hkl_full_mode_operations,
87 TRUE);
90 static HklMode *emergence_fixed_2_2()
92 static const char* axes_r[] = {BETA, MU, OMEGA, GAMMA, DELTA};
93 static const char* axes_w[] = {MU, OMEGA, GAMMA, DELTA};
94 static const HklFunction* functions[] = {&emergence_fixed_func};
95 static const HklParameter parameters[] = {
96 HKL_MODE_HKL_EMERGENCE_FIXED_PARAMETERS_DEFAULTS(0, 1, 0, 0),
98 static const HklModeAutoInfo info = {
99 HKL_MODE_AUTO_INFO_WITH_PARAMS("emergence_fixed", axes_r, axes_w,
100 functions, parameters),
103 return hkl_mode_hkl_emergence_fixed_new(&info);
106 static HklEngine *hkl_engine_soleil_sixs_med_2_2_hkl_new(HklEngineList *engines)
108 HklEngine *self;
109 HklMode *default_mode;
111 self = hkl_engine_hkl_new(engines);
113 default_mode = mu_fixed_2_2();
114 hkl_engine_add_mode(self, default_mode);
115 hkl_engine_mode_set(self, default_mode);
117 hkl_engine_add_mode(self, reflectivity_2_2());
118 hkl_engine_add_mode(self, emergence_fixed_2_2());
120 return self;
123 /* mode incidence */
125 REGISTER_READONLY_INCIDENCE(hkl_engine_soleil_sixs_med_2_2_incidence_new,
126 P99_PROTECT({BETA, MU, OMEGA}),
127 surface_parameters_y);
129 REGISTER_READONLY_EMERGENCE(hkl_engine_soleil_sixs_med_2_2_emergence_new,
130 P99_PROTECT({BETA, MU, OMEGA, GAMMA, DELTA}),
131 surface_parameters_y);
134 /*********************/
135 /* MED 1+2 HklEngine */
136 /*********************/
138 static HklMode* pitch_fixed()
140 static const char *axes_r[] = {PITCH, MU, GAMMA, DELTA};
141 static const char* axes_w[] = {MU, GAMMA, DELTA};
142 static const HklFunction *functions[] = {&RUBh_minus_Q_func};
143 static const HklModeAutoInfo info = {
144 HKL_MODE_AUTO_INFO(__func__, axes_r, axes_w, functions),
147 return hkl_mode_auto_new(&info,
148 &hkl_full_mode_operations,
149 TRUE);
152 static HklMode *delta_fixed()
154 static const char *axes_r[] = {PITCH, MU, GAMMA, DELTA};
155 static const char* axes_w[] = {PITCH, MU, GAMMA};
156 static const HklFunction *functions[] = {&RUBh_minus_Q_func};
157 static const HklModeAutoInfo info = {
158 HKL_MODE_AUTO_INFO(__func__, axes_r, axes_w, functions),
161 return hkl_mode_auto_new(&info,
162 &hkl_full_mode_operations,
163 TRUE);
166 static HklEngine *hkl_engine_soleil_sixs_med_1_2_hkl_new(HklEngineList *engines)
168 HklEngine *self;
169 HklMode *default_mode;
171 self = hkl_engine_hkl_new(engines);
173 default_mode = pitch_fixed();
174 hkl_engine_add_mode(self, default_mode);
175 hkl_engine_mode_set(self, default_mode);
177 hkl_engine_add_mode(self, delta_fixed());
179 return self;
182 /* mode incidence */
184 static const HklParameter surface_parameters[] = {
185 SURFACE_PARAMETERS(0, 0, 1),
188 REGISTER_READONLY_INCIDENCE(hkl_engine_soleil_sixs_med_1_2_incidence_new,
189 P99_PROTECT({PITCH, MU}),
190 surface_parameters_z);
192 REGISTER_READONLY_EMERGENCE(hkl_engine_soleil_sixs_med_1_2_emergence_new,
193 P99_PROTECT({PITCH, MU, GAMMA, DELTA}),
194 surface_parameters_z);
196 /*********************/
197 /* MED 2+3 HklEngine */
198 /*********************/
200 typedef struct _HklSlitsFit HklSlitsFit;
201 struct _HklSlitsFit
203 HklGeometry *geometry;
204 HklVector surface;
205 unsigned int slits_id;
206 unsigned int len;
207 HklParameter *axis;
210 static int slits_func(const gsl_vector *x, void *params, gsl_vector *f)
212 double const *x_data = gsl_vector_const_ptr(x, 0);
213 double *f_data = gsl_vector_ptr(f, 0);
214 HklVector n_slits = {{0, 0, 1}};
215 HklSlitsFit *parameters = params;
217 hkl_parameter_value_set(parameters->axis, x_data[0], HKL_UNIT_DEFAULT, NULL);
218 hkl_geometry_update(parameters->geometry);
220 /* compute the orientation of the slits */
221 hkl_vector_rotated_quaternion(&n_slits,
222 &darray_item(parameters->geometry->holders, 1)->q);
224 /* both directions must be perpendicular */
225 f_data[0] = hkl_vector_scalar_product(&parameters->surface, &n_slits);
227 return GSL_SUCCESS;
230 static int fit_slits_orientation(HklSlitsFit *params)
232 size_t i;
233 gsl_multiroot_fsolver_type const *T;
234 gsl_multiroot_fsolver *s;
235 gsl_multiroot_function f;
236 gsl_vector *x;
237 double *x_data;
238 int status;
239 int res = FALSE;
240 int iter;
242 /* now solve the system */
243 /* Initialize method */
244 T = gsl_multiroot_fsolver_hybrid;
245 s = gsl_multiroot_fsolver_alloc (T, params->len);
246 x = gsl_vector_alloc(params->len);
247 x_data = gsl_vector_ptr(x, 0);
249 /* initialize x with the right values */
250 x_data[0] = params->axis->_value;
252 f.f = slits_func;
253 f.n = params->len;
254 f.params = params;
255 gsl_multiroot_fsolver_set (s, &f, x);
257 /* iterate to find the solution */
258 iter = 0;
259 do {
260 ++iter;
261 status = gsl_multiroot_fsolver_iterate(s);
262 if (status || iter % 100 == 0) {
263 /* Restart from another point. */
264 for(i=0; i<params->len; ++i)
265 x_data[i] = (double)rand() / RAND_MAX * 180. / M_PI;
266 gsl_multiroot_fsolver_set(s, &f, x);
267 gsl_multiroot_fsolver_iterate(s);
269 status = gsl_multiroot_test_residual (s->f, HKL_EPSILON);
270 } while (status == GSL_CONTINUE && iter < 1000);
272 #ifdef DEBUG
273 fprintf(stdout, "\n fitting the detector position using thoses axes :");
274 for(i=0; i<params->len; ++i)
275 fprintf(stdout, " \"%s\"", params->axis->name);
276 fprintf(stdout, " status : %d iter : %d", status, iter);
277 fprintf(stdout, " x: [");
278 for(i=0; i<params->len; ++i)
279 fprintf(stdout, " %.7f", s->x->data[i]);
280 fprintf(stdout, "] f: [");
281 for(i=0; i<params->len; ++i)
282 fprintf(stdout, " %.7f", s->f->data[i]);
283 fprintf(stdout, "]\n");
284 hkl_geometry_fprintf(stdout, params->geometry);
285 #endif
286 if(status != GSL_CONTINUE){
287 res = TRUE;
288 /* put the axes in the -pi, pi range. */
289 gsl_sf_angle_restrict_pos_e(&params->axis->_value);
291 /* release memory */
292 gsl_vector_free(x);
293 gsl_multiroot_fsolver_free(s);
295 return res;
298 static void hkl_geometry_list_multiply_soleil_sixs_med_2_3(HklGeometryList *self,
299 HklGeometryListItem *item)
301 HklSlitsFit params;
302 HklGeometry *geometry;
303 double slits_position;
304 HklHolder *sample_holder;
305 HklHolder *detector_holder;
307 /* For each solution already found we will generate another one */
308 /* we will set the right slit orientation for a given detector arm position */
309 geometry = item->geometry;
310 sample_holder = darray_item(geometry->holders, 0);
311 detector_holder = darray_item(geometry->holders, 1);
313 /* get the index of the axis corresponding to the slits */
314 /* for now the last holder is the detector one */
315 params.slits_id = detector_holder->config->idx[detector_holder->config->len-1];
316 params.len = 1; /* only one axis to fit */
317 params.geometry = geometry;
318 params.axis = darray_item(params.geometry->axes, params.slits_id);
320 /* compute the surface orientation fixed during the fit */
321 /* use the last sample axis as sample surface normal */
322 params.surface = container_of(darray_item(geometry->axes,
323 sample_holder->config->idx[sample_holder->config->len - 1]),
324 HklAxis, parameter)->axis_v;
325 hkl_vector_rotated_quaternion(&params.surface,
326 &sample_holder->q);
329 /* we just need to fit the slits orientation */
330 /* save it's value before */
331 slits_position = hkl_parameter_value_get(params.axis, HKL_UNIT_DEFAULT);
332 if (fit_slits_orientation(&params) != TRUE)
333 hkl_parameter_value_set(params.axis, slits_position, HKL_UNIT_DEFAULT, NULL);
336 static HklMode* mu_fixed_2_3()
338 static const char *axes_r[] = {BETA, MU, OMEGA, GAMMA, DELTA, ETA_A};
339 static const char* axes_w[] = {OMEGA, GAMMA, DELTA};
340 static const HklFunction *functions[] = {&RUBh_minus_Q_func};
341 static const HklModeAutoInfo info = {
342 HKL_MODE_AUTO_INFO("mu_fixed", axes_r, axes_w, functions),
345 return hkl_mode_auto_new(&info,
346 &hkl_full_mode_operations,
347 TRUE);
350 static HklMode* gamma_fixed_2_3()
352 static const char *axes_r[] = {BETA, MU, OMEGA, GAMMA, DELTA, ETA_A};
353 static const char* axes_w[] = {MU, OMEGA, DELTA};
354 static const HklFunction *functions[] = {&RUBh_minus_Q_func};
355 static const HklModeAutoInfo info = {
356 HKL_MODE_AUTO_INFO("gamma_fixed", axes_r, axes_w, functions),
359 return hkl_mode_auto_new(&info,
360 &hkl_full_mode_operations,
361 TRUE);
364 static HklMode *emergence_fixed_2_3()
366 static const char* axes_r[] = {BETA, MU, OMEGA, GAMMA, DELTA, ETA_A};
367 static const char* axes_w[] = {MU, OMEGA, GAMMA, DELTA};
368 static const HklFunction* functions[] = {&emergence_fixed_func};
369 static const HklParameter parameters[] = {
370 HKL_MODE_HKL_EMERGENCE_FIXED_PARAMETERS_DEFAULTS(0, 1, 0, 0),
372 static const HklModeAutoInfo info = {
373 HKL_MODE_AUTO_INFO_WITH_PARAMS("emergence_fixed", axes_r, axes_w,
374 functions, parameters),
377 return hkl_mode_hkl_emergence_fixed_new(&info);
380 static HklEngine *hkl_engine_soleil_sixs_med_2_3_hkl_new(HklEngineList *engines)
382 HklEngine *self;
383 HklMode *default_mode;
385 self = hkl_engine_hkl_new(engines);
387 default_mode = mu_fixed_2_3();
388 hkl_engine_add_mode(self, default_mode);
389 hkl_engine_mode_set(self, default_mode);
391 hkl_engine_add_mode(self, gamma_fixed_2_3());
392 hkl_engine_add_mode(self, emergence_fixed_2_3());
394 return self;
397 /***********************/
398 /* SOLEIL SIXS MED 2+2 */
399 /***********************/
401 #define HKL_GEOMETRY_TYPE_SOLEIL_SIXS_MED_2_2_DESCRIPTION \
402 "+ xrays source fix allong the :math:`\\vec{x}` direction (1, 0, 0)\n" \
403 "+ 3 axes for the sample\n" \
404 "\n" \
405 " + **" BETA "** : rotation around the :math:`-\\vec{y}` direction (0, -1, 0)\n" \
406 " + **" MU "** : rotation around the :math:`\\vec{z}` direction (0, 0, 1)\n" \
407 " + **" OMEGA "** : rotating around the :math:`-\\vec{y}` direction (0, -1, 0)\n" \
408 "\n" \
409 "+ 3 axis for the detector\n" \
410 "\n" \
411 " + **" BETA "** : rotation around the :math:`-\\vec{y}` direction (0, -1, 0)\n" \
412 " + **" GAMMA "** : rotation around the :math:`\\vec{z}` direction (0, 0, 1)\n" \
413 " + **" DELTA "** : rotation around the :math:`-\\vec{y}` direction (0, -1, 0)\n"
415 static const char* hkl_geometry_soleil_sixs_med_2_2_axes[] = {BETA, MU, OMEGA, GAMMA, DELTA};
417 static HklGeometry *hkl_geometry_new_soleil_sixs_med_2_2(const HklFactory *factory)
419 HklGeometry *self = hkl_geometry_new(factory);
420 HklHolder *h;
422 h = hkl_geometry_add_holder(self);
423 hkl_holder_add_rotation_axis(h, BETA, 0, -1, 0);
424 hkl_holder_add_rotation_axis(h, MU, 0, 0, 1);
425 hkl_holder_add_rotation_axis(h, OMEGA, 0, -1, 0);
427 h = hkl_geometry_add_holder(self);
428 hkl_holder_add_rotation_axis(h, BETA, 0, -1, 0);
429 hkl_holder_add_rotation_axis(h, GAMMA, 0, 0, 1);
430 hkl_holder_add_rotation_axis(h, DELTA, 0, -1, 0);
432 return self;
435 static HklEngineList *hkl_engine_list_new_soleil_sixs_med_2_2(const HklFactory *factory)
437 HklEngineList *self = hkl_engine_list_new();
439 hkl_engine_soleil_sixs_med_2_2_hkl_new(self);
440 hkl_engine_q2_new(self);
441 hkl_engine_qper_qpar_new(self);
442 hkl_engine_tth2_new(self);
443 hkl_engine_soleil_sixs_med_2_2_incidence_new(self);
444 hkl_engine_soleil_sixs_med_2_2_emergence_new(self);
446 return self;
449 REGISTER_DIFFRACTOMETER(soleil_sixs_med_2_2,"SOLEIL SIXS MED2+2", HKL_GEOMETRY_TYPE_SOLEIL_SIXS_MED_2_2_DESCRIPTION);
451 /***********************/
452 /* SOLEIL SIXS MED 1+2 */
453 /***********************/
455 #define HKL_GEOMETRY_TYPE_SOLEIL_SIXS_MED_1_2_DESCRIPTION \
456 "+ xrays source fix allong the :math:`\\vec{x}` direction (1, 0, 0)\n" \
457 "+ 2 axes for the sample\n" \
458 "\n" \
459 " + **" PITCH "** : rotation around the :math:`-\\vec{y}` direction (0, -1, 0)\n" \
460 " + **" MU "** : rotation around the :math:`\\vec{z}` direction (0, 0, 1)\n" \
461 "\n" \
462 "+ 3 axis for the detector\n" \
463 "\n" \
464 " + **" PITCH "** : rotation around the :math:`-\\vec{y}` direction (0, -1, 0)\n" \
465 " + **" GAMMA "** : rotation around the :math:`\\vec{z}` direction (0, 0, 1)\n" \
466 " + **" DELTA "** : rotation around the :math:`-\\vec{y}` direction (0, -1, 0)\n"
468 static const char* hkl_geometry_soleil_sixs_med_1_2_axes[] = {PITCH, MU, GAMMA, DELTA};
470 static HklGeometry *hkl_geometry_new_soleil_sixs_med_1_2(const HklFactory *factory)
472 HklGeometry *self = hkl_geometry_new(factory);
473 HklHolder *h;
474 h = hkl_geometry_add_holder(self);
475 hkl_holder_add_rotation_axis(h, PITCH, 0, -1, 0);
476 hkl_holder_add_rotation_axis(h, MU, 0, 0, 1);
478 h = hkl_geometry_add_holder(self);
479 hkl_holder_add_rotation_axis(h, PITCH, 0, -1, 0);
480 hkl_holder_add_rotation_axis(h, GAMMA, 0, 0, 1);
481 hkl_holder_add_rotation_axis(h, DELTA, 0, -1, 0);
483 return self;
486 static HklEngineList *hkl_engine_list_new_soleil_sixs_med_1_2(const HklFactory *factory)
488 HklEngineList *self = hkl_engine_list_new();
490 hkl_engine_soleil_sixs_med_1_2_hkl_new(self);
491 hkl_engine_q2_new(self);
492 hkl_engine_qper_qpar_new(self);
493 hkl_engine_tth2_new(self);
494 hkl_engine_soleil_sixs_med_1_2_incidence_new(self);
495 hkl_engine_soleil_sixs_med_1_2_emergence_new(self);
497 return self;
500 REGISTER_DIFFRACTOMETER(soleil_sixs_med_1_2, "SOLEIL SIXS MED1+2", HKL_GEOMETRY_TYPE_SOLEIL_SIXS_MED_1_2_DESCRIPTION);
503 /***********************/
504 /* SOLEIL SIXS MED 2+3 */
505 /***********************/
507 #define HKL_GEOMETRY_TYPE_SOLEIL_SIXS_MED_2_3_DESCRIPTION \
508 "+ xrays source fix allong the :math:`\\vec{x}` direction (1, 0, 0)\n" \
509 "+ 3 axes for the sample\n" \
510 "\n" \
511 " + **" BETA "** : rotation around the :math:`-\\vec{y}` direction (0, -1, 0)\n" \
512 " + **" MU "** : rotation around the :math:`\\vec{z}` direction (0, 0, 1)\n" \
513 " + **" OMEGA "** : rotating around the :math:`-\\vec{y}` direction (0, -1, 0)\n" \
514 "\n" \
515 "+ 4 axis for the detector\n" \
516 "\n" \
517 " + **" BETA "** : rotation around the :math:`-\\vec{y}` direction (0, -1, 0)\n" \
518 " + **" GAMMA "** : rotation around the :math:`\\vec{z}` direction (0, 0, 1)\n" \
519 " + **" DELTA "** : rotation around the :math:`-\\vec{y}` direction (0, -1, 0)\n" \
520 " + **" ETA_A "** : rotation around the :math:`-\\vec{x}` direction (-1, 0, 0)\n"
522 static const char* hkl_geometry_soleil_sixs_med_2_3_axes[] = {BETA, MU, OMEGA, GAMMA, DELTA, ETA_A};
524 static HklGeometry *hkl_geometry_new_soleil_sixs_med_2_3(const HklFactory *factory)
526 HklGeometry *self = hkl_geometry_new(factory);
527 HklHolder *h;
529 h = hkl_geometry_add_holder(self);
530 hkl_holder_add_rotation_axis(h, BETA, 0, -1, 0);
531 hkl_holder_add_rotation_axis(h, MU, 0, 0, 1);
532 hkl_holder_add_rotation_axis(h, OMEGA, 0, -1, 0);
534 h = hkl_geometry_add_holder(self);
535 hkl_holder_add_rotation_axis(h, BETA, 0, -1, 0);
536 hkl_holder_add_rotation_axis(h, GAMMA, 0, 0, 1);
537 hkl_holder_add_rotation_axis(h, DELTA, 0, -1, 0);
538 hkl_holder_add_rotation_axis(h, ETA_A, -1, 0, 0);
540 return self;
543 static HklEngineList *hkl_engine_list_new_soleil_sixs_med_2_3(const HklFactory *factory)
545 HklEngineList *self = hkl_engine_list_new();
547 self->geometries->multiply = hkl_geometry_list_multiply_soleil_sixs_med_2_3;
548 hkl_engine_soleil_sixs_med_2_3_hkl_new(self);
549 hkl_engine_q2_new(self);
550 hkl_engine_qper_qpar_new(self);
551 hkl_engine_tth2_new(self);
552 hkl_engine_soleil_sixs_med_2_2_incidence_new(self);
553 hkl_engine_soleil_sixs_med_2_2_emergence_new(self);
555 return self;
558 REGISTER_DIFFRACTOMETER(soleil_sixs_med_2_3, "SOLEIL SIXS MED2+3", HKL_GEOMETRY_TYPE_SOLEIL_SIXS_MED_2_3_DESCRIPTION);