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-2017 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>
21 * Maria-Teresa Nunez-Pardo-de-Verra <tnunez@mail.desy.de>
23 #include <gsl/gsl_errno.h> // for ::GSL_SUCCESS, etc
24 #include <gsl/gsl_multiroots.h>
25 #include <gsl/gsl_sf_trig.h> // for gsl_sf_angle_restrict_pos
26 #include <gsl/gsl_vector_double.h> // for gsl_vector, etc
27 #include <math.h> // for fabs, M_PI
28 #include <stddef.h> // for size_t
29 #include <stdlib.h> // for free, malloc, rand, etc
30 #include <string.h> // for NULL
31 #include <sys/types.h> // for uint
32 #include "hkl-axis-private.h" // for HklAxis
33 #include "hkl-detector-private.h" // for hkl_detector_compute_kf
34 #include "hkl-geometry-private.h" // for HklHolder, _HklGeometry, etc
35 #include "hkl-macros-private.h" // for hkl_assert, HKL_MALLOC, etc
36 #include "hkl-matrix-private.h" // for hkl_matrix_times_vector, etc
37 #include "hkl-parameter-private.h" // for _HklParameter, etc
38 #include "hkl-pseudoaxis-auto-private.h" // for CHECK_NAN, etc
39 #include "hkl-pseudoaxis-common-hkl-private.h" // for HklEngineHkl
40 #include "hkl-pseudoaxis-common-q-private.h" // for HklEngineHkl
41 #include "hkl-pseudoaxis-private.h" // for _HklEngine, _HklMode, etc
42 #include "hkl-quaternion-private.h" // for hkl_quaternion_init, etc
43 #include "hkl-sample-private.h" // for _HklSample
44 #include "hkl-source-private.h" // for hkl_source_compute_ki
45 #include "hkl-vector-private.h" // for HklVector, etc
46 #include "hkl.h" // for HklEngine, HklGeometry, etc
47 #include "hkl/ccan/array_size/array_size.h" // for ARRAY_SIZE
48 #include "hkl/ccan/container_of/container_of.h" // for container_of
49 #include "hkl/ccan/darray/darray.h" // for darray_item, darray_size
53 /*******************************************/
54 /* common methode use by hkl getter/setter */
55 /*******************************************/
57 typedef struct _HklDetectorFit HklDetectorFit
;
59 struct _HklDetectorFit
61 HklGeometry
*geometry
;
62 HklDetector
*detector
;
68 /* this method is used to fit only the detector position */
69 /* usable with only 1 or 2 axes */
70 static int fit_detector_function(const gsl_vector
*x
, void *params
, gsl_vector
*f
)
73 HklDetectorFit
*fitp
= params
;
76 /* update the workspace from x; */
77 for(i
=0; i
<fitp
->len
; ++i
)
78 hkl_parameter_value_set(fitp
->axes
[i
],
80 HKL_UNIT_DEFAULT
, NULL
);
82 hkl_geometry_update(fitp
->geometry
);
84 hkl_detector_compute_kf(fitp
->detector
, fitp
->geometry
, &kf
);
86 f
->data
[0] = fabs(fitp
->kf0
->data
[0] - kf
.data
[0])
87 + fabs(fitp
->kf0
->data
[1] - kf
.data
[1])
88 + fabs(fitp
->kf0
->data
[2] - kf
.data
[2]);
90 f
->data
[1] = fabs(fitp
->kf0
->data
[1] - kf
.data
[1]);
93 fprintf(stdout
, "\nkf0 [%f, %f, %f], kf [%f, %f, %f]",
94 fitp
->kf0
->data
[0], fitp
->kf0
->data
[1], fitp
->kf0
->data
[2],
95 kf
.data
[0], kf
.data
[1], kf
.data
[2]);
96 fprintf(stdout
, " x : [");
97 for(i
=0; i
<fitp
->len
; ++i
)
98 fprintf(stdout
, " %.7f", x_data
[i
]);
99 fprintf(stdout
, "] | f : [");
100 for(i
=0; i
<fitp
->len
; ++i
)
101 fprintf(stdout
, " %.7f", f_data
[i
]);
102 fprintf(stdout
, "]\n");
108 static int fit_detector_position(HklMode
*mode
,
109 HklGeometry
*geometry
,
110 HklDetector
*detector
,
111 const HklSample
*sample
,
114 const char **axis_name
;
115 HklDetectorFit params
;
116 gsl_multiroot_fsolver_type
const *T
;
117 gsl_multiroot_fsolver
*s
;
118 gsl_multiroot_function f
;
123 const HklHolder
*sample_holder
= hkl_geometry_sample_holder_get(geometry
, sample
);
124 const HklHolder
*detector_holder
= hkl_geometry_detector_holder_get(geometry
, detector
);
126 /* fit the detector part to find the position of the detector for a given kf */
127 /* FIXME for now the sample and detector holder are respectively the first and the second one */
128 /* we need to find the right axes to use for the fit */
129 /* BECARFULL the sample part must not move during this fit. So exclude an axis */
130 /* if it is also part of the sample holder. */
131 /* For now compare the holder axes with the axes of the mode to generate the right gsl multiroot solver */
132 params
.geometry
= geometry
;
133 params
.detector
= detector
;
135 params
.axes
= malloc(sizeof(*params
.axes
) * detector_holder
->config
->len
);
137 /* for each axis of the mode */
138 darray_foreach(axis_name
, mode
->info
->axes_w
){
142 tmp
= hkl_geometry_get_axis_idx_by_name(params
.geometry
, *axis_name
);
143 /* check that this axis is in the detector's holder */
144 for(k
=0; k
<detector_holder
->config
->len
; ++k
)
145 if(tmp
== detector_holder
->config
->idx
[k
]){
149 /* and not in the sample's holder */
150 for(j
=0; j
<sample_holder
->config
->len
; ++j
){
151 if (tmp
== sample_holder
->config
->idx
[j
]){
157 params
.axes
[params
.len
++] = darray_item(params
.geometry
->axes
, tmp
);
161 /* if no detector axis found ???? abort */
162 /* maybe put this at the begining of the method */
166 /* now solve the system */
167 /* Initialize method */
168 T
= gsl_multiroot_fsolver_hybrid
;
169 s
= gsl_multiroot_fsolver_alloc (T
, params
.len
);
170 x
= gsl_vector_alloc(params
.len
);
172 /* initialize x with the right values */
173 for(i
=0; i
<params
.len
; ++i
)
174 x
->data
[i
] = hkl_parameter_value_get(params
.axes
[i
], HKL_UNIT_DEFAULT
);
176 f
.f
= fit_detector_function
;
179 gsl_multiroot_fsolver_set (s
, &f
, x
);
181 /* iterate to find the solution */
185 status
= gsl_multiroot_fsolver_iterate(s
);
186 if (status
|| iter
% 100 == 0) {
187 /* Restart from another point. */
188 for(i
=0; i
<params
.len
; ++i
)
189 x
->data
[i
] = (double)rand() / RAND_MAX
* 180. / M_PI
;
190 gsl_multiroot_fsolver_set(s
, &f
, x
);
191 gsl_multiroot_fsolver_iterate(s
);
193 status
= gsl_multiroot_test_residual (s
->f
, HKL_EPSILON
);
194 } while (status
== GSL_CONTINUE
&& iter
< 1000);
197 fprintf(stdout
, "\n fitting the detector position using thoses axes :");
198 for(i
=0; i
<params
.len
; ++i
)
199 fprintf(stdout
, " \"%s\"", ((HklParameter
*)params
.axes
[i
])->name
);
200 fprintf(stdout
, " status : %d iter : %d", status
, iter
);
201 fprintf(stdout
, " x: [");
202 for(i
=0; i
<params
.len
; ++i
)
203 fprintf(stdout
, " %.7f", s
->x
->data
[i
]);
204 fprintf(stdout
, "] f: [");
205 for(i
=0; i
<params
.len
; ++i
)
206 fprintf(stdout
, " %.7f", s
->f
->data
[i
]);
207 fprintf(stdout
, "]\n");
208 hkl_geometry_fprintf(stdout
, params
.geometry
);
210 if(status
!= GSL_CONTINUE
){
212 /* put the axes in the -pi, pi range. */
213 for(i
=0; i
<params
.len
; ++i
){
216 value
= hkl_parameter_value_get(params
.axes
[i
], HKL_UNIT_DEFAULT
);
217 /* TODO one day deal with the error for real */
218 hkl_parameter_value_set(params
.axes
[i
],
219 gsl_sf_angle_restrict_pos(value
),
220 HKL_UNIT_DEFAULT
, NULL
);
225 gsl_multiroot_fsolver_free(s
);
232 /* get the highest index of the axis in a holder */
233 /* BEWARE, NOT the axis index in the geometry->axes */
234 /* which is part of the axis_names of the mode */
235 /* return -1 if there is no axes of the mode in the sample part of the geometry */
236 static int get_last_sample_axis_idx(HklGeometry
*geometry
, const HklSample
*sample
,
237 const darray_string
*axes
)
240 const char **axis_name
;
241 HklHolder
*sample_holder
= hkl_geometry_sample_holder_get(geometry
, sample
);
243 darray_foreach(axis_name
, *axes
){
247 /* FIXME for now the sample holder is the first one */
248 idx
= hkl_geometry_get_axis_idx_by_name(geometry
, *axis_name
);
249 for(i
=0; i
<sample_holder
->config
->len
; ++i
)
250 if(idx
== sample_holder
->config
->idx
[i
]){
251 last
= last
> (int)i
? last
: (int)i
;
259 int hkl_is_reachable(HklEngine
*engine
, double wavelength
, GError
**error
)
261 HklEngineHkl
*engine_hkl
= container_of(engine
, HklEngineHkl
, engine
);
264 engine_hkl
->h
->_value
,
265 engine_hkl
->k
->_value
,
266 engine_hkl
->l
->_value
,
270 hkl_matrix_times_vector(&engine
->sample
->UB
, &Hkl
);
271 if (hkl_vector_norm2(&Hkl
) > qmax(wavelength
)){
274 HKL_ENGINE_ERROR_SET
,
275 "unreachable hkl, try to change the wavelength");
283 * _RUBh_minus_Q_func: (skip)
288 * Only usefull if you need to create a new hkl mode.
292 int _RUBh_minus_Q_func(const gsl_vector
*x
, void *params
, gsl_vector
*f
)
294 CHECK_NAN(x
->data
, x
->size
);
296 return RUBh_minus_Q(x
->data
, params
, f
->data
);
300 * RUBh_minus_Q: (skip)
309 int RUBh_minus_Q(double const x
[], void *params
, double f
[])
311 HklEngine
*engine
= params
;
312 HklEngineHkl
*engine_hkl
= container_of(engine
, HklEngineHkl
, engine
);
315 engine_hkl
->h
->_value
,
316 engine_hkl
->k
->_value
,
317 engine_hkl
->l
->_value
,
321 HklHolder
*sample_holder
= hkl_geometry_sample_holder_get(engine
->geometry
,
324 /* update the workspace from x; */
325 set_geometry_axes(engine
, x
);
328 /* for now the 0 holder is the sample holder. */
329 hkl_matrix_times_vector(&engine
->sample
->UB
, &Hkl
);
330 /* Hkl = hkl_holder_transformation_apply(sample_holder, &Hkl); */
331 hkl_vector_rotated_quaternion(&Hkl
, &sample_holder
->q
);
334 hkl_source_compute_ki(&engine
->geometry
->source
, &ki
);
335 hkl_detector_compute_kf(engine
->detector
, engine
->geometry
, &dQ
);
336 hkl_vector_minus_vector(&dQ
, &ki
);
338 hkl_vector_minus_vector(&dQ
, &Hkl
);
347 int hkl_mode_get_hkl_real(HklMode
*self
,
349 HklGeometry
*geometry
,
350 HklDetector
*detector
,
355 HklVector hkl
, ki
, Q
;
356 HklEngineHkl
*engine_hkl
= container_of(engine
, HklEngineHkl
, engine
);
357 HklHolder
*sample_holder
= hkl_geometry_sample_holder_get(geometry
, sample
);
359 /* update the geometry internals */
360 hkl_geometry_update(geometry
);
363 hkl_quaternion_to_matrix(&sample_holder
->q
, &RUB
);
364 hkl_matrix_times_matrix(&RUB
, &sample
->UB
);
367 hkl_source_compute_ki(&geometry
->source
, &ki
);
368 hkl_detector_compute_kf(detector
, geometry
, &Q
);
369 hkl_vector_minus_vector(&Q
, &ki
);
371 hkl_matrix_solve(&RUB
, &hkl
, &Q
);
373 engine_hkl
->h
->_value
= hkl
.data
[0];
374 engine_hkl
->k
->_value
= hkl
.data
[1];
375 engine_hkl
->l
->_value
= hkl
.data
[2];
380 int hkl_mode_set_hkl_real(HklMode
*self
,
382 HklGeometry
*geometry
,
383 HklDetector
*detector
,
389 hkl_error (error
== NULL
|| *error
== NULL
);
391 /* check the input parameters */
392 if(!hkl_is_reachable(engine
, geometry
->source
.wave_length
,
394 hkl_assert(error
== NULL
|| *error
!= NULL
);
397 hkl_assert(error
== NULL
|| *error
== NULL
);
399 /* compute the mode */
400 if(!hkl_mode_auto_set_real(self
, engine
,
401 geometry
, detector
, sample
,
403 hkl_assert(error
== NULL
|| *error
!= NULL
);
404 //fprintf(stdout, "message :%s\n", (*error)->message);
407 hkl_assert(error
== NULL
|| *error
== NULL
);
409 /* check that the mode allow to move a sample axis */
410 /* FIXME for now the sample holder is the first one */
411 last_axis
= get_last_sample_axis_idx(geometry
, sample
, &self
->info
->axes_w
);
414 const HklGeometryListItem
*item
;
415 uint len
= engine
->engines
->geometries
->n_items
;
417 /* For each solution already found we will generate another one */
418 /* using the Ewalds construction by rotating Q around the last sample */
419 /* axis of the mode until it intersect again the Ewald sphere. */
420 /* FIXME do not work if ki is colinear with the axis. */
422 /* for this we needs : */
423 /* - the coordinates of the end of the Q vector (q) */
424 /* - the last sample axis orientation of the mode (axis_v) */
425 /* - the coordinates of the center of the ewalds sphere (c) */
426 /* - the coordinates of the center of rotation of the sample (o = 0, 0, 0) */
429 /* - project the origin in plane of normal axis_v containing q (o') */
430 /* - project the center of the ewalds sphere into the same plan (c') */
431 /* - rotate q around this (o', c') line of 180° to find the (q2) solution */
432 /* - compute the (kf2) corresponding to this q2 solution */
433 /* at the end we just need to solve numerically the position of the detector */
435 /* we will add solution to the geometries so save its length before */
436 for(i
=0, item
=list_top(&engine
->engines
->geometries
->items
, HklGeometryListItem
, list
);
438 ++i
, item
=list_next(&engine
->engines
->geometries
->items
, item
, list
)){
446 HklVector cp
= {{0}};
447 HklVector op
= {{0}};
449 HklGeometry
*geom
= hkl_geometry_new_copy(item
->geometry
);
450 HklHolder
*sample_holder
= hkl_geometry_sample_holder_get(geom
, sample
);
452 geom
= hkl_geometry_new_copy(item
->geometry
);
454 /* get the Q vector kf - ki */
455 hkl_detector_compute_kf(detector
, geom
, &q
);
456 hkl_source_compute_ki(&geom
->source
, &ki
);
457 hkl_vector_minus_vector(&q
, &ki
);
459 /* compute the current orientation of the last axis */
460 axis
= container_of(darray_item(geom
->axes
,
461 sample_holder
->config
->idx
[last_axis
]),
463 axis_v
= axis
->axis_v
;
464 hkl_quaternion_init(&qr
, 1, 0, 0, 0);
465 for(j
=0; j
<last_axis
; ++j
)
466 hkl_quaternion_times_quaternion(
468 &container_of(darray_item(geom
->axes
,
469 sample_holder
->config
->idx
[j
]),
470 HklAxis
, parameter
)->q
);
471 hkl_vector_rotated_quaternion(&axis_v
, &qr
);
473 /* - project the center of the ewalds sphere into the same plan (c') */
474 hkl_vector_minus_vector(&cp
, &ki
);
475 hkl_vector_project_on_plan_with_point(&cp
, &axis_v
, &q
);
476 hkl_vector_project_on_plan_with_point(&op
, &axis_v
, &q
);
478 /* - rotate q around this (o', c') line of 180° to find the (q2) solution */
480 hkl_vector_rotated_around_line(&kf2
, M_PI
, &cp
, &op
);
481 angle
= hkl_vector_oriented_angle_points(&q
, &op
, &kf2
, &axis_v
);
482 /* TODO parameter list for geometry */
483 if(!hkl_parameter_value_set(&axis
->parameter
,
484 hkl_parameter_value_get(&axis
->parameter
, HKL_UNIT_DEFAULT
) + angle
,
485 HKL_UNIT_DEFAULT
, error
))
487 hkl_geometry_update(geom
);
489 fprintf(stdout
, "\n- try to add a solution by rotating Q <%f, %f, %f> around the \"%s\" axis <%f, %f, %f> of %f radian",
490 q
.data
[0], q
.data
[1], q
.data
[2],
491 ((HklParameter
*)axis
)->name
,
492 axis_v
.data
[0], axis_v
.data
[1], axis_v
.data
[2],
494 fprintf(stdout
, "\n op: <%f, %f, %f>", op
.data
[0], op
.data
[1], op
.data
[2]);
495 fprintf(stdout
, "\n q2: <%f, %f, %f>", kf2
.data
[0], kf2
.data
[1], kf2
.data
[2]);
497 hkl_vector_add_vector(&kf2
, &ki
);
499 /* at the end we just need to solve numerically the position of the detector */
500 if(fit_detector_position(self
, geom
, detector
, sample
, &kf2
))
501 hkl_geometry_list_add(engine
->engines
->geometries
,
504 hkl_geometry_free(geom
);
510 /***************************************/
511 /* the double diffraction get set part */
512 /***************************************/
515 * double_diffraction: (skip)
524 int _double_diffraction(double const x
[], void *params
, double f
[])
526 HklEngine
*engine
= params
;
527 HklEngineHkl
*engine_hkl
= container_of(engine
, HklEngineHkl
, engine
);
530 engine_hkl
->h
->_value
,
531 engine_hkl
->k
->_value
,
532 engine_hkl
->l
->_value
,
538 HklHolder
*sample_holder
= hkl_geometry_sample_holder_get(engine
->geometry
,
541 /* update the workspace from x; */
542 set_geometry_axes(engine
, x
);
544 /* get the second hkl from the mode parameters */
545 hkl_vector_init(&kf2
,
546 darray_item(engine
->mode
->parameters
, 0)->_value
,
547 darray_item(engine
->mode
->parameters
, 1)->_value
,
548 darray_item(engine
->mode
->parameters
, 2)->_value
);
550 /* R * UB * hkl = Q */
551 /* for now the 0 holder is the sample holder. */
552 hkl_matrix_times_vector(&engine
->sample
->UB
, &hkl
);
553 hkl_vector_rotated_quaternion(&hkl
, &sample_holder
->q
);
556 hkl_source_compute_ki(&engine
->geometry
->source
, &ki
);
557 hkl_detector_compute_kf(engine
->detector
, engine
->geometry
, &dQ
);
558 hkl_vector_minus_vector(&dQ
, &ki
);
559 hkl_vector_minus_vector(&dQ
, &hkl
);
561 /* R * UB * hlk2 = Q2 */
562 hkl_matrix_times_vector(&engine
->sample
->UB
, &kf2
);
563 hkl_vector_rotated_quaternion(&kf2
, &sample_holder
->q
);
564 hkl_vector_add_vector(&kf2
, &ki
);
569 f
[3] = hkl_vector_norm2(&kf2
) - hkl_vector_norm2(&ki
);
575 * double_diffraction_func: (skip)
584 int _double_diffraction_func(gsl_vector
const *x
, void *params
, gsl_vector
*f
)
586 CHECK_NAN(x
->data
, x
->size
);
588 _double_diffraction(x
->data
, params
, f
->data
);
594 /******************************************/
595 /* the psi_constant_vertical get set part */
596 /******************************************/
599 * psi_constant_vertical_func: (skip)
608 int _psi_constant_vertical_func(gsl_vector
const *x
, void *params
, gsl_vector
*f
)
611 HklEngine
*engine
= params
;
613 CHECK_NAN(x
->data
, x
->size
);
615 RUBh_minus_Q(x
->data
, params
, f
->data
);
617 /* update the workspace from x; */
618 set_geometry_axes(engine
, x
->data
);
621 hkl_source_compute_ki(&engine
->geometry
->source
, &ki
);
622 hkl_detector_compute_kf(engine
->detector
, engine
->geometry
, &kf
);
624 hkl_vector_minus_vector(&Q
, &ki
);
626 f
->data
[3] = darray_item(engine
->mode
->parameters
, 3)->_value
;
628 /* if |Q| > epsilon ok */
629 if(hkl_vector_normalize(&Q
)){
632 HklHolder
*sample_holder
= hkl_geometry_sample_holder_get(engine
->geometry
,
635 /* compute n the intersection of the plan P(kf, ki) and PQ (normal Q) */
637 hkl_vector_vectorial_product(&n
, &ki
);
638 hkl_vector_vectorial_product(&n
, &Q
);
640 /* compute the hkl ref position in the laboratory */
641 /* referentiel. The geometry was already updated. */
642 hkl
.data
[0] = darray_item(engine
->mode
->parameters
, 0)->_value
;
643 hkl
.data
[1] = darray_item(engine
->mode
->parameters
, 1)->_value
;
644 hkl
.data
[2] = darray_item(engine
->mode
->parameters
, 2)->_value
;
645 hkl_matrix_times_vector(&engine
->sample
->UB
, &hkl
);
646 hkl_vector_rotated_quaternion(&hkl
, &sample_holder
->q
);
648 /* project hkl on the plan of normal Q */
649 hkl_vector_project_on_plan(&hkl
, &Q
);
651 fprintf(stdout
, "\n");
652 hkl_geometry_fprintf(stdout
, engine
->geometry
);
653 fprintf(stdout
, "\n");
654 fprintf(stdout
, "%s n : <%f, %f, %f> hkl : <%f, %f, %f> Q : <%f, %f, %f> angle : %f\n",
656 n
.data
[0], n
.data
[1], n
.data
[2],
657 hkl
.data
[0], hkl
.data
[1], hkl
.data
[2],
658 Q
.data
[0], Q
.data
[1], Q
.data
[2],
659 hkl_vector_oriented_angle(&n
, &hkl
, &Q
) * HKL_RADTODEG
);
661 if(hkl_vector_norm2(&hkl
) > HKL_EPSILON
)
662 f
->data
[3] -= hkl_vector_oriented_angle(&n
, &hkl
, &Q
);
668 #define HKL_MODE_PSI_CONSTANT_VERTICAL_ERROR hkl_mode_psi_constant_vertical_error_quark ()
670 static GQuark
hkl_mode_psi_constant_vertical_error_quark (void)
672 return g_quark_from_static_string ("hkl-mode-psi-constant-vertical-error-quark");
676 HKL_MODE_PSI_CONSTANT_VERTICAL_ERROR_INITIALIZED_SET
, /* can not init the engine */
677 } HklModePsiConstantVerticalError
;
679 int hkl_mode_initialized_set_psi_constant_vertical_real(HklMode
*self
,
681 HklGeometry
*geometry
,
682 HklDetector
*detector
,
688 HklVector ki
, kf
, Q
, n
;
692 hkl_source_compute_ki(&geometry
->source
, &ki
);
693 hkl_detector_compute_kf(detector
, geometry
, &kf
);
695 hkl_vector_minus_vector(&Q
, &ki
);
697 if (hkl_vector_is_null(&Q
)){
699 HKL_MODE_PSI_CONSTANT_VERTICAL_ERROR
,
700 HKL_MODE_PSI_CONSTANT_VERTICAL_ERROR_INITIALIZED_SET
,
701 "can not initialize the \"%s\" mode with a null hkl (kf == ki)"
702 "\nplease select a non-null hkl", self
->info
->name
);
705 const HklHolder
*sample_holder
= hkl_geometry_sample_holder_get(geometry
, sample
);
707 /* needed for a problem of precision */
708 hkl_vector_normalize(&Q
);
710 /* compute the intersection of the plan P(kf, ki) and PQ (normal Q) */
712 hkl_vector_vectorial_product(&n
, &ki
);
713 hkl_vector_vectorial_product(&n
, &Q
);
715 /* compute hkl in the laboratory referentiel */
716 /* the geometry was already updated in the detector compute kf */
717 hkl
.data
[0] = darray_item(self
->parameters
, 0)->_value
;
718 hkl
.data
[1] = darray_item(self
->parameters
, 1)->_value
;
719 hkl
.data
[2] = darray_item(self
->parameters
, 2)->_value
;
720 hkl_matrix_times_vector(&sample
->UB
, &hkl
);
721 hkl_vector_rotated_quaternion(&hkl
, &sample_holder
->q
);
723 /* project hkl on the plan of normal Q */
724 hkl_vector_project_on_plan(&hkl
, &Q
);
726 if (hkl_vector_is_null(&hkl
)){
728 HKL_MODE_PSI_CONSTANT_VERTICAL_ERROR
,
729 HKL_MODE_PSI_CONSTANT_VERTICAL_ERROR_INITIALIZED_SET
,
730 "can not initialize the \"%s\" mode"
731 "\nwhen Q and the <h2, k2, l2> ref vector are colinear."
732 "\nplease change one or both of them", engine
->mode
->info
->name
);
735 /* compute the angle beetween hkl and n and
736 * store in in the fourth parameter */
737 if (!hkl_parameter_value_set(darray_item(self
->parameters
, 3),
738 hkl_vector_oriented_angle(&n
, &hkl
, &Q
),
739 HKL_UNIT_DEFAULT
, error
))
745 self
->initialized
= initialized
;
750 /*******************/
751 /* emergence fixed */
752 /*******************/
754 typedef struct _HklModeAutoHklEmergenceFixed HklModeAutoHklEmergenceFixed
;
756 struct _HklModeAutoHklEmergenceFixed
759 HklParameter
*n_x
; /* not owned */
760 HklParameter
*n_y
; /* not owned */
761 HklParameter
*n_z
; /* not owned */
762 HklParameter
*emergence
; /* not owned */
765 #define HKL_MODE_HKL_EMERGENCE_FIXED_ERROR hkl_mode_hkl_emergence_fixed_error_quark ()
767 static GQuark
hkl_mode_hkl_emergence_fixed_error_quark (void)
769 return g_quark_from_static_string ("hkl-mode-hkl-emergence-fixed-error-quark");
773 HKL_MODE_HKL_EMERGENCE_FIXED_ERROR_INITIALIZED_SET
, /* can not init the engine */
774 HKL_MODE_HKL_EMERGENCE_FIXED_ERROR_SET
, /* can not set the engine */
775 } HklModeAutoHklEmergenceFixedError
;
778 static HklVector
surface(const HklModeAutoHklEmergenceFixed
*mode
){
789 static double expected_emergence(const HklModeAutoHklEmergenceFixed
*mode
){
790 return mode
->emergence
->_value
;
793 static int hkl_mode_hkl_emergence_fixed_initialized_set_real(HklMode
*self
,
795 HklGeometry
*geometry
,
796 HklDetector
*detector
,
801 const HklModeAutoHklEmergenceFixed
*mode
= container_of(self
, HklModeAutoHklEmergenceFixed
, parent
);
803 HklVector n
= surface(mode
);
804 const HklHolder
*sample_holder
= hkl_geometry_sample_holder_get(geometry
, sample
);
806 /* first check the parameters */
807 if (hkl_vector_is_null(&n
)){
809 HKL_MODE_HKL_EMERGENCE_FIXED_ERROR
,
810 HKL_MODE_HKL_EMERGENCE_FIXED_ERROR_INITIALIZED_SET
,
811 "Can not compute emergence fixed when the surface vector is null.");
815 /* compute the orientation of the surface */
816 hkl_vector_rotated_quaternion(&n
, &sample_holder
->q
);
818 hkl_detector_compute_kf(detector
, geometry
, &kf
);
820 /* compute emergence and keep it */
821 mode
->emergence
->_value
= _emergence(&n
, &kf
);
823 self
->initialized
= initialized
;
829 int _emergence_fixed_func(const gsl_vector
*x
, void *params
, gsl_vector
*f
)
831 HklEngine
*engine
= params
;
832 HklModeAutoHklEmergenceFixed
*mode
= container_of(engine
->mode
,
833 HklModeAutoHklEmergenceFixed
,
835 HklGeometry
*geometry
= engine
->geometry
;
836 const HklDetector
*detector
= engine
->detector
;
837 const HklSample
*sample
= engine
->sample
;
838 HklVector n
= surface(mode
);
840 const HklHolder
*sample_holder
= hkl_geometry_sample_holder_get(geometry
, sample
);
842 CHECK_NAN(x
->data
, x
->size
);
844 RUBh_minus_Q(x
->data
, params
, f
->data
);
846 /* compute the orientation of the surface */
847 hkl_vector_rotated_quaternion(&n
, &sample_holder
->q
);
848 hkl_detector_compute_kf(detector
, geometry
, &kf
);
850 f
->data
[3] = expected_emergence(mode
) - _emergence(&n
, &kf
);
855 int hkl_mode_hkl_emergence_fixed_set_real(HklMode
*self
,
857 HklGeometry
*geometry
,
858 HklDetector
*detector
,
862 const HklModeAutoHklEmergenceFixed
*mode
= container_of(self
, HklModeAutoHklEmergenceFixed
, parent
);
863 HklVector n
= surface(mode
);
865 /* first check the parameters */
866 if (hkl_vector_is_null(&n
)){
868 HKL_MODE_HKL_EMERGENCE_FIXED_ERROR
,
869 HKL_MODE_HKL_EMERGENCE_FIXED_ERROR_SET
,
870 "Can not compute hkl with emergence fixed when the surface vector is null.");
874 return hkl_mode_set_hkl_real(self
, engine
, geometry
, detector
, sample
, error
);
877 HklMode
*hkl_mode_hkl_emergence_fixed_new(const HklModeAutoInfo
*auto_info
)
879 static const HklModeOperations operations
= {
880 HKL_MODE_OPERATIONS_HKL_FULL_DEFAULTS
,
881 .capabilities
= HKL_ENGINE_CAPABILITIES_READABLE
| HKL_ENGINE_CAPABILITIES_WRITABLE
| HKL_ENGINE_CAPABILITIES_INITIALIZABLE
,
882 .initialized_set
= hkl_mode_hkl_emergence_fixed_initialized_set_real
,
883 .set
= hkl_mode_hkl_emergence_fixed_set_real
,
885 HklModeAutoHklEmergenceFixed
*self
;
887 if (darray_size(auto_info
->info
.axes_w
) != 4){
888 fprintf(stderr
, "This generic HklModeAutoHklEmergenceFixed need exactly 4 axes");
892 self
= HKL_MALLOC(HklModeAutoHklEmergenceFixed
);
894 /* the base constructor; */
895 hkl_mode_auto_init(&self
->parent
,
899 self
->n_x
= register_mode_parameter(&self
->parent
, 0);
900 self
->n_y
= register_mode_parameter(&self
->parent
, 1);
901 self
->n_z
= register_mode_parameter(&self
->parent
, 2);
902 self
->emergence
= register_mode_parameter(&self
->parent
, 3);
904 return &self
->parent
;
911 static void hkl_engine_hkl_free_real(HklEngine
*base
)
913 HklEngineHkl
*self
= container_of(base
, HklEngineHkl
, engine
);
914 hkl_engine_release(&self
->engine
);
918 HklEngine
*hkl_engine_hkl_new(HklEngineList
*engines
)
921 static const HklParameter h
= {
922 HKL_PARAMETER_DEFAULTS
, .name
= "h",
923 .description
= "h coordinate of the diffracting plan",
924 .range
= { .min
=-1, .max
=1 },
926 static const HklParameter k
= {
927 HKL_PARAMETER_DEFAULTS
, .name
= "k",
928 .description
= "k coordinate of the diffracting plan",
929 .range
= { .min
=-1, .max
=1 },
931 static const HklParameter l
= {
932 HKL_PARAMETER_DEFAULTS
, .name
= "l",
933 .description
= "l coordinate of the diffracting plan",
934 .range
={ .min
=-1, .max
=1 },
936 static const HklParameter
*pseudo_axes
[] = {&h
, &k
, &l
};
937 static HklEngineInfo info
= {
938 HKL_ENGINE_INFO("hkl",
940 HKL_ENGINE_DEPENDENCIES_AXES
| HKL_ENGINE_DEPENDENCIES_ENERGY
| HKL_ENGINE_DEPENDENCIES_SAMPLE
),
942 static HklEngineOperations operations
= {
943 HKL_ENGINE_OPERATIONS_DEFAULTS
,
944 .free
=hkl_engine_hkl_free_real
,
947 self
= HKL_MALLOC(HklEngineHkl
);
949 hkl_engine_init(&self
->engine
, &info
, &operations
, engines
);
951 self
->h
= register_pseudo_axis(&self
->engine
, engines
, &h
);
952 self
->k
= register_pseudo_axis(&self
->engine
, engines
, &k
);
953 self
->l
= register_pseudo_axis(&self
->engine
, engines
, &l
);
955 return &self
->engine
;