wip
[hkl.git] / hkl / hkl-engine-soleil-sixs-med.c
blobddb9ee8affc71a4b1a0c2de3c55bb157d6fbc97e
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-2019, 2022 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 REGISTER_READONLY_INCIDENCE(hkl_engine_soleil_sixs_med_1_2_incidence_new,
185 P99_PROTECT({PITCH, MU}),
186 surface_parameters_z);
188 REGISTER_READONLY_EMERGENCE(hkl_engine_soleil_sixs_med_1_2_emergence_new,
189 P99_PROTECT({PITCH, MU, GAMMA, DELTA}),
190 surface_parameters_z);
192 /*********************/
193 /* MED 2+3 HklEngine */
194 /*********************/
196 typedef struct _HklSlitsFit HklSlitsFit;
197 struct _HklSlitsFit
199 HklGeometry *geometry;
200 HklVector surface;
201 unsigned int slits_id;
202 unsigned int len;
203 HklParameter *axis;
206 static int slits_func(const gsl_vector *x, void *params, gsl_vector *f)
208 double const *x_data = gsl_vector_const_ptr(x, 0);
209 double *f_data = gsl_vector_ptr(f, 0);
210 HklVector n_slits = {{0, 0, 1}};
211 HklSlitsFit *parameters = params;
213 hkl_parameter_value_set(parameters->axis, x_data[0], HKL_UNIT_DEFAULT, NULL);
214 hkl_geometry_update(parameters->geometry);
216 /* compute the orientation of the slits */
217 hkl_vector_rotated_quaternion(&n_slits,
218 &darray_item(parameters->geometry->holders, 1)->q);
220 /* both directions must be perpendicular */
221 f_data[0] = hkl_vector_scalar_product(&parameters->surface, &n_slits);
223 return GSL_SUCCESS;
226 static int fit_slits_orientation(HklSlitsFit *params)
228 size_t i;
229 gsl_multiroot_fsolver_type const *T;
230 gsl_multiroot_fsolver *s;
231 gsl_multiroot_function f;
232 gsl_vector *x;
233 double *x_data;
234 int status;
235 int res = FALSE;
236 int iter;
238 /* now solve the system */
239 /* Initialize method */
240 T = gsl_multiroot_fsolver_hybrid;
241 s = gsl_multiroot_fsolver_alloc (T, params->len);
242 x = gsl_vector_alloc(params->len);
243 x_data = gsl_vector_ptr(x, 0);
245 /* initialize x with the right values */
246 x_data[0] = params->axis->_value;
248 f.f = slits_func;
249 f.n = params->len;
250 f.params = params;
251 gsl_multiroot_fsolver_set (s, &f, x);
253 /* iterate to find the solution */
254 iter = 0;
255 do {
256 ++iter;
257 status = gsl_multiroot_fsolver_iterate(s);
258 if (status || iter % 100 == 0) {
259 /* Restart from another point. */
260 for(i=0; i<params->len; ++i)
261 x_data[i] = (double)rand() / RAND_MAX * 180. / M_PI;
262 gsl_multiroot_fsolver_set(s, &f, x);
263 gsl_multiroot_fsolver_iterate(s);
265 status = gsl_multiroot_test_residual (s->f, HKL_EPSILON);
266 } while (status == GSL_CONTINUE && iter < 1000);
268 #ifdef DEBUG
269 fprintf(stdout, "\n fitting the detector position using thoses axes :");
270 for(i=0; i<params->len; ++i)
271 fprintf(stdout, " \"%s\"", params->axis->name);
272 fprintf(stdout, " status : %d iter : %d", status, iter);
273 fprintf(stdout, " x: [");
274 for(i=0; i<params->len; ++i)
275 fprintf(stdout, " %.7f", s->x->data[i]);
276 fprintf(stdout, "] f: [");
277 for(i=0; i<params->len; ++i)
278 fprintf(stdout, " %.7f", s->f->data[i]);
279 fprintf(stdout, "]\n");
280 hkl_geometry_fprintf(stdout, params->geometry);
281 #endif
282 if(status != GSL_CONTINUE){
283 res = TRUE;
284 /* put the axes in the -pi, pi range. */
285 gsl_sf_angle_restrict_pos_e(&params->axis->_value);
287 /* release memory */
288 gsl_vector_free(x);
289 gsl_multiroot_fsolver_free(s);
291 return res;
294 static void hkl_geometry_list_multiply_soleil_sixs_med_2_3(HklGeometryList *self,
295 HklGeometryListItem *item) HKL_ARG_NONNULL(1, 2);
296 static void hkl_geometry_list_multiply_soleil_sixs_med_2_3(HklGeometryList *self,
297 HklGeometryListItem *item)
299 HklSlitsFit params;
300 HklGeometry *geometry;
301 double slits_position;
302 HklHolder *sample_holder;
303 HklHolder *detector_holder;
305 /* For each solution already found we will generate another one */
306 /* we will set the right slit orientation for a given detector arm position */
307 geometry = item->geometry;
308 sample_holder = darray_item(geometry->holders, 0);
309 detector_holder = darray_item(geometry->holders, 1);
311 /* get the index of the axis corresponding to the slits */
312 /* for now the last holder is the detector one */
313 params.slits_id = detector_holder->config->idx[detector_holder->config->len-1];
314 params.len = 1; /* only one axis to fit */
315 params.geometry = geometry;
316 params.axis = darray_item(params.geometry->axes, params.slits_id);
318 /* compute the surface orientation fixed during the fit */
319 /* use the last sample axis as sample surface normal */
320 params.surface = container_of(darray_item(geometry->axes,
321 sample_holder->config->idx[sample_holder->config->len - 1]),
322 HklAxis, parameter)->axis_v;
323 hkl_vector_rotated_quaternion(&params.surface,
324 &sample_holder->q);
327 /* we just need to fit the slits orientation */
328 /* save it's value before */
329 slits_position = hkl_parameter_value_get(params.axis, HKL_UNIT_DEFAULT);
330 if (fit_slits_orientation(&params) != TRUE)
331 hkl_parameter_value_set(params.axis, slits_position, HKL_UNIT_DEFAULT, NULL);
334 static HklMode* mu_fixed_2_3()
336 static const char *axes_r[] = {BETA, MU, OMEGA, GAMMA, DELTA, ETA_A};
337 static const char* axes_w[] = {OMEGA, GAMMA, DELTA};
338 static const HklFunction *functions[] = {&RUBh_minus_Q_func};
339 static const HklModeAutoInfo info = {
340 HKL_MODE_AUTO_INFO("mu_fixed", axes_r, axes_w, functions),
343 return hkl_mode_auto_new(&info,
344 &hkl_full_mode_operations,
345 TRUE);
348 static HklMode* gamma_fixed_2_3()
350 static const char *axes_r[] = {BETA, MU, OMEGA, GAMMA, DELTA, ETA_A};
351 static const char* axes_w[] = {MU, OMEGA, DELTA};
352 static const HklFunction *functions[] = {&RUBh_minus_Q_func};
353 static const HklModeAutoInfo info = {
354 HKL_MODE_AUTO_INFO("gamma_fixed", axes_r, axes_w, functions),
357 return hkl_mode_auto_new(&info,
358 &hkl_full_mode_operations,
359 TRUE);
362 static HklMode *emergence_fixed_2_3()
364 static const char* axes_r[] = {BETA, MU, OMEGA, GAMMA, DELTA, ETA_A};
365 static const char* axes_w[] = {MU, OMEGA, GAMMA, DELTA};
366 static const HklFunction* functions[] = {&emergence_fixed_func};
367 static const HklParameter parameters[] = {
368 HKL_MODE_HKL_EMERGENCE_FIXED_PARAMETERS_DEFAULTS(0, 1, 0, 0),
370 static const HklModeAutoInfo info = {
371 HKL_MODE_AUTO_INFO_WITH_PARAMS("emergence_fixed", axes_r, axes_w,
372 functions, parameters),
375 return hkl_mode_hkl_emergence_fixed_new(&info);
378 static HklEngine *hkl_engine_soleil_sixs_med_2_3_hkl_new(HklEngineList *engines)
380 HklEngine *self;
381 HklMode *default_mode;
383 self = hkl_engine_hkl_new(engines);
385 default_mode = mu_fixed_2_3();
386 hkl_engine_add_mode(self, default_mode);
387 hkl_engine_mode_set(self, default_mode);
389 hkl_engine_add_mode(self, gamma_fixed_2_3());
390 hkl_engine_add_mode(self, emergence_fixed_2_3());
392 return self;
395 /***********************/
396 /* SOLEIL SIXS MED 2+2 */
397 /***********************/
399 #define HKL_GEOMETRY_TYPE_SOLEIL_SIXS_MED_2_2_DESCRIPTION \
400 "+ xrays source fix allong the :math:`\\vec{x}` direction (1, 0, 0)\n" \
401 "+ 3 axes for the sample\n" \
402 "\n" \
403 " + **" BETA "** : rotation around the :math:`-\\vec{y}` direction (0, -1, 0)\n" \
404 " + **" MU "** : rotation around the :math:`\\vec{z}` direction (0, 0, 1)\n" \
405 " + **" OMEGA "** : rotating around the :math:`-\\vec{y}` direction (0, -1, 0)\n" \
406 "\n" \
407 "+ 3 axis for the detector\n" \
408 "\n" \
409 " + **" BETA "** : rotation around the :math:`-\\vec{y}` direction (0, -1, 0)\n" \
410 " + **" GAMMA "** : rotation around the :math:`\\vec{z}` direction (0, 0, 1)\n" \
411 " + **" DELTA "** : rotation around the :math:`-\\vec{y}` direction (0, -1, 0)\n"
413 static const char* hkl_geometry_soleil_sixs_med_2_2_axes[] = {BETA, MU, OMEGA, GAMMA, DELTA};
415 static HklGeometry *hkl_geometry_new_soleil_sixs_med_2_2(const HklFactory *factory)
417 HklGeometry *self = hkl_geometry_new(factory, &hkl_geometry_operations_defaults);
418 HklHolder *h;
420 h = hkl_geometry_add_holder(self);
421 hkl_holder_add_rotation(h, BETA, 0, -1, 0, &hkl_unit_angle_deg);
422 hkl_holder_add_rotation(h, MU, 0, 0, 1, &hkl_unit_angle_deg);
423 hkl_holder_add_rotation(h, OMEGA, 0, -1, 0, &hkl_unit_angle_deg);
425 h = hkl_geometry_add_holder(self);
426 hkl_holder_add_rotation(h, BETA, 0, -1, 0, &hkl_unit_angle_deg);
427 hkl_holder_add_rotation(h, GAMMA, 0, 0, 1, &hkl_unit_angle_deg);
428 hkl_holder_add_rotation(h, DELTA, 0, -1, 0, &hkl_unit_angle_deg);
430 return self;
433 static HklEngineList *hkl_engine_list_new_soleil_sixs_med_2_2(const HklFactory *factory)
435 HklEngineList *self = hkl_engine_list_new();
437 hkl_engine_soleil_sixs_med_2_2_hkl_new(self);
438 hkl_engine_q2_new(self);
439 hkl_engine_qper_qpar_new(self);
440 hkl_engine_tth2_new(self);
441 hkl_engine_soleil_sixs_med_2_2_incidence_new(self);
442 hkl_engine_soleil_sixs_med_2_2_emergence_new(self);
444 return self;
447 REGISTER_DIFFRACTOMETER(soleil_sixs_med_2_2,"SOLEIL SIXS MED2+2", HKL_GEOMETRY_TYPE_SOLEIL_SIXS_MED_2_2_DESCRIPTION);
449 /***********************/
450 /* SOLEIL SIXS MED 1+2 */
451 /***********************/
453 #define HKL_GEOMETRY_TYPE_SOLEIL_SIXS_MED_1_2_DESCRIPTION \
454 "+ xrays source fix allong the :math:`\\vec{x}` direction (1, 0, 0)\n" \
455 "+ 2 axes for the sample\n" \
456 "\n" \
457 " + **" PITCH "** : rotation around the :math:`-\\vec{y}` direction (0, -1, 0)\n" \
458 " + **" MU "** : rotation around the :math:`\\vec{z}` direction (0, 0, 1)\n" \
459 "\n" \
460 "+ 3 axis for the detector\n" \
461 "\n" \
462 " + **" PITCH "** : rotation around the :math:`-\\vec{y}` direction (0, -1, 0)\n" \
463 " + **" GAMMA "** : rotation around the :math:`\\vec{z}` direction (0, 0, 1)\n" \
464 " + **" DELTA "** : rotation around the :math:`-\\vec{y}` direction (0, -1, 0)\n"
466 static const char* hkl_geometry_soleil_sixs_med_1_2_axes[] = {PITCH, MU, GAMMA, DELTA};
468 static HklGeometry *hkl_geometry_new_soleil_sixs_med_1_2(const HklFactory *factory)
470 HklGeometry *self = hkl_geometry_new(factory, &hkl_geometry_operations_defaults);
471 HklHolder *h;
472 h = hkl_geometry_add_holder(self);
473 hkl_holder_add_rotation(h, PITCH, 0, -1, 0, &hkl_unit_angle_deg);
474 hkl_holder_add_rotation(h, MU, 0, 0, 1, &hkl_unit_angle_deg);
476 h = hkl_geometry_add_holder(self);
477 hkl_holder_add_rotation(h, PITCH, 0, -1, 0, &hkl_unit_angle_deg);
478 hkl_holder_add_rotation(h, GAMMA, 0, 0, 1, &hkl_unit_angle_deg);
479 hkl_holder_add_rotation(h, DELTA, 0, -1, 0, &hkl_unit_angle_deg);
481 return self;
484 static HklEngineList *hkl_engine_list_new_soleil_sixs_med_1_2(const HklFactory *factory)
486 HklEngineList *self = hkl_engine_list_new();
488 hkl_engine_soleil_sixs_med_1_2_hkl_new(self);
489 hkl_engine_q2_new(self);
490 hkl_engine_qper_qpar_new(self);
491 hkl_engine_tth2_new(self);
492 hkl_engine_soleil_sixs_med_1_2_incidence_new(self);
493 hkl_engine_soleil_sixs_med_1_2_emergence_new(self);
495 return self;
498 REGISTER_DIFFRACTOMETER(soleil_sixs_med_1_2, "SOLEIL SIXS MED1+2", HKL_GEOMETRY_TYPE_SOLEIL_SIXS_MED_1_2_DESCRIPTION);
501 /******************************/
502 /* SOLEIL SIXS MED 2+3 (MedV) */
503 /******************************/
505 #define HKL_GEOMETRY_TYPE_SOLEIL_SIXS_MED_2_3_DESCRIPTION \
506 "+ xrays source fix allong the :math:`\\vec{x}` direction (1, 0, 0)\n" \
507 "+ 3 axes for the sample\n" \
508 "\n" \
509 " + **" BETA "** : rotation around the :math:`-\\vec{y}` direction (0, -1, 0)\n" \
510 " + **" MU "** : rotation around the :math:`\\vec{z}` direction (0, 0, 1)\n" \
511 " + **" OMEGA "** : rotating around the :math:`-\\vec{y}` direction (0, -1, 0)\n" \
512 "\n" \
513 "+ 4 axis for the detector\n" \
514 "\n" \
515 " + **" BETA "** : rotation around the :math:`-\\vec{y}` direction (0, -1, 0)\n" \
516 " + **" GAMMA "** : rotation around the :math:`\\vec{z}` direction (0, 0, 1)\n" \
517 " + **" DELTA "** : rotation around the :math:`-\\vec{y}` direction (0, -1, 0)\n" \
518 " + **" ETA_A "** : rotation around the :math:`-\\vec{x}` direction (-1, 0, 0)\n"
520 static const char* hkl_geometry_soleil_sixs_med_2_3_axes[] = {BETA, MU, OMEGA, GAMMA, DELTA, ETA_A};
522 static HklGeometry *hkl_geometry_new_soleil_sixs_med_2_3(const HklFactory *factory)
524 HklGeometry *self = hkl_geometry_new(factory, &hkl_geometry_operations_defaults);
525 HklHolder *h;
527 h = hkl_geometry_add_holder(self);
528 hkl_holder_add_rotation(h, BETA, 0, -1, 0, &hkl_unit_angle_deg);
529 hkl_holder_add_rotation(h, MU, 0, 0, 1, &hkl_unit_angle_deg);
530 hkl_holder_add_rotation(h, OMEGA, 0, -1, 0, &hkl_unit_angle_deg);
532 h = hkl_geometry_add_holder(self);
533 hkl_holder_add_rotation(h, BETA, 0, -1, 0, &hkl_unit_angle_deg);
534 hkl_holder_add_rotation(h, GAMMA, 0, 0, 1, &hkl_unit_angle_deg);
535 hkl_holder_add_rotation(h, DELTA, 0, -1, 0, &hkl_unit_angle_deg);
536 hkl_holder_add_rotation(h, ETA_A, -1, 0, 0, &hkl_unit_angle_deg);
538 return self;
541 static HklEngineList *hkl_engine_list_new_soleil_sixs_med_2_3(const HklFactory *factory)
543 HklEngineList *self = hkl_engine_list_new();
545 self->geometries->multiply = hkl_geometry_list_multiply_soleil_sixs_med_2_3;
546 hkl_engine_soleil_sixs_med_2_3_hkl_new(self);
547 hkl_engine_q2_new(self);
548 hkl_engine_qper_qpar_new(self);
549 hkl_engine_tth2_new(self);
550 hkl_engine_soleil_sixs_med_2_2_incidence_new(self);
551 hkl_engine_soleil_sixs_med_2_2_emergence_new(self);
553 return self;
556 REGISTER_DIFFRACTOMETER(soleil_sixs_med_2_3, "SOLEIL SIXS MED2+3", HKL_GEOMETRY_TYPE_SOLEIL_SIXS_MED_2_3_DESCRIPTION);
559 /**************************/
560 /* SOLEIL SIXS MED 2+3 v2 */
561 /**************************/
563 static HklMode* mu_fixed_2_3_v2()
565 static const char *axes_r[] = {MU, OMEGA, GAMMA, DELTA, ETA_A};
566 static const char* axes_w[] = {OMEGA, GAMMA, DELTA};
567 static const HklFunction *functions[] = {&RUBh_minus_Q_func};
568 static const HklModeAutoInfo info = {
569 HKL_MODE_AUTO_INFO("mu_fixed", axes_r, axes_w, functions),
572 return hkl_mode_auto_new(&info,
573 &hkl_full_mode_operations,
574 TRUE);
577 static HklMode* gamma_fixed_2_3_v2()
579 static const char *axes_r[] = {MU, OMEGA, GAMMA, DELTA, ETA_A};
580 static const char* axes_w[] = {MU, OMEGA, DELTA};
581 static const HklFunction *functions[] = {&RUBh_minus_Q_func};
582 static const HklModeAutoInfo info = {
583 HKL_MODE_AUTO_INFO("gamma_fixed", axes_r, axes_w, functions),
586 return hkl_mode_auto_new(&info,
587 &hkl_full_mode_operations,
588 TRUE);
591 static HklMode *emergence_fixed_2_3_v2()
593 static const char* axes_r[] = {MU, OMEGA, GAMMA, DELTA, ETA_A};
594 static const char* axes_w[] = {MU, OMEGA, GAMMA, DELTA};
595 static const HklFunction* functions[] = {&emergence_fixed_func};
596 static const HklParameter parameters[] = {
597 HKL_MODE_HKL_EMERGENCE_FIXED_PARAMETERS_DEFAULTS(0, 1, 0, 0),
599 static const HklModeAutoInfo info = {
600 HKL_MODE_AUTO_INFO_WITH_PARAMS("emergence_fixed", axes_r, axes_w,
601 functions, parameters),
604 return hkl_mode_hkl_emergence_fixed_new(&info);
608 static HklEngine *hkl_engine_soleil_sixs_med_2_3_v2_hkl_new(HklEngineList *engines)
610 HklEngine *self;
611 HklMode *default_mode;
613 self = hkl_engine_hkl_new(engines);
615 default_mode = mu_fixed_2_3_v2();
616 hkl_engine_add_mode(self, default_mode);
617 hkl_engine_mode_set(self, default_mode);
619 hkl_engine_add_mode(self, gamma_fixed_2_3_v2());
620 hkl_engine_add_mode(self, emergence_fixed_2_3_v2());
622 return self;
626 #define HKL_GEOMETRY_TYPE_SOLEIL_SIXS_MED_2_3_V2_DESCRIPTION \
627 "+ xrays source fix allong the :math:`\\vec{x}` direction (1, 0, 0)\n" \
628 "+ 2 axes for the sample\n" \
629 "\n" \
630 " + **" MU "** : rotation around the :math:`\\vec{z}` direction (0, 0, 1)\n" \
631 " + **" OMEGA "** : rotating around the :math:`-\\vec{y}` direction (0, -1, 0)\n" \
632 "\n" \
633 "+ 3 axis for the detector\n" \
634 "\n" \
635 " + **" GAMMA "** : rotation around the :math:`\\vec{z}` direction (0, 0, 1)\n" \
636 " + **" DELTA "** : rotation around the :math:`-\\vec{y}` direction (0, -1, 0)\n" \
637 " + **" ETA_A "** : rotation around the :math:`-\\vec{x}` direction (-1, 0, 0)\n"
639 static const char* hkl_geometry_soleil_sixs_med_2_3_v2_axes[] = {MU, OMEGA, GAMMA, DELTA, ETA_A};
641 static HklGeometry *hkl_geometry_new_soleil_sixs_med_2_3_v2(const HklFactory *factory)
643 HklGeometry *self = hkl_geometry_new(factory, &hkl_geometry_operations_defaults);
644 HklHolder *h;
646 h = hkl_geometry_add_holder(self);
647 hkl_holder_add_rotation(h, MU, 0, 0, 1, &hkl_unit_angle_deg);
648 hkl_holder_add_rotation(h, OMEGA, 0, -1, 0, &hkl_unit_angle_deg);
650 h = hkl_geometry_add_holder(self);
651 hkl_holder_add_rotation(h, GAMMA, 0, 0, 1, &hkl_unit_angle_deg);
652 hkl_holder_add_rotation(h, DELTA, 0, -1, 0, &hkl_unit_angle_deg);
653 hkl_holder_add_rotation(h, ETA_A, -1, 0, 0, &hkl_unit_angle_deg);
655 return self;
658 static inline int hkl_engine_list_post_engine_set_med_2_3_v2_real(HklEngineList *self)
660 int res = TRUE;
661 int eta_a_rotation = darray_item(self->parameters, 0)->_value;
663 if(!self || !self->geometries)
664 goto out;
666 if(eta_a_rotation == 1){
667 uint i = 0;
668 uint len = self->geometries->n_items;
669 HklGeometryListItem *item;
672 * warning this method change the self->len so we need to save it
673 * before using the recursive perm_r calls
675 for(i=0, item=list_top(&self->geometries->items, HklGeometryListItem, list);
676 i<len && NULL != item;
677 ++i, item=list_next(&self->geometries->items, item, list))
678 hkl_geometry_list_multiply_soleil_sixs_med_2_3(self->geometries, item);
680 out:
681 return res;
684 static HklEngineList *hkl_engine_list_new_soleil_sixs_med_2_3_v2(const HklFactory *factory)
686 static const HklParameter eta_a_rotation = {
687 HKL_PARAMETER_DEFAULTS, .name = "eta_a_rotation",
688 ._value = 0,
689 .description = "rotation of the detector (zaxis-like)",
690 .range = { .min=0, .max=1 },
692 static const HklParameter *parameters[] = { &eta_a_rotation };
693 static const HklEngineListInfo info = {HKL_ENGINE_LIST_INFO(parameters)};
694 static const HklEngineListOperations ops = {
695 HKL_ENGINE_LIST_OPERATIONS_DEFAULTS,
696 .post_engine_set=hkl_engine_list_post_engine_set_med_2_3_v2_real,
698 HklEngineList *self = hkl_engine_list_new_with_info(&info, &ops);
700 hkl_engine_soleil_sixs_med_2_3_v2_hkl_new(self);
701 hkl_engine_q2_new(self);
702 hkl_engine_qper_qpar_new(self);
703 hkl_engine_tth2_new(self);
704 hkl_engine_soleil_sixs_med_2_2_incidence_new(self);
705 hkl_engine_soleil_sixs_med_2_2_emergence_new(self);
707 return self;
710 REGISTER_DIFFRACTOMETER(soleil_sixs_med_2_3_v2, "SOLEIL SIXS MED2+3 v2", HKL_GEOMETRY_TYPE_SOLEIL_SIXS_MED_2_3_V2_DESCRIPTION);