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-2015 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"
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
;
57 static const HklFunction reflectivity_func
= {
58 .function
= _reflectivity_func
,
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
,
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
,
90 static HklEngine
*hkl_engine_soleil_sixs_med_2_2_hkl_new(HklEngineList
*engines
)
93 HklMode
*default_mode
;
95 self
= hkl_engine_hkl_new(engines
);
97 default_mode
= mu_fixed_2_2();
98 hkl_engine_add_mode(self
, default_mode
);
99 hkl_engine_mode_set(self
, default_mode
);
101 hkl_engine_add_mode(self
, reflectivity_2_2());
108 REGISTER_READONLY_INCIDENCE(hkl_engine_soleil_sixs_med_2_2_incidence_new
,
109 P99_PROTECT({BETA
, MU
, OMEGA
}));
111 /*********************/
112 /* MED 1+2 HklEngine */
113 /*********************/
115 static HklMode
* pitch_fixed()
117 static const char *axes_r
[] = {PITCH
, MU
, GAMMA
, DELTA
};
118 static const char* axes_w
[] = {MU
, GAMMA
, DELTA
};
119 static const HklFunction
*functions
[] = {&RUBh_minus_Q_func
};
120 static const HklModeAutoInfo info
= {
121 HKL_MODE_AUTO_INFO(__func__
, axes_r
, axes_w
, functions
),
124 return hkl_mode_auto_new(&info
,
125 &hkl_full_mode_operations
,
129 static HklEngine
*hkl_engine_soleil_sixs_med_1_2_hkl_new(HklEngineList
*engines
)
132 HklMode
*default_mode
;
134 self
= hkl_engine_hkl_new(engines
);
136 default_mode
= pitch_fixed();
137 hkl_engine_add_mode(self
, default_mode
);
138 hkl_engine_mode_set(self
, default_mode
);
145 REGISTER_READONLY_INCIDENCE(hkl_engine_soleil_sixs_med_1_2_incidence_new
,
146 P99_PROTECT({PITCH
, MU
}));
148 /*********************/
149 /* MED 2+3 HklEngine */
150 /*********************/
152 typedef struct _HklSlitsFit HklSlitsFit
;
155 HklGeometry
*geometry
;
157 unsigned int slits_id
;
162 static int slits_func(const gsl_vector
*x
, void *params
, gsl_vector
*f
)
164 double const *x_data
= gsl_vector_const_ptr(x
, 0);
165 double *f_data
= gsl_vector_ptr(f
, 0);
166 HklVector n_slits
= {{0, 0, 1}};
167 HklSlitsFit
*parameters
= params
;
169 hkl_parameter_value_set(parameters
->axis
, x_data
[0], HKL_UNIT_DEFAULT
, NULL
);
170 hkl_geometry_update(parameters
->geometry
);
172 /* compute the orientation of the slits */
173 hkl_vector_rotated_quaternion(&n_slits
,
174 &darray_item(parameters
->geometry
->holders
, 1)->q
);
176 /* both directions must be perpendicular */
177 f_data
[0] = hkl_vector_scalar_product(¶meters
->surface
, &n_slits
);
182 static int fit_slits_orientation(HklSlitsFit
*params
)
185 gsl_multiroot_fsolver_type
const *T
;
186 gsl_multiroot_fsolver
*s
;
187 gsl_multiroot_function f
;
194 /* now solve the system */
195 /* Initialize method */
196 T
= gsl_multiroot_fsolver_hybrid
;
197 s
= gsl_multiroot_fsolver_alloc (T
, params
->len
);
198 x
= gsl_vector_alloc(params
->len
);
199 x_data
= gsl_vector_ptr(x
, 0);
201 /* initialize x with the right values */
202 x_data
[0] = params
->axis
->_value
;
207 gsl_multiroot_fsolver_set (s
, &f
, x
);
209 /* iterate to find the solution */
213 status
= gsl_multiroot_fsolver_iterate(s
);
214 if (status
|| iter
% 100 == 0) {
215 /* Restart from another point. */
216 for(i
=0; i
<params
->len
; ++i
)
217 x_data
[i
] = (double)rand() / RAND_MAX
* 180. / M_PI
;
218 gsl_multiroot_fsolver_set(s
, &f
, x
);
219 gsl_multiroot_fsolver_iterate(s
);
221 status
= gsl_multiroot_test_residual (s
->f
, HKL_EPSILON
);
222 } while (status
== GSL_CONTINUE
&& iter
< 1000);
225 fprintf(stdout
, "\n fitting the detector position using thoses axes :");
226 for(i
=0; i
<params
->len
; ++i
)
227 fprintf(stdout
, " \"%s\"", params
->axis
->name
);
228 fprintf(stdout
, " status : %d iter : %d", status
, iter
);
229 fprintf(stdout
, " x: [");
230 for(i
=0; i
<params
->len
; ++i
)
231 fprintf(stdout
, " %.7f", s
->x
->data
[i
]);
232 fprintf(stdout
, "] f: [");
233 for(i
=0; i
<params
->len
; ++i
)
234 fprintf(stdout
, " %.7f", s
->f
->data
[i
]);
235 fprintf(stdout
, "]\n");
236 hkl_geometry_fprintf(stdout
, params
->geometry
);
238 if(status
!= GSL_CONTINUE
){
240 /* put the axes in the -pi, pi range. */
241 gsl_sf_angle_restrict_pos_e(¶ms
->axis
->_value
);
245 gsl_multiroot_fsolver_free(s
);
250 static void hkl_geometry_list_multiply_soleil_sixs_med_2_3(HklGeometryList
*self
,
251 HklGeometryListItem
*item
)
254 HklGeometry
*geometry
;
255 double slits_position
;
256 HklHolder
*sample_holder
;
257 HklHolder
*detector_holder
;
259 /* For each solution already found we will generate another one */
260 /* we will set the right slit orientation for a given detector arm position */
261 geometry
= item
->geometry
;
262 sample_holder
= darray_item(geometry
->holders
, 0);
263 detector_holder
= darray_item(geometry
->holders
, 1);
265 /* get the index of the axis corresponding to the slits */
266 /* for now the last holder is the detector one */
267 params
.slits_id
= detector_holder
->config
->idx
[detector_holder
->config
->len
-1];
268 params
.len
= 1; /* only one axis to fit */
269 params
.geometry
= geometry
;
270 params
.axis
= darray_item(params
.geometry
->axes
, params
.slits_id
);
272 /* compute the surface orientation fixed during the fit */
273 /* use the last sample axis as sample surface normal */
274 params
.surface
= container_of(darray_item(geometry
->axes
,
275 sample_holder
->config
->idx
[sample_holder
->config
->len
- 1]),
276 HklAxis
, parameter
)->axis_v
;
277 hkl_vector_rotated_quaternion(¶ms
.surface
,
281 /* we just need to fit the slits orientation */
282 /* save it's value before */
283 slits_position
= hkl_parameter_value_get(params
.axis
, HKL_UNIT_DEFAULT
);
284 if (fit_slits_orientation(¶ms
) != TRUE
)
285 hkl_parameter_value_set(params
.axis
, slits_position
, HKL_UNIT_DEFAULT
, NULL
);
288 static HklMode
* mu_fixed_2_3()
290 static const char *axes_r
[] = {BETA
, MU
, OMEGA
, GAMMA
, DELTA
, ETA_A
};
291 static const char* axes_w
[] = {OMEGA
, GAMMA
, DELTA
};
292 static const HklFunction
*functions
[] = {&RUBh_minus_Q_func
};
293 static const HklModeAutoInfo info
= {
294 HKL_MODE_AUTO_INFO("mu_fixed", axes_r
, axes_w
, functions
),
297 return hkl_mode_auto_new(&info
,
298 &hkl_full_mode_operations
,
302 static HklEngine
*hkl_engine_soleil_sixs_med_2_3_hkl_new(HklEngineList
*engines
)
305 HklMode
*default_mode
;
307 self
= hkl_engine_hkl_new(engines
);
309 default_mode
= mu_fixed_2_3();
310 hkl_engine_add_mode(self
, default_mode
);
311 hkl_engine_mode_set(self
, default_mode
);
316 /***********************/
317 /* SOLEIL SIXS MED 2+2 */
318 /***********************/
320 #define HKL_GEOMETRY_TYPE_SOLEIL_SIXS_MED_2_2_DESCRIPTION \
321 "+ xrays source fix allong the :math:`\\vec{x}` direction (1, 0, 0)\n" \
322 "+ 3 axes for the sample\n" \
324 " + **" BETA "** : rotation around the :math:`-\\vec{y}` direction (0, -1, 0)\n" \
325 " + **" MU "** : rotation around the :math:`\\vec{z}` direction (0, 0, 1)\n" \
326 " + **" OMEGA "** : rotating around the :math:`-\\vec{y}` direction (0, -1, 0)\n" \
328 "+ 3 axis for the detector\n" \
330 " + **" BETA "** : rotation around the :math:`-\\vec{y}` direction (0, -1, 0)\n" \
331 " + **" GAMMA "** : rotation around the :math:`\\vec{z}` direction (0, 0, 1)\n" \
332 " + **" DELTA "** : rotation around the :math:`-\\vec{y}` direction (0, -1, 0)\n"
334 static const char* hkl_geometry_soleil_sixs_med_2_2_axes
[] = {BETA
, MU
, OMEGA
, GAMMA
, DELTA
};
336 static HklGeometry
*hkl_geometry_new_soleil_sixs_med_2_2(const HklFactory
*factory
)
338 HklGeometry
*self
= hkl_geometry_new(factory
);
341 h
= hkl_geometry_add_holder(self
);
342 hkl_holder_add_rotation_axis(h
, BETA
, 0, -1, 0);
343 hkl_holder_add_rotation_axis(h
, MU
, 0, 0, 1);
344 hkl_holder_add_rotation_axis(h
, OMEGA
, 0, -1, 0);
346 h
= hkl_geometry_add_holder(self
);
347 hkl_holder_add_rotation_axis(h
, BETA
, 0, -1, 0);
348 hkl_holder_add_rotation_axis(h
, GAMMA
, 0, 0, 1);
349 hkl_holder_add_rotation_axis(h
, DELTA
, 0, -1, 0);
354 static HklEngineList
*hkl_engine_list_new_soleil_sixs_med_2_2(const HklFactory
*factory
)
356 HklEngineList
*self
= hkl_engine_list_new();
358 hkl_engine_soleil_sixs_med_2_2_hkl_new(self
);
359 hkl_engine_q2_new(self
);
360 hkl_engine_qper_qpar_new(self
);
361 hkl_engine_tth2_new(self
);
362 hkl_engine_soleil_sixs_med_2_2_incidence_new(self
);
367 REGISTER_DIFFRACTOMETER(soleil_sixs_med_2_2
,"SOLEIL SIXS MED2+2", HKL_GEOMETRY_TYPE_SOLEIL_SIXS_MED_2_2_DESCRIPTION
);
369 /***********************/
370 /* SOLEIL SIXS MED 1+2 */
371 /***********************/
373 #define HKL_GEOMETRY_TYPE_SOLEIL_SIXS_MED_1_2_DESCRIPTION \
374 "+ xrays source fix allong the :math:`\\vec{x}` direction (1, 0, 0)\n" \
375 "+ 2 axes for the sample\n" \
377 " + **" PITCH "** : rotation around the :math:`-\\vec{y}` direction (0, -1, 0)\n" \
378 " + **" MU "** : rotation around the :math:`\\vec{z}` direction (0, 0, 1)\n" \
380 "+ 3 axis for the detector\n" \
382 " + **" PITCH "** : rotation around the :math:`-\\vec{y}` direction (0, -1, 0)\n" \
383 " + **" GAMMA "** : rotation around the :math:`\\vec{z}` direction (0, 0, 1)\n" \
384 " + **" DELTA "** : rotation around the :math:`-\\vec{y}` direction (0, -1, 0)\n"
386 static const char* hkl_geometry_soleil_sixs_med_1_2_axes
[] = {PITCH
, MU
, GAMMA
, DELTA
};
388 static HklGeometry
*hkl_geometry_new_soleil_sixs_med_1_2(const HklFactory
*factory
)
390 HklGeometry
*self
= hkl_geometry_new(factory
);
393 h
= hkl_geometry_add_holder(self
);
394 hkl_holder_add_rotation_axis(h
, PITCH
, 0, -1, 0);
395 hkl_holder_add_rotation_axis(h
, MU
, 0, 0, 1);
397 h
= hkl_geometry_add_holder(self
);
398 hkl_holder_add_rotation_axis(h
, PITCH
, 0, -1, 0);
399 hkl_holder_add_rotation_axis(h
, GAMMA
, 0, 0, 1);
400 hkl_holder_add_rotation_axis(h
, DELTA
, 0, -1, 0);
405 static HklEngineList
*hkl_engine_list_new_soleil_sixs_med_1_2(const HklFactory
*factory
)
407 HklEngineList
*self
= hkl_engine_list_new();
409 hkl_engine_soleil_sixs_med_1_2_hkl_new(self
);
410 hkl_engine_q2_new(self
);
411 hkl_engine_qper_qpar_new(self
);
412 hkl_engine_tth2_new(self
);
413 hkl_engine_soleil_sixs_med_1_2_incidence_new(self
);
418 REGISTER_DIFFRACTOMETER(soleil_sixs_med_1_2
, "SOLEIL SIXS MED1+2", HKL_GEOMETRY_TYPE_SOLEIL_SIXS_MED_1_2_DESCRIPTION
);
421 /***********************/
422 /* SOLEIL SIXS MED 2+3 */
423 /***********************/
425 #define HKL_GEOMETRY_TYPE_SOLEIL_SIXS_MED_2_3_DESCRIPTION \
426 "+ xrays source fix allong the :math:`\\vec{x}` direction (1, 0, 0)\n" \
427 "+ 3 axes for the sample\n" \
429 " + **" BETA "** : rotation around the :math:`-\\vec{y}` direction (0, -1, 0)\n" \
430 " + **" MU "** : rotation around the :math:`\\vec{z}` direction (0, 0, 1)\n" \
431 " + **" OMEGA "** : rotating around the :math:`-\\vec{y}` direction (0, -1, 0)\n" \
433 "+ 4 axis for the detector\n" \
435 " + **" BETA "** : rotation around the :math:`-\\vec{y}` direction (0, -1, 0)\n" \
436 " + **" GAMMA "** : rotation around the :math:`\\vec{z}` direction (0, 0, 1)\n" \
437 " + **" DELTA "** : rotation around the :math:`-\\vec{y}` direction (0, -1, 0)\n" \
438 " + **" ETA_A "** : rotation around the :math:`-\\vec{x}` direction (-1, 0, 0)\n"
440 static const char* hkl_geometry_soleil_sixs_med_2_3_axes
[] = {BETA
, MU
, OMEGA
, GAMMA
, DELTA
, ETA_A
};
442 static HklGeometry
*hkl_geometry_new_soleil_sixs_med_2_3(const HklFactory
*factory
)
444 HklGeometry
*self
= hkl_geometry_new(factory
);
447 h
= hkl_geometry_add_holder(self
);
448 hkl_holder_add_rotation_axis(h
, BETA
, 0, -1, 0);
449 hkl_holder_add_rotation_axis(h
, MU
, 0, 0, 1);
450 hkl_holder_add_rotation_axis(h
, OMEGA
, 0, -1, 0);
452 h
= hkl_geometry_add_holder(self
);
453 hkl_holder_add_rotation_axis(h
, BETA
, 0, -1, 0);
454 hkl_holder_add_rotation_axis(h
, GAMMA
, 0, 0, 1);
455 hkl_holder_add_rotation_axis(h
, DELTA
, 0, -1, 0);
456 hkl_holder_add_rotation_axis(h
, ETA_A
, -1, 0, 0);
461 static HklEngineList
*hkl_engine_list_new_soleil_sixs_med_2_3(const HklFactory
*factory
)
463 HklEngineList
*self
= hkl_engine_list_new();
465 self
->geometries
->multiply
= hkl_geometry_list_multiply_soleil_sixs_med_2_3
;
466 hkl_engine_soleil_sixs_med_2_3_hkl_new(self
);
467 hkl_engine_q2_new(self
);
468 hkl_engine_qper_qpar_new(self
);
469 hkl_engine_tth2_new(self
);
470 hkl_engine_soleil_sixs_med_2_2_incidence_new(self
);
475 REGISTER_DIFFRACTOMETER(soleil_sixs_med_2_3
, "SOLEIL SIXS MED2+3", HKL_GEOMETRY_TYPE_SOLEIL_SIXS_MED_2_3_DESCRIPTION
);